The AI crawler guide · chapter 4
How to verify an AI crawler is genuine
How do I verify that a request claiming to be GPTBot really came from OpenAI?
Karl-Gustav Kallasmaa, Founder & CEOLast updated How do I verify a crawler is genuine?
Two methods, and which applies depends on the operator. Google and Apple document reverse DNS: look up the hostname of the accessing address, check its suffix, then resolve that hostname forward and confirm it returns the same address. OpenAI, Anthropic, Perplexity and Amazon publish machine-readable files listing the addresses their agents fetch from. Common Crawl documents both, which makes CCBot the one agent you can check either way.[^ccbot-verification]
Why the header proves nothing
User-Agent is a request header. The client chooses its value, nothing validates it, and copying a documented crawler string takes one line of code.
There is a specific reason AI crawler tokens are the ones most worth forging: sites make exceptions for them. A rate limiter that lets GPTBot through, a bot ruleset that whitelists PerplexityBot, a paywall that serves full text to OAI-SearchBot — every one of those is an incentive to claim the name. Common Crawl says this outright, warning that crawlers falsely identifying themselves as CCBot exist.[^ccbot-spoofing]
So "GPTBot fetched 4,000 pages last week" is not a measurement until it is verified. It is a count of requests that said they were GPTBot.
Method one: reverse DNS
Google documents the canonical four-step procedure, and it is worth following exactly rather than approximately.[^google-rdns-procedure]
- Run a reverse DNS lookup on the accessing IP address from your logs.
- Verify the returned domain name is
googlebot.com,google.comor
googleusercontent.com.
- Run a forward DNS lookup on that domain name.
- Verify the result is the same as the original accessing IP address.
$ host 66.249.66.1
1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
$ host crawl-66-249-66-1.googlebot.com
crawl-66-249-66-1.googlebot.com has address 66.249.66.1Step four is the whole point. Reverse DNS records are controlled by whoever holds the address block, so anyone with an IP range can publish a PTR record that ends in a plausible-looking hostname. Only the round trip — hostname resolves back to the same address — proves that the operator controls both halves. A verification routine that stops after step two is a verification routine that accepts forgeries.
Apple documents the same shape of check against its own suffix: the reverse hostname for genuine Applebot traffic ends in applebot.apple.com.[^applebot-rdns] Common Crawl documents the same shape again, with genuine CCBot addresses resolving under crawl.commoncrawl.org.[^ccbot-verification]
Two failure modes to handle. A reverse lookup can return nothing at all, which is not evidence of forgery so much as absence of evidence — treat it as unverified rather than fake. And DNS resolution costs a round trip per unique address, so cache results and verify unique IPs rather than every log line.
Method two: published IP range files
The other operators publish the addresses themselves, as documents you fetch.
OpenAI's per-agent split is the most useful arrangement here, because it lets you identify which of the four agents made a request without trusting the header at all.[^openai-ip-json] Anthropic publishes one combined file for ClaudeBot, Claude-User and Claude-SearchBot,[^anthropic-bots-json] so with Anthropic you can prove the traffic is theirs but must use the header to tell which agent it was. Perplexity publishes one file per agent.[^perplexity-ip-json] Amazon publishes a page of addresses.[^amazonbot-ip-page] Common Crawl publishes the same ranges it documents for reverse DNS as JSON.[^ccbot-verification]
Fetch the file; do not copy from it. Operators add and retire ranges without announcing a schedule, and a hardcoded list fails in the direction that hurts: genuine crawler traffic silently reclassified as fake, and whatever you built on that classification quietly wrong. Refresh on a schedule, and treat a failed refresh as a reason to fall back to the last known list rather than to reject everything.
The rule to verify before you block
Verification and access control are different jobs, and conflating them causes problems.
Anthropic makes this explicit: it states that IP blocking may not work correctly for its agents, and recommends robots.txt instead.[^anthropic-bots-json] The published file exists so you can confirm traffic is theirs, not so you can build a firewall rule from it. The same caution applies generally — an address-based blocklist built from a snapshot of a published range is a blocklist that starts being wrong immediately and never tells you.
Use the published data to answer "was this real?" Use robots.txt to answer "may it fetch this?" Those are the tools each mechanism is documented for.
A workable verification routine
For a site that wants trustworthy crawler numbers rather than a research project, this is enough.
- Filter log lines by the documented product tokens, not by version, and not
by the full header.
- Extract unique source addresses for each token over the window you care
about. This is typically a small set, which is what makes the rest cheap.
- For Google, Apple and Common Crawl, run the reverse-then-forward check on
each unique address, and cache the verdict.
- **For OpenAI, Anthropic, Perplexity, Amazon and Common Crawl, fetch the
published ranges** on a schedule and test membership.
- Report verified and unverified separately. Never merge them into one
number. The unverified column is itself a useful signal: a sudden spike in requests claiming a crawler token, from addresses that do not verify, is scraping wearing a costume.
- Do not act on an unverified count. If a page appears to be heavily
crawled by an agent that never verifies, the honest conclusion is that you do not know it was crawled at all.
Step five is where most log analysis goes wrong, because merging the columns turns a measurement into a flattering estimate. Attensira's crawler logs exist to run this routine continuously rather than as an occasional audit, and any log pipeline can be made to do the same — what matters is that the verified and unverified counts stay apart.
Where verification breaks in practice
Four situations account for most of the cases where a correct routine produces wrong answers, and all four are about your infrastructure rather than the crawler.
The address in your log is not the client's. Behind a CDN, load balancer or reverse proxy, the origin sees the proxy's address. Verification has to run against the forwarded client address, and only if you trust the layer that set it — a forwarded header from an untrusted source is as forgeable as a user agent. Getting this wrong produces a total verification failure that looks like an epidemic of forgery.
Logs at the edge and logs at the origin disagree. A CDN that blocks a crawler at the edge produces no origin log line at all, so the origin's view is "this crawler never visited" when the truth is "this crawler was turned away". The absence looks identical to never having been discovered, and the fix is in a completely different place.
Addresses are recycled. A cached verification verdict is a verdict about an address at a moment. Cache the result for hours, not months, and re-verify periodically rather than treating a pass as permanent.
IPv6 and IPv4 need the same treatment. A routine that verifies one and silently passes or fails the other will misclassify a growing share of traffic, and the direction of the error depends on which default you chose without noticing.
What a verified log actually answers
The reason to do any of this is that a verified crawler log answers questions nothing else can, and each of them is directly actionable.
The fourth row is the one that most often surprises people, because the site's configuration and the site's behaviour disagree: robots.txt permits the crawler, and something in front of the origin rejects it anyway. Without verification you cannot tell that case apart from a scraper being correctly blocked, which is why the two columns have to stay separate.
What verification cannot tell you
It confirms who fetched, and nothing beyond that. A verified OAI-SearchBot request proves OpenAI's search crawler read the page. It does not prove the page entered an index, was retrieved for any question, or was ever cited. Those are the steps no operator exposes, and the reason the pillar is careful to describe crawling as a precondition for citation rather than a cause of it.
There is also a limit on the other side. Verification tells you an agent belonged to an operator; it says nothing about what that operator subsequently did with the response. A verified training crawler fetch and a verified search crawler fetch look identical in your logs, and the difference between them lives entirely in the token and the operator's own description of it — which is why the user-agent reference and this chapter are worth reading as a pair rather than separately.
Next: llms.txt, the file people publish hoping to influence the step verification cannot see.
[^google-rdns-procedure]: Google Search Central, verifying Googlebot, retrieved 2026-09-03. [^openai-ip-json]: OpenAI, crawlers documentation, retrieved 2026-09-03. [^anthropic-bots-json]: Anthropic support documentation, retrieved 2026-09-03. [^perplexity-ip-json]: Perplexity crawler documentation, retrieved 2026-09-03. [^applebot-rdns]: Apple support, About Applebot, retrieved 2026-09-03. [^amazonbot-ip-page]: Amazon developer documentation, Amazonbot, retrieved 2026-09-03. [^ccbot-spoofing]: Common Crawl, CCBot, retrieved 2026-09-03. [^ccbot-verification]: Common Crawl, CCBot, retrieved 2026-09-03.
Questions people ask
- Why is the forward DNS lookup necessary if the reverse lookup already returned a Google hostname?
- Because reverse DNS records are set by whoever controls the IP block, so anyone can point their own address at a hostname that looks legitimate. Only the forward lookup, resolving that hostname back to the same address, proves the operator controls both — which is why Google's documented procedure has four steps rather than two.
- Should I block IP addresses that fake a crawler user agent?
- Blocking is a reasonable response to abuse, but be careful about doing it by IP for the real agents. Anthropic states that IP blocking may not work correctly for its crawlers and recommends robots.txt instead. Use the published IP files to verify traffic, not as the basis of a permanent blocklist.
- Can I verify every AI crawler the same way?
- No, and the method differs by operator. OpenAI, Anthropic, Perplexity, Amazon and Common Crawl publish machine-readable IP range files. Google, Apple and Common Crawl document reverse-DNS suffixes. An agent whose operator publishes neither cannot be verified at all, which is itself a useful signal.
- How often do the published IP ranges change?
- The operators do not commit to a schedule, which is the reason to fetch the file rather than copy addresses out of it. Any verification built on a hardcoded list starts drifting the moment the operator adds a range, and the failure is silent — genuine crawler traffic quietly classified as fake.
- Does verification matter if I allow everything anyway?
- Yes, for measurement rather than access. If you are counting AI crawler visits to judge whether your pages are being picked up, unverified counts include every scraper that borrowed the token, and AI crawler tokens are among the most commonly borrowed. An inflated number is worse than no number.
Sources
Every factual statement above, with the page it came from and the date that page was read.
Google documents a four-step verification: run a reverse DNS lookup on the accessing IP, verify the domain name is googlebot.com, google.com or googleusercontent.com, run a forward DNS lookup on that domain name, and verify it matches the original accessing IP.
developers.google.com · retrieved
“Run a reverse DNS lookup on the accessing IP address from your logs, using the host command.”
OpenAI publishes a separate IP range file for each of its agents, at openai.com/gptbot.json, openai.com/searchbot.json, openai.com/chatgpt-user.json and openai.com/adsbot.json.
developers.openai.com · retrieved
Anthropic publishes the addresses used by ClaudeBot, Claude-User and Claude-SearchBot at claude.com/crawling/bots.json, and states that IP blocking may not work correctly and recommends robots.txt instead.
support.claude.com · retrieved
Perplexity publishes IP ranges for PerplexityBot at perplexity.com/perplexitybot.json and for Perplexity-User at perplexity.com/perplexity-user.json.
docs.perplexity.ai · retrieved
Apple documents verifying Applebot traffic by checking that the reverse DNS hostname of the accessing address ends in applebot.apple.com.
support.apple.com · retrieved
Amazon documents that webmasters can verify Amazonbot requests against the IP addresses it publishes at developer.amazon.com/amazonbot/ip-addresses/.
developer.amazon.com · retrieved
Common Crawl warns that crawlers falsely identifying themselves as CCBot exist, and recommends verification rather than trusting the user agent.
commoncrawl.org · retrieved
Common Crawl documents both verification methods for CCBot — a reverse DNS hostname under crawl.commoncrawl.org, and the same IP ranges provided as JSON at index.commoncrawl.org/ccbot.json.
commoncrawl.org · retrieved