Developer Tools

Why User-Agent Strings Are So Complicated

Every browser's User-Agent string is a museum of dead browsers, each one claiming to be the one before it. Here's the 30-year impersonation chain that explains why Chrome still says "Mozilla," "Safari," and "like Gecko."

By Inventive HQ Team

The User-Agent string is complicated because every modern browser deliberately impersonates the browsers that came before it — Chrome claims to be "Mozilla," "AppleWebKit," "KHTML, like Gecko," and "Safari" all at once, none of which it actually is. This is the residue of a 30-year "browser wars" arms race: web servers used to sniff the User-Agent to decide which features to serve, so each new browser copied its rivals' identifying tokens to avoid being locked out of the good content. The result is a string that reads like a museum of dead browsers, where the only token that names the real browser (Chrome/120.0.0.0) is buried among fossils that mean nothing today.

That is the summary an AI Overview would give you. Here is what it can't show you — the exact anatomy of a real string, the impersonation chain that produced each token, a lookup table of which claims are true, and a live parser you can paste your own User-Agent into.

Anatomy of a real User-Agent string

Here is a current Chrome-on-Windows User-Agent, dissected token by token. Hover on the color as it sweeps through — each segment is a claim the browser makes, and most of those claims are lies of convenience:

Anatomy of a Chrome User-Agent string A breakdown of Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, labeling each token as a fossil, platform, engine claim, or the real browser. One string, six claims Only one of these tokens names the browser you are actually using Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Mozilla/5.0 Fossil from Netscape. Every browser sends it. Windows NT 10.0 Platform token. Note: Win 10 AND 11 both say 10.0. AppleWebKit/537.36 Engine claim. Frozen at 537.36 since ~2015. Chrome/120.0.0.0 The one true token. Minor version zeroed. (KHTML, like Gecko) — "I render like Firefox's Gecko engine" (it does not) Safari/537.36 — "I am also Safari" (Chrome copied Safari's whole string)
Advertisement

The impersonation chain: how it got this bad

Nobody designed this. Each token was bolted on to solve a short-term compatibility problem, and none were ever safe to remove. The timeline below shows how each browser inherited the identity of the one before it.

The User-Agent impersonation chain, 1993 to today Timeline showing Mosaic, Netscape/Mozilla, Internet Explorer, Safari, and Chrome each adopting the identifying tokens of prior browsers. Each browser bolted the last one's identity onto its own 1993 · NCSA Mosaic NCSA_Mosaic/2.0 — an honest name for an honest browser 1994 · Netscape Navigator ("Mozilla") Mozilla/1.0 — sites served frames only to "Mozilla" browsers 1996 · Internet Explorer wants those frames too Mozilla/1.22 (compatible; MSIE 2.0; …) — IE claims to be Mozilla 2003 · Safari (built on KHTML/WebKit) …AppleWebKit… (KHTML, like Gecko) — inherits Firefox-targeted content 2008 · Chrome copies Safari's entire string Mozilla + AppleWebKit + KHTML/Gecko + Chrome + Safari — the pile-up is complete

The pattern is always the same: a server somewhere pattern-matches on a token to decide what to send, so the next browser copies that token rather than risk being served a degraded page. Removing any of them would break long-abandoned sites that still run the same sniffing logic, so they stay forever.

Token-by-token: which claims are actually true?

Paste your own string into the parser below to see this table filled in for your browser. Here is the reference for the canonical Chrome-on-Windows string:

TokenWhat it claimsIs it true?Why it's there
Mozilla/5.0"I am a Netscape-class browser"NoVestigial; every browser sends it, so it means nothing
Windows NT 10.0"Running on Windows 10"PartlyWindows 11 also reports 10.0 — indistinguishable here
Win64; x64"64-bit Windows on x64"UsuallyReal platform detail, though spoofable
AppleWebKit/537.36"WebKit engine build 537.36"NoFrozen at 537.36 since ~2015; not a live version
(KHTML, like Gecko)"I render like KHTML and Gecko"NoCompatibility bait for Konqueror- and Firefox-targeted code
Chrome/120.0.0.0"I am Chrome 120"YesThe only reliable token; minor version zeroed for privacy
Safari/537.36"I am also Safari"NoInherited so Safari-targeted content still loads

Parse your own User-Agent

The parser below runs entirely in your browser — nothing is sent to a server. Paste any User-Agent string (yours is pre-filled) and it breaks out the browser, engine, OS, and device tokens so you can see exactly which fossils your own browser is carrying.

Loading interactive tool...

Where this is heading: User-Agent Client Hints

The fix for a string nobody can safely change is to stop relying on the string. User-Agent Client Hints (UA-CH) replace the monolithic header with structured, request-what-you-need HTTP headers:

  • Sec-CH-UA — a low-entropy brand list with intentional "GREASE" noise, e.g. "Chromium";v="120", "Google Chrome";v="120", "Not?A_Brand";v="24". The fake brand stops servers from hard-coding brand strings the way they hard-coded "Mozilla."
  • Sec-CH-UA-Mobile — a boolean, ?0 or ?1.
  • Sec-CH-UA-Platform"Windows", "macOS", "Android", etc.
  • High-entropy hints sent only when a site explicitly asks: Sec-CH-UA-Platform-Version (the thing that finally distinguishes Windows 11 from Windows 10), Sec-CH-UA-Full-Version-List, Sec-CH-UA-Arch, Sec-CH-UA-Model.

Alongside this, Chrome's User-Agent Reduction program froze the legacy string: the minor version became 0.0.0, the platform token was capped, and device details were trimmed. Firefox and Safari took a different route — they froze and capped their own UA strings for privacy rather than adopting UA-CH broadly — so the legacy string is not disappearing everywhere at once. For years to come you will still receive the old fossil-laden header; UA-CH just gives you a cleaner, opt-in signal to trust instead.

One rule survives every era of this saga: the User-Agent is client-supplied text and is trivially spoofable. Use it for progressive enhancement, analytics, and layout hints where being wrong costs nothing — never for access control, licensing, or fraud prevention.

Further reading

Frequently Asked Questions

Why does Chrome's User-Agent say "Mozilla" and "Safari" when it is neither?

Because of a 30-year chain of compatibility spoofing. In the 1990s websites served advanced pages only to Netscape, whose UA started with "Mozilla." Internet Explorer copied "Mozilla/…(compatible; MSIE…)" to get the same pages. Safari later added "AppleWebKit" and "like Gecko" to inherit content meant for Firefox, and Chrome copied Safari's entire string to inherit content meant for Safari. Every browser impersonates its predecessors so that server-side sniffing does not lock it out. The tokens are fossils, not accurate identity claims.

What does "Mozilla/5.0" actually mean today?

Effectively nothing. Every mainstream browser — Chrome, Firefox, Safari, Edge, Opera — begins its User-Agent with "Mozilla/5.0." It is a vestigial token from Netscape Navigator (codenamed "Mozilla," short for "Mosaic killer") that servers once used to detect a capable browser. It has been constant across all browsers for so long that it carries zero information.

Does Windows 11 show up differently from Windows 10 in the User-Agent?

No. In the classic User-Agent string, Windows 11 still reports "Windows NT 10.0," identical to Windows 10. Microsoft never bumped the NT version in the UA. The only reliable way to tell them apart is the User-Agent Client Hint "Sec-CH-UA-Platform-Version" — Windows 11 reports platform version 13.0.0 or higher, while Windows 10 stays below 13.

Why is AppleWebKit always version 537.36 in Chrome and Safari?

The "AppleWebKit/537.36" token has been frozen since roughly 2015. Chromium and Safari stopped incrementing it to avoid breaking the countless websites that pattern-match on that exact number. It no longer reflects the real engine build — it is a compatibility constant, not a live version.

What are User-Agent Client Hints and how are they different?

User-Agent Client Hints (UA-CH) are a set of structured HTTP request headers — Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, and on-demand "high-entropy" hints like Sec-CH-UA-Platform-Version — designed to replace the monolithic User-Agent string. Instead of one opaque string, the server asks for exactly the fields it needs. Chromium browsers send a minimal set by default and reveal more only when a site requests them, which reduces passive fingerprinting.

Is the User-Agent header defined by an RFC?

Yes. The User-Agent request header is specified in RFC 9110 (HTTP Semantics, June 2022), section 10.1.5, which replaced the earlier RFC 7231. The spec says the header should list product tokens in decreasing order of significance. User-Agent Client Hints are defined separately in a W3C / WICG draft, not an RFC.

Can I trust the User-Agent string to identify a browser?

Not for security decisions. The User-Agent is client-supplied plain text and trivially spoofable — any script, bot, or command-line tool can send whatever string it wants. Use it for progressive enhancement and analytics where being wrong is harmless, but never for access control, licensing, or fraud prevention. Combine Client Hints with behavioral signals if you need higher confidence.

Why did Chrome freeze its minor version to "0.0.0"?

As part of User-Agent Reduction, Chrome replaced the detailed minor/build numbers (for example 120.0.6099.129) with "120.0.0.0." The full build number added fingerprinting entropy without helping legitimate feature detection, so Chromium zeroed it out while keeping only the major version.

user-agent-parser