A user agent string is supposed to say which browser made a request. Most of what it actually contains describes browsers and engines that aren’t the one running, kept alive as compatibility credentials for three decades.
A user agent string is meant to carry the browser, its rendering engine, the operating system, and a version number, sent automatically on every request. A newer field, sua, is meant to carry a more honest structured version, built from data the browser only shares if asked, and only on the next request. OpenRTB’s spec recommends sua over the plain string when both exist, since the plain one can be frozen or reduced. sua also carries a field marking where its data came from, and since Safari and Firefox never adopted the mechanism that would make it genuine, that value is often just the old string, parsed and reshaped to look tidier.
The reason goes back to 1995. Netscape’s browser identified itself as Mozilla, and sites checked for that word before serving the full page. When Internet Explorer 2 shipped that year, it started sending Mozilla too, so it wouldn’t get the downgraded page. Every browser has kept the trick since.
The format itself isn’t even consistent. Browsers and mobile apps mostly send that same layered string, since they run real browser engines underneath. CTV splits in two: some platforms send their own short device string with no browser claims at all. Others run an actual browser under their interface and produce the identical Mozilla, WebKit, Safari chain a phone would. Three conventions, depending only on what’s asking.
The same identification problem is showing up again, one generation newer. GPTBot, ClaudeBot, PerplexityBot, and Google-Extended are real, distinct strings site owners write rules against, commonly blocking the ones built for training while letting the real-time answer ones through. Research from January 2026 already found some AI agents using those exact strings to get past the blocks.
An IETF draft called Web Bot Auth, backed by engineers at Cloudflare, Google, and Amazon, replaces the self-reported string with proof. A bot signs each request with a private key only it holds, and publishes the matching public key at a known address. A server checks the signature against that public key: a match proves who sent it, anything else proves nothing. A text string can be typed by anyone, a signature only by whoever holds the private key. Cloudflare already runs a version of it, though the standard itself is still a draft, not yet adopted.
As a field for saying what’s actually making a request, user agent is unreliable. Every other identifier in this series gets patched by someone, privacy extensions, sync mechanisms, truncation policies. This one has a patch too, and most of what claims to be patched is really just the old string, reshaped. The approach that might work doesn’t patch it at all, it stops asking the field anything and checks a signature instead.
When a browser identifies itself, most of what it says is no longer true




