Skip to main content
Returns the bot taxonomy: every intent bucket (why a bot crawls) together with the full list of bots in it, who operates each one, and how its identity is verified. This is the decoder for the crawl exports. Export Crawl Analytics returns botTotals keyed by bot ID with an intent on each, and Export Page Analytics returns per-bot tier splits under pages[].bots — this endpoint tells you what those IDs and intents mean.
Always call this endpoint from a server-side environment (backend API, serverless function, build script, etc.). Never include your API key in client-side code — it will be visible to anyone inspecting your frontend.
Programmatic (API key) access requires the Pro plan and above — requests from Starter accounts return 403 plan_upgrade_required.
Cache on the version. The response is immutable for a given definitionsVersion. Read definitionsVersion from any export response you already fetch, and only call this endpoint when it reports a version you haven’t cached — typically once a month or less.

Versioning

The taxonomy is published as numbered, immutable snapshots starting at 1.0. Every response carries the version it came from and the date that version took effect. A major bump is the signal that switching on intent in your own code may need updating. A minor bump never changes the set of possible intent values.

Request

Headers

Body Parameters

Example Request

Current taxonomy:
A specific historical snapshot:

Response

Success (200)

intents and bots are two flat arrays joined on intent — bots are not nested under their bucket. Looking a bot up by the ID you got from an export is a direct index into bots; listing a bucket’s members is one filter on intent.

Fields

Buckets are returned in display order (AI intents first); bots are sorted by botId.
Retired bots are included, not dropped. A bot we have stopped classifying stays in the payload with isActive: false, so decoding an archived export never hits an ID that resolves to nothing. For “which bots can crawl my site today”, filter bots on isActive.
AI intents. isAiIntent is true for exactly training, answer-fetch, and search-index. That is the definition behind “AI crawl volume” in the dashboard: models reading your content. search-classic (Googlebot, Bingbot) is deliberately excluded — including it would drown the AI signal in ordinary organic crawling.

Matching a User-Agent yourself

uaPatterns is the actual rule set we classify with, published so you can reproduce our attribution against your own access logs rather than taking the bot IDs on faith. They are lowercased substrings, not whole User-Agent strings and not regular expressions. To match a request the way we do:
  1. Lowercase the request’s User-Agent.
  2. Find every bot with a pattern contained in it.
  3. The longest matching pattern wins. This matters: googlebot-image and googlebot are separate bots, and a Googlebot-Image request contains both. Matching shortest-first would collapse the whole Google suite into one bucket.
  4. No match → the hit is counted under the unknown bot at the unknown tier. That entry is the synthetic catch-all, so its uaPatterns is deliberately empty — it is the bucket you fall into, never one you match.
A UA match alone only establishes the declared tier — anyone can send any User-Agent. Reaching verified additionally requires the source IP to check out, which is what verificationMethod describes below. If your own counts come out higher than ours, that difference is usually spoofed traffic we declined to attribute.

Verification methods

verificationMethod is how a bot can reach the verified attribution tier. A bot with none can never be verified, so it will only ever appear as declared in your exports — that is expected, not a data quality problem.

Error Responses

Examples

JavaScript / Node.js

The version-aware pattern — fetch definitions only when the version changes, then decode an export’s bot keys into display names:
A handful of bot keys on days before the legacy cutover are aggregates with no taxonomy entry and carry "intent": null. Skip keys that don’t resolve, as the example above does.