Read a user agent string and mark every field: read from a token, a frozen constant, or something the string cannot answer at all.
Initializing in your browser…
Write a robots.txt by the RFC 9309 rules, then test a URL against it and see which rule wins and why.
Check a link for typosquats, brand-in-subdomain tricks, mixed-alphabet homographs, and hidden destinations. Public Suffix List parsing, explainable per-rule scoring, and the link is never fetched.
Decode an X.509 certificate field by field, check which host names it covers, and verify that each certificate in a chain was signed by the one above it
A bug reproduces only for one customer. Their ticket carries a raw User-Agent header, and you need to know which browser to open before you can chase it.
The raw User-Agent header
Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.6099.119 Mobile/15E148 Safari/604.1
What each field is, and where it came from
Browser Chrome 120.0.6099.119 read CriOS/120.0.6099.119
OS iOS 17.2 read iPhone OS 17_2
Engine WebKit inferred
CPU Unknown not in the string
Device Apple iPhone, mobile
Every token, and what it means:
Mozilla/5.0 dates from Netscape, means nothing
iPhone the model is never in the string
CPU iPhone OS 17_2 like Mac OS X the iOS version; "like Mac OS X"
is for old sniffers and is not macOS
AppleWebKit/605.1.15 a real WebKit version
KHTML, like Gecko carried since 2003
CriOS/120.0.6099.119 the browser: Chrome 120.0.6099.119
Mobile/15E148 a frozen iOS build number
Safari/604.1 a real Safari build numberThree answers here are ones a keyword parser gets wrong, and all three change what you would go and test.
There is no Chrome token in this string. Chrome on iOS writes CriOS, so a parser looking for "Chrome" finds nothing and reports the browser as Unknown, or falls through to the Safari branch and reports Safari. The same applies to FxiOS, EdgiOS and OPT.
The words "like Mac OS X" appear in every iOS string, put there for sniffers written in 2007. A macOS test that runs before the iOS test matches them, so a naive parser reports every iPhone and every iPad as a Mac. That is why the order of tests here puts iOS and iPadOS first, and why the token breakdown says outright what the phrase is for.
The engine is WebKit, and here that is the truth rather than the usual fiction. App Store rules require every browser on iOS to use the system engine, so Chrome on iOS really is WebKit. On the desktop the same token means the opposite: every Chromium browser sends AppleWebKit/537.36 and Safari/537.36 while running Blink, so reading the engine off the token there gets it wrong for Chrome, Edge, Opera, Brave, Vivaldi and Samsung Internet at once.
The CPU line is worth as much as the others. The string does not carry the architecture, so nothing is reported, rather than a guess being dressed up as a reading. Every field on the page carries a badge saying whether it was read from a token, is a frozen constant that says nothing about the machine, or is simply absent.
Paste a user agent string and every field comes back marked with where it came from: read from a token, a frozen constant that says nothing about the machine, or something the string simply cannot answer. Chrome on iOS is named as Chrome, an iPhone is not called a Mac, and every Chromium browser is reported as Blink rather than as the WebKit its own string claims.
Almost every token in a user agent string is there because some site once sniffed for it, and the three biggest consequences are the reason most parsers get the same three things wrong.
The first is the engine. Every Chromium browser sends "AppleWebKit/537.36 (KHTML, like Gecko)" and "Safari/537.36" and has done since 2013, while its engine is Blink. A parser that reads the engine off the AppleWebKit token calls Chrome, Edge, Opera, Brave, Vivaldi and Samsung Internet WebKit, which is exactly the mistake the token was put there to cause. Here the engine is derived from the browser instead, and the reason is printed next to the answer.
The second is iOS. App Store rules require every browser on iOS to use the system engine, so Chrome is CriOS, Firefox is FxiOS, Edge is EdgiOS and Opera is OPT. None of them contains a Chrome token at all, and all of them contain "like Mac OS X", which is what makes a naive macOS test match first and report every iPhone in the world as a Mac. The order of tests here puts iOS and iPadOS ahead of macOS for that reason, and each of the four browsers is named rather than falling through to Safari or to Unknown.
The third is that several fields are frozen and carry a constant whatever the machine is. macOS has reported 10_15_7 in the user agent string for every version since Big Sur, so the number says nothing. Windows 11 reports "Windows NT 10.0" exactly as Windows 10 does, because Microsoft did not raise the NT version, so a tool that tells you which one you are on is guessing. Chrome's reduced user agent sends "Android 10" and the device model "K" on every Android device there is, and zeroes the minor, build and patch of its own version. Each of those is labelled frozen rather than reported as a reading, and the page says what the constant is and why.
Where the string cannot answer, the browser itself sometimes can. navigator.userAgentData is the browser answering the same questions about itself in structured form, and on a Chromium build it carries the real platform version, the device model and the CPU architecture. That is the only reference a user agent parser can be checked against that is not another parser, so when the box holds your own browser's string the two are shown side by side with the disagreements marked. On the machine these tests run on, the string says macOS 10.15.7 and the browser says macOS 26.6.2, and the string cannot give the architecture at all while the browser reports ARM64. Safari and Firefox declined to implement the API, and the page says so rather than leaving the panel blank.
Non-browser clients are the other half. A keyword list built from bot, crawl, spider, slurp, search, fetch and archive misses facebookexternalhit, curl, python-requests, Go-http-client and okhttp, which between them account for a great deal of what actually hits a server. Named crawlers are matched on the token each one publishes, including the AI crawlers that appeared recently, and anything left that writes the product/version form RFC 9110 section 10.1.5 describes without opening with Mozilla is reported as a library rather than as a desktop browser.
Finally, the whole string is broken up by the RFC 9110 grammar rather than on whitespace, so "Windows NT 10.0" stays one item instead of three, and each piece is shown with what it means. Above all of it sits the fact that decides how much any of this is worth: a user agent string is whatever the client chose to send. Nothing measures it, every browser lets an extension change it, and a crawler that wants to look like a person simply writes a browser string.
A CriOS string has no Chrome token at all and says "like Mac OS X". The page names Chrome, reports iOS rather than macOS, and gives the engine as WebKit because iOS requires the system engine.
The string carries SamsungBrowser/23.0 and Chrome/115.0.0.0. The browser is Samsung Internet 23; the Chrome number is the Chromium version it is built on, and both are shown with a line saying which is which.
Chrome sends "Android 10; K" on every Android device. The version is marked frozen and the model is not reported at all, because K is a constant rather than a device.
The Facebook link fetcher contains none of the usual crawler keywords, so keyword lists miss it. It is matched on its own token and reported as a crawler.
iPad traffic reads as macOS, Brave reads as Chrome, and every Android device reads as Android 10. The page names each of those rather than presenting the number as a fact.
Paste the User-Agent header and see the browser, the engine and which parts of the string were constants rather than readings.
Named crawlers, AI crawlers and library clients are identified separately, and anything that is not identifiable is said to be not identifiable rather than called a desktop browser.
On a Chromium browser, compare the string against navigator.userAgentData and see exactly which fields the string gets wrong about the machine it came from.
Because the string is lying, on purpose. Every Chromium browser has sent AppleWebKit/537.36 and Safari/537.36 since 2013 so that sites sniffing for WebKit would serve it the right code. The engine is Blink. Reading the token instead of the browser is the single most common error a user agent parser makes.
No, and nothing can from the string. Microsoft did not raise the NT version, so both report Windows NT 10.0. Client Hints can answer it: a platformVersion of 13 or higher means Windows 11.
Because Safari and Chrome froze the number there. Every macOS from Big Sur onward reports 10_15_7 in the user agent string, and Firefox reports 10.15. The real version is not in the string at all.
Those are constants in Chrome's reduced user agent, sent by every Android device regardless of what it is. The real version and model are in the Client Hints platformVersion and model fields, and a site has to ask for them.
Only as far as you trust the client. A user agent string is whatever the client decides to send: nothing measures it, every browser lets an extension change it, and a crawler that wants to look like a person simply writes a browser string. Use feature detection for anything that matters.
Brave removes its own token deliberately, so its string is identical to Chrome's. No parser can separate them, and one that claims to is guessing. The page says so on every plain Chrome string.
The User-Agent Client Hints API: the browser answering the same questions in structured form, with the real platform version, device model and architecture behind a permission-like request for the high entropy values. Only Chromium browsers implement it; Safari and Firefox declined.
This runs as client-side JavaScript. Keys, tokens, payloads, and other inputs never leave your device.