webtracking.org
concepts

Measuring AI crawler traffic in your server logs

GPTBot, ClaudeBot, PerplexityBot and the rest never show up in client-side analytics. How to measure AI crawlers from server and CDN logs, verify them against spoofing with IP lists, rDNS, and TLS fingerprints, and what robots.txt can and cannot do about them.

last verified 2026-07-11

“AI traffic” conflates two different things, and separating them is the first job of any honest measurement. AI crawler traffic is bots fetching your pages — to train models, to build a search index, or to ground a live answer. AI referral traffic is humans clicking through to your site from an assistant’s answer; that one lives in client-side analytics and gets its own guide. This guide covers the crawlers — and the crucial point is that your analytics tool cannot see them. Most AI crawlers do not execute JavaScript, so they never fire a tag. Crawler measurement is a server-log and CDN-log discipline, closer to classic log analysis than to anything in the tag manager.

The crawlers worth knowing

The table below lists the major operators’ user-agent tokens and how each can be verified, as documented in each operator’s own bot documentation — last reviewed 2026-07-11. Operators add, rename, and re-scope crawlers often, so treat any copy of this table older than a quarter as stale and re-check the tokens and IP lists against the operator’s published docs before relying on them (the same discipline this guide demands of every published number).

OperatorUser-agent token(s)PurposeVerification
OpenAIGPTBotModel-training crawlPublished IP ranges (openai.com/gptbot.json); rDNS not guaranteed
OpenAIOAI-SearchBotSearch indexPublished IP ranges
OpenAIChatGPT-UserLive retrieval for a user promptPublished IP ranges
AnthropicClaudeBot, Claude-User, Claude-SearchBotTraining / user-triggered fetch / searchPublished IP ranges (anthropic.com docs)
GoogleGoogle-ExtendedGemini-training opt-out control — a robots.txt token only, not a separate fetchern/a — it gates Googlebot
GoogleGooglebotMain index, which also powers AI OverviewsReverse + forward DNS to googlebot.com
PerplexityPerplexityBot, Perplexity-UserIndex / live fetchPublished IP ranges; documented UA-masking controversy — IP verification is mandatory
MicrosoftbingbotBing index, which powers CopilotrDNS to search.msn.com
Common CrawlCCBotOpen crawl used by many model trainersUA plus IP heuristics
AppleApplebot, Applebot-ExtendedApple IntelligencerDNS to applebot.apple.com
AmazonAmazonbotAlexa / model trainingrDNS to crawl.amazonbot.amazon
Metameta-externalagent, FacebookBotLlama training / link previewsPublished ranges
ByteDanceBytespiderTikTok / Doubao trainingAggressive crawler; UA plus IP heuristics

Note the three distinct purposes hiding in one column: training crawls (GPTBot, ClaudeBot, Bytespider), search-index crawls (OAI-SearchBot, PerplexityBot), and live retrieval (ChatGPT-User, Claude-User, Perplexity-User) — a fetch made because a human just asked a question your page might answer. For anyone measuring AI visibility, those are three very different signals, and lumping them into one “AI bots” number destroys the information.

The trap: user agents are free to fake

A user-agent string is a self-declared HTTP header. Anyone can send GPTBot. Counting log lines by UA token therefore fails in both directions: scrapers spoof well-known AI crawler UAs to look benign and slip through allowlists, and some operators have been documented fetching with browser-like UAs that no token search will catch. A UA-only count is not a measurement — it is an upper bound on politeness. Any number you publish or act on should be verified against the request’s source, by at least one of the following methods.

1. Published IP ranges. Most major operators now publish their crawler egress IPs as JSON (OpenAI’s gptbot.json is the pattern; Anthropic, Perplexity, and others publish equivalents as of mid-2026). Match the connecting IP against the CIDR list: exact and fast, but the lists change, so fetch them on a schedule and record which version of the list verified each hit.

2. Reverse-plus-forward DNS. For Googlebot, bingbot, Applebot, and Amazonbot, the operator’s documented method is rDNS: resolve the IP to a hostname, check it ends in the operator’s domain, then forward-resolve that hostname and confirm it returns the same IP. The forward step is what defeats spoofing — anyone can put lies in their own reverse zone, but not in googlebot.com’s forward zone:

$ 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.1   # matches → verified

3. TLS fingerprinting (JA3/JA4). A TLS client’s ClientHello — cipher suites, extensions, ordering — fingerprints the software making the request. A request claiming to be GPTBot but presenting the JA4 fingerprint of headless Chrome or python-requests is lying, whatever its IP story. Fingerprinting requires visibility at the TLS terminator (CDN, load balancer, or an eBPF-based capture on your own edge), which is why it is usually the last method teams add — and the strongest.

Instrumenting it in practice

  • Behind a CDN (fastest path): Cloudflare and its peers already classify verified bots and expose bot-category and JA4 fields in their request logs. Push the logs to object storage and query them with whatever engine you like — the crawler table above becomes a simple join.
  • Raw nginx/Apache logs: a small scheduled job — DuckDB or Polars is plenty — parses the access log, joins the source IP against the cached operator IP lists (expand CIDRs to integer ranges and join on ip_int between range_start and range_end), applies rDNS checks for the DNS-verified operators, and emits a daily ai_crawler_hits table with operator, agent, purpose, verified columns. Keep the unverified UA matches in a separate column rather than discarding them: the gap between claimed and verified is itself a spoofing metric.
  • Zero-instrumentation capture: eBPF-based tools can observe HTTP server traffic without touching application code, which suits infrastructures where log access is awkward — the same event stream then feeds the pipeline like any other log source.

Whatever the plumbing, report at minimum: verified hits per operator per day, the pages fetched (training crawls concentrate on your most-linked content; live retrieval concentrates on whatever users are asking about right now), and the verified-to-claimed ratio.

robots.txt: a request, not a control

The blocking surface is robots.txt, and it is worth stating plainly what it is: a voluntary convention. Reputable operators honor it; nothing forces anyone to.

# Block model-training crawls
User-agent: GPTBot
Disallow: /

User-agent: ClaudeBot
Disallow: /

# Opt out of Gemini model training while remaining in Google Search
User-agent: Google-Extended
Disallow: /

Per-operator nuances matter. Google-Extended is not a crawler — it is a token that tells Googlebot not to use your content for Gemini training, without touching your Search presence. Blocking GPTBot stops OpenAI’s training crawl but is a separate decision from blocking OAI-SearchBot (search visibility) or ChatGPT-User (live answers that may cite you) — many sites want to block training while staying citable, and the tokens let you split that decision. But if a crawler ignores the file, robots.txt does nothing; actual enforcement means WAF or edge rules keyed to the verified identity signals above, which is precisely why verification and policy belong in the same pipeline. Measure first, then decide, then — if needed — enforce.

Across the wider web, robots.txt posture toward AI crawlers is itself a measurable, moving statistic; it is the kind of dimension the State of Web Tracking report exists to track over time. On your own site, the honest baseline is simpler: verified crawler hits by operator and purpose, refreshed IP lists, a dated reference table — and no number in a deck that started life as an unverified user-agent count.