Here's a real user-agent string from a current Chrome browser on Windows:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
That string claims to be Mozilla, AppleWebKit, KHTML, Gecko, Chrome, and Safari, simultaneously. Three of those names refer to rendering engines made by different companies. One refers to a browser that hasn't existed in its original form since 2004. Only one of the names is accurate. Welcome to the user-agent string — thirty years of accumulated lies in a single header, and the slow, awkward transition to something better.
The user-agent string — a 30-year history in 200 characters
The User-Agent header was introduced in HTTP/1.0 in 1996. The original idea was honest: tell the server what browser made the request, so the server could send back appropriate content. Mosaic was Mosaic, Netscape Navigator was Netscape. Simple.
Then sites started sniffing the UA. If you're not Netscape, you don't get the fancy version of the site. If you're not Internet Explorer, you don't get the ActiveX features. The arms race started immediately: every new browser that wanted to render modern sites had to claim to be one of the dominant browsers, or get served the stripped-down fallback.
This cycle never stopped. Each new browser added its name to the end of the UA but kept the previous browsers' names at the front, to placate sites that were still sniffing. The result is a stack of identities, thirty years deep, none of which can be removed without breaking some long-forgotten compatibility check.
Why every UA claims to be Mozilla and Chrome and Safari
Walk through the chain piece by piece:
Mozilla/5.0. The original Netscape Navigator was internally code-named Mozilla, and its UA started with Mozilla/3.0. Sites in the mid-1990s checked for Mozilla/ at the start of the UA to decide whether the browser supported frames, tables, JavaScript. Every browser since has prefixed Mozilla/5.0 to its UA so those ancient sniffers don't lock it out. The number stopped meaning anything around 1998.
AppleWebKit and KHTML. AppleWebKit is the rendering engine Apple developed for Safari, forked from KHTML (KDE's browser engine). When WebKit-based browsers started appearing, sites began sniffing for AppleWebKit specifically to enable modern rendering. So Chrome — which was built on Apple's WebKit until 2013, when it forked into Blink — still claims AppleWebKit in its UA, even though it hasn't actually used WebKit for over a decade. The KHTML claim is more vestigial still.
Safari. Same story. Once sites started feature-gating on Safari, every WebKit-derived browser added Safari to its UA. Chrome's UA says it's Safari for the same reason it says it's Mozilla: compatibility paranoia.
Chrome. The one bit that's actually true. This is the browser you're using. By the time it appeared in the UA in 2008, the cargo-cult chain in front of it was already five names long.
Could this have been cleaned up? In principle, yes. In practice, no — there's no central registry of which sites do UA sniffing, and the long tail of broken sites is huge. Every browser vendor knows that trimming the UA would break something; they just don't know what. So nobody does it.
The new way — User-Agent Client Hints (UA-CH)
Client Hints are the structured replacement. Instead of one opaque string, the browser exposes individual fields as HTTP headers:
Sec-CH-UA— the browser brand and major version, e.g."Chromium";v="120".Sec-CH-UA-Mobile—?0or?1depending on whether this is a mobile device.Sec-CH-UA-Platform— the OS, e.g."Windows"or"macOS".
JavaScript can read the same data via navigator.userAgentData, which returns an object instead of a string. The structured format means no parsing, no regex, no ambiguity about which substring is the version number.
The privacy improvement comes from what's not exposed by default. Sites get the brand and the major version. They don't get the full version, the platform version, the device model, or any of the other high-entropy fields that make fingerprinting possible. If a site wants those, it has to ask explicitly via an Accept-CH response header, which signals intent and gives the browser a chance to refuse.
High-entropy vs low-entropy hints
Low-entropy hints — brand, mobile flag, platform — are sent with every request automatically. They're not useful for fingerprinting because everyone of a particular platform looks identical.
High-entropy hints require an explicit opt-in. Full browser version, OS version, device model, CPU architecture, bitness — sites have to request each one via Accept-CH, and the browser can refuse or strip them. JavaScript code asking for high-entropy data goes through navigator.userAgentData.getHighEntropyValues(), which is asynchronous and returns a promise. That's deliberate: it makes the cost of asking visible, which discourages bulk fingerprinting as a default behaviour.
On Chromium-based browsers running on Android, users can opt out of high-entropy hints at the OS level, and the browser will silently lie when asked. That's the design's biggest privacy win — passive fingerprinting doesn't work, and active fingerprinting can be detected.
Detection in practice today
Most production code does both: check for navigator.userAgentData, use it if available, fall back to parsing the UA string if not. The tool on this site does exactly that. It reads the structured Client Hints when the browser provides them and falls back to a UA-string parser otherwise.
The reality is the UA string isn't going anywhere for years yet. Firefox supports Client Hints but ships many fewer than Chromium. Safari supports them but with different defaults and a frozen UA string as a deliberate anti-fingerprinting policy — Apple decided the right answer was to lie consistently rather than expose structured truth. So any code that needs to work across all major browsers still has to handle the old UA string. Client Hints are the better tool when they're available, but they're not yet a complete replacement.
When to use the what-browser-am-i-using tool here
The what browser am I using tool shows both: the parsed details, the raw UA string, and the structured Client Hints side by side. Useful when you're filing a support ticket and the agent needs to know exactly what your browser is sending, or when you're checking whether a compatibility issue lines up with a specific version, or just curious what your browser tells every site you visit.
Related reading
For the full picture of what a site can see about your browser — not just identity, but capabilities, permissions, codec support, and storage — the browser diagnostic is the heavier-weight tool. The screen resolution checker covers the related question of what the page's viewport looks like to a site, which is independent of the UA but often diagnostic of the same kinds of compatibility issues.