Why one signal is never enough
The instinct is to grep the user-agent header and be done. That works for the minority of agents that self-identify - OpenAI's ChatGPT-User, Perplexity's Perplexity-User, and Anthropic's Claude-User all ship a distinct token when they fetch a page on a user's behalf. It fails for the growing share that do not: ChatGPT Atlas in agent mode presents an ordinary Chrome-on-Mac user-agent string, and Anthropic's Computer Use agent drives a full browser session that executes JavaScript, holds cookies, and produces traffic indistinguishable from a human visitor by design. Google's Project Mariner shipped the same way before later adding a distinct GoogleAgent-Mariner token, and was folded into a newer "Gemini Agent" surface in 2026 - a reminder that these tokens change fast and a hard-coded list goes stale within months. Full directory: AI agent user-agent directory.
Meanwhile a meaningful share of requests that claim to be ChatGPT, Perplexity, or another named agent are spoofed - a script setting the string without the traffic actually originating from that vendor. So the UA field cuts both ways: absent (real agent, no signal) or present-but-fake (no agent, false signal). Neither failure mode is solved by reading the header more carefully. See spoofed agent user-agents for how to verify a claimed identity rather than trust it.
The signal stack, ranked by reliability
| Signal | What it tells you | Reliability |
|---|---|---|
| Web Bot Auth signature | An Ed25519-signed HTTP Message Signature (RFC 9421) checked against a public key at a well-known URL - cryptographic proof of the signer's identity | Strongest available, but adoption is still early; only present when the agent operator supports it |
| Declared user-agent token | A self-identifying string like ChatGPT-User or Perplexity-User | Trustworthy only once corroborated - trivially spoofable on its own |
| IP / ASN / published ranges | Whether the request originates from a range the vendor has published or an ASN known for the vendor's infrastructure | Reasonably strong for named crawlers with published ranges; weaker for agents that route through a user's own residential IP or a generic cloud host |
| TLS / browser fingerprint, headless flags | Whether the client's TLS handshake and browser-automation flags (e.g. navigator.webdriver, missing plugin lists) match a real browser or an automation framework | Useful for scripted bots; close to useless against agents that drive a genuine, unmodified browser instance |
| Behavioral timing | Request cadence, mouse/scroll entropy, time-to-first-action - patterns that differ from typical human browsing | Probabilistic and vendor-modeled; a supporting signal, never a verdict on its own |
What "agent" excludes
Two neighboring categories get bundled into "AI traffic" and shouldn't be. AI crawlers that index your site for training or retrieval (GPTBot, ClaudeBot, CCBot, and peers) are a separate, well-documented population with published UAs and IP ranges - covered in full in the AI crawlers guide. Human AI-referral traffic - a person who read a ChatGPT answer and clicked through, browsing as themselves - is covered by the AI traffic measurement arm of this site. This page, and the rest of this cluster, is about the third category: the agent itself as the visitor, acting semi- or fully autonomously.