The policy has one action per key: the six configurable categories and the five extra keys. The decision for a request is the bot's own override if it has one; otherwise the strongest action among the keys that apply to it.
Defaults
Every key is log, except ai_search, ai_user_agent and search_engine, which are allow. Humans are always allowed.
Templates
A template replaces the whole policy. Mode, spoofed_challenge and bot overrides stay as they are. Policy keys sent in the same change apply on top of the template.
| Key | search_ok_block_training | verified_only | block_unverified_automation |
|---|---|---|---|
| Dashboard name | Allow search engines and AI search, block training | Verified only | Block all unverified automation |
ai_training | block | allow | log |
ai_search | allow | allow | allow |
ai_user_agent | allow | allow | allow |
search_engine | allow | allow | allow |
unverified_automation | log | challenge | block |
spoofed | challenge | block | block |
unverified_bot | log | block | log |
trap_hit | log | challenge | block |
secret_probe | log | block | block |
robots_violation | log | log | block |
agent_burst | log | challenge | block |
Change the policy
AI Crawl Control → Overview → Settings: Templates → Apply, then adjust Action per category. Review and save shows the diff before saving.
openwaf-cloud ctl zones set example.com ai_agents.template=search_ok_block_training ai_agents.policy.spoofed=block \
--reason "Block training and fake crawlers"ai_agents in PATCH …/edge is a JSON merge patch: objects merge (the policy key by key), lists are replaced whole, null puts a field back to its default. template is write-only.
curl -sS -X PATCH "https://dash.openwaf.dev/v1/orgs/$ORG/zones/example.com/edge" \
-H "Authorization: Bearer $OPENWAF_TOKEN" \
-H "X-Change-Reason: Block training and fake crawlers" \
-H "Content-Type: application/json" \
-d '{"ai_agents": {"template": "search_ok_block_training", "policy": {"spoofed": "block"}}}'ai_agents_settings with {"zone": "example.com", "template": "search_ok_block_training", "patch": {"policy": {"spoofed": "block"}}, "reason": "…"}. Without patch and template it only reads the settings.
Per-bot overrides
bot_overrides (up to 100 {bot_id, action} entries) sets the action of one catalog bot, whatever its category. The list is replaced whole.
Settings → Crawler overrides → Add crawler, pick the crawler and its action.
bot:action pairs, separated by commas; "" removes every override.
openwaf-cloud ctl zones set example.com ai_agents.bot_overrides=gptbot:block,ccbot:allow --reason "Per-bot policy"{"ai_agents": {"bot_overrides": [{"bot_id": "gptbot", "action": "block"}, {"bot_id": "ccbot", "action": "allow"}]}}ai_agents_settings with "patch": {"bot_overrides": [{"bot_id": "gptbot", "action": "block"}]}.
Log and enforce
mode | Effect |
|---|---|
log (default) | Decisions are computed and counted with enforced: false; traffic passes. Reports show them as "would". |
enforce | Decisions are applied. |
The tarpit action needs tarpit.enabled; see Trap and tarpit.
One name, its own policy
hosts.<name>.ai_agents replaces the zone's settings for that name as a whole; the first change to a name starts from the zone's settings. In the dashboard use Applies to in the settings; in MCP pass host; in the CLI use --host:
openwaf-cloud ctl zones set example.com --host shop.example.com ai_agents.mode=enforce --reason "Enforce on the shop"