User-Agent Strings Explained
TL;DR: The User-Agent header is a 30-year-old compatibility hack that every browser
still sends on every request. Most of its tokens are lies kept for historical reasons. The truth about
your browser has largely moved to Sec-CH-UA (Client Hints). Decode your own UA with our
User-Agent Analyzer.
📋 Contents
Anatomy of a modern User-Agent
Here's the User-Agent a recent Chrome on Windows 11 sends:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
That single line contains six separate product tokens, at least four of which are pretending to be something
they're not. It claims to be Netscape Navigator (Mozilla/5.0), claims to be KHTML (Konqueror's
engine), claims to be Gecko (Firefox's engine), and claims to be Safari — all before getting to the honest
part (Chrome/131). Then it claims to be Safari again for good measure.
Reading a UA is less like parsing a structured data format and more like reading the archaeological record of the web browser wars. Every weird token is there because a website, somewhere, once broke when it wasn't. Let's dig through the layers.
Why it starts with Mozilla/5.0 — the oldest lie on the web
In 1994 Netscape's codename was Mozilla. The Navigator browser identified itself as
Mozilla/1.0. Websites began branching on this token: "If it's Mozilla, serve the fancy
JavaScript version; otherwise serve plain HTML."
When Microsoft shipped Internet Explorer 2 in 1995, it faced a cold reality: websites that checked for
Mozilla would serve IE the stripped-down page. The fix? Microsoft made IE claim to be
Mozilla/2.0 (compatible; MSIE 3.0; ...). Now sites would serve IE the full experience.
Every new browser repeated this trick. KHTML wanted pages meant for Gecko, so Safari's WebKit claimed to be
"KHTML, like Gecko." Chrome wanted pages meant for Safari, so it claimed to be Safari. And they all still
claim to be Mozilla, because a 2005-vintage PHP script somewhere still does
if (strpos($ua, 'Mozilla') === false) { echo "Please use a modern browser"; }.
🧠 The lesson
The User-Agent is not a statement of fact. It's a compatibility payload — a sequence of lies each browser tells to make sure old servers hand back the good content. You can't "read" it for truth without knowing which token in the chain is the honest one.
Every token, decoded
Pretends to be Netscape. Always 5.0 for the last twenty years — the number is a constant, not
a version. Every browser sends this.
The platform comment. Windows NT 10.0 means Windows 10 or Windows 11 — Microsoft chose not to
bump the NT version for 11, so servers can't distinguish them from the UA alone. Win64; x64
means 64-bit x86. On macOS this becomes (Macintosh; Intel Mac OS X 10_15_7) — note that
macOS 11+ also freezes at "10_15_7" for compatibility. Linux shows (X11; Linux x86_64).
Claims to be the WebKit rendering engine version 537.36. Chrome forked Blink from WebKit in 2013 but still sends this exact version on every request. The number has not incremented in over a decade. Changing it now would break some corporate intranets.
A literal promise: "I support KHTML-style APIs, and I also look enough like Gecko that you can treat me like Firefox." Both rendering engines are no longer what WebKit or Blink actually use, but this string stays because removing it would trigger ancient user-agent-sniffing code paths.
The honest token. "Chrome version 131." Note the .0.0 — Chrome froze the minor version
digits in 2022. You no longer see the full build number (which used to look like
Chrome/131.0.6778.205) in the UA. The precise version moved to
Sec-CH-UA-Full-Version-List, which is only sent when servers explicitly request it.
Chrome claiming to be Safari. Again: some site in 2009 served better CSS to Safari than to Chrome, and
the workaround is still in every UA today. The 537.36 matches the WebKit version above.
Microsoft Edge adds this to the end of a Chrome-style UA. Note the three-letter Edg — not
Edge, which was the token old EdgeHTML-based Edge used. Microsoft shortened it specifically to
avoid triggering old "if Edge, show upgrade warning" scripts.
Opera, Vivaldi, and Brave all ship on Chromium. Opera and Vivaldi append their own tokens at the end of a Chrome UA. Brave famously does not — by default it sends an unmodified Chrome UA to blend in with the ~65% of users who are on Chrome.
Firefox's honest part. Gecko/20100101 is another frozen token (the date never advances —
it was fixed to January 1, 2010 to keep parsers happy). Firefox/122.0 is the real browser
version.
On iOS, Apple requires all browsers to use WebKit. So "Chrome for iOS" is really Safari under the hood,
wearing Chrome's interface. The UA still says CriOS/131 as a branding tell, but the rendering
engine and feature set are Safari's.
Enter Client Hints (Sec-CH-UA)
Because the UA is a tangled mess, Google proposed a replacement: User-Agent Client Hints. Instead of one big string, the browser sends several small, structured headers:
Sec-CH-UA: "Chromium";v="131", "Not_A Brand";v="24", "Google Chrome";v="131"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "Windows"
These are sent automatically on every request — but only the coarse-grained ones. More detailed hints
(platform version, architecture, device model, full version list) are sent only after the server opts in via
an Accept-CH response header. This is called the "low entropy / high entropy" split: low-entropy
hints go out to everyone; high-entropy hints require a server to ask.
The "GREASE" token. Notice the "Not_A Brand" in the example. That's
deliberately random-looking chaff inserted so that servers are forced to parse the header properly instead
of hardcoding the known brands. Chrome rotates the exact token occasionally to prevent servers from
hardcoding it too.
Browser support. Chrome, Edge, Opera, Brave, and Vivaldi (all Chromium) send Client Hints. Firefox and Safari do not — their privacy models treat the additional signal surface as something to minimise rather than standardise.
🔍 See your own Client Hints
Our User-Agent Analyzer reads
navigator.userAgentData and shows exactly which low-entropy and high-entropy hints your
browser will send.
Why Chrome froze the UA string
Before 2022, the Chrome UA on Windows looked like:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36
That single line carried the exact Windows build, the exact Chrome version down to the patch, the architecture, and the rendering engine version. For fingerprinting purposes that's a lot — Panopticlick-style fingerprinters got 8–12 bits of entropy from the UA alone.
Chrome's "UA reduction" project (2022–2023) rolled back most of that. In the modern frozen form:
- Windows NT version freezes at
10.0regardless of actual Windows version. - Chrome's minor/build/patch versions become
0.0.0. - Architecture details (
Win64; x64) remain but no longer distinguish Windows 10 from 11.
The fine-grained truth moved to Client Hints, where servers have to actively request it. Most ad tech still does, but analytics tools that don't bother now see a much blurrier picture.
Bot user-agents and how sites detect them
Not all UA strings come from browsers. A handful of common bot UAs:
Googlebot/2.1 (+http://www.google.com/bot.html)
Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
GPTBot/1.0 (+https://openai.com/gptbot)
ClaudeBot/1.0 (+http://www.anthropic.com/claudebot)
facebookexternalhit/1.1
Twitterbot/1.0
curl/8.5.0
python-requests/2.31.0
Mozilla/5.0 (X11; Linux x86_64) PostmanRuntime/7.36.0
Well-behaved bots identify themselves and include a URL to their documentation. Scrapers that don't want to be blocked either copy a real browser UA wholesale or rotate through a pool of recent ones.
Sites don't rely on the UA alone for bot detection — a spoofed UA is trivial. They cross-check:
- Reverse DNS. Googlebot UAs that don't resolve to
*.googlebot.comare fake. - TLS fingerprint (JA3/JA4). Python's requests library negotiates TLS differently than Chrome, regardless of what UA it claims.
- Client Hints presence. A UA claiming Chrome 131 that doesn't send
Sec-CH-UAis almost certainly fake. - Behavioural signals. Mouse movement, scroll timing, navigation patterns.
Can you spoof your UA for privacy?
⚠️ Spoofing usually makes things worse
If your UA says "iPhone" but your Client Hints say "Windows," your canvas fingerprint shows a desktop GPU, and your screen resolution is 2560x1440, you look more distinctive than if you'd sent nothing. Fewer than 1 in 10,000 users have mismatched UAs, so inconsistency becomes its own fingerprint.
Two approaches actually help:
- Use a browser with a unified UA for all its users. Tor Browser is the canonical example — everyone on a given Tor Browser version sends identical UA and UA-related hints, producing genuine anonymity through the crowd.
- Use Firefox's
privacy.resistFingerprintingpreference, which normalises the UA, screen size, timezone, and language to a single Firefox default. It breaks some sites, but for the ones that still work you blend in with every other RFP user.
Spoofing to pretend to be a specific other browser (the "User-Agent Switcher" category of extensions) is mostly useful for compatibility ("make this old site think I'm IE11") rather than privacy.
Reading real UA strings
With the tokens decoded, some real-world UAs become readable:
iPhone running iOS 17 Safari
Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X)
AppleWebKit/605.1.15 (KHTML, like Gecko)
Version/17.4 Mobile/15E148 Safari/604.1
Real iPhone, iOS 17.4, Safari 17.4. The Mobile/15E148 is a generic build tag used by all iOS
Safaris — it's not a device identifier despite looking like one.
Android 14 Chrome
Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36
Android 14 on a Pixel 8. The device model is still in the UA on Android — one of the more distinctive signals left in the post-reduction era. Chrome on Android hasn't removed this yet.
macOS Safari
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
AppleWebKit/605.1.15 (KHTML, like Gecko)
Version/17.3 Safari/605.1.15
Safari on macOS. Note 10_15_7 — frozen at macOS Catalina for compatibility even on Sonoma
and later. The Intel claim is also frozen on Apple Silicon Macs, to keep sites that branch on
CPU architecture from serving the wrong bundle.
A suspicious one
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
Claims to be Chrome 90, which shipped in April 2021 — but any real Chrome that old has long since auto-updated. If a site sees this UA in 2026, it's almost certainly a scraper using a hardcoded UA from a scraping tutorial.
FAQ
Why does every user-agent start with Mozilla/5.0?
For historical compatibility. Netscape's codename was Mozilla, and websites in the 1990s branched on that token to decide whether to serve the feature-rich version of a page. Every browser since has claimed to be Mozilla/5.0 to avoid being downgraded. Removing the prefix today would break a long tail of old sites.
What's the difference between User-Agent and Sec-CH-UA?
User-Agent is a single free-form string. Sec-CH-UA is part of the newer Client Hints system: structured, machine-readable headers where coarse details are sent by default and fine-grained details require the server to opt in. Chromium browsers send both; Firefox and Safari send only User-Agent.
Can I spoof my user-agent for privacy?
Changing it usually hurts. A UA that disagrees with Client Hints, canvas fingerprint, and feature detection is itself a distinctive fingerprint. The only genuinely effective approach is to use a browser (Tor Browser, Firefox with resistFingerprinting) that unifies the UA across its entire user base.
Is User-Agent going away?
The string will stay for compatibility, but its information content is shrinking. Chrome has frozen most of its detail; Safari and Firefox hide even more. The real signals are moving to Client Hints (for sites that want them) or being removed entirely (for sites that don't need them).
What does a bot's user-agent look like?
Legitimate bots identify themselves openly (Googlebot, bingbot, GPTBot, ClaudeBot). Scrapers either copy a real browser UA or use library defaults like python-requests/2.31.0. Sites cross-check the UA with reverse DNS, TLS fingerprints, and behavioural signals to tell real bots from fake ones.
🛠️ Decode your own identity signals
All tools run in your browser. Nothing stored, nothing logged.
About FunWithText
We build free, privacy-focused text tools and network diagnostics. Most of our tools run in your browser — your data stays on your device. Our mission is to make privacy tooling accessible to everyone.
Read More Articles →📚 Related Articles
The HTTP Headers That Leak Your Identity
Fifteen request headers ranked by leak severity. UA is only the start.
What Your Browser Fingerprint Reveals
Canvas, WebGL, fonts, and the tiny tells that identify you across sites.
What Your IP Address Actually Reveals
Geolocation accuracy, ASN, rDNS, and what a VPN really changes.
How to Stop WebRTC Leaks in 2026
Your VPN probably doesn't cover WebRTC. Here's how to fix it per browser.