Developer Tools

What is a User-Agent String? Complete Guide to Browser Detection

A User-Agent string is the HTTP header your browser sends to identify itself. Learn how to read every token, why it's a pile of legacy lies, how servers parse it, and why Client Hints are replacing it.

By Inventive HQ Team

A User-Agent string is the text your browser puts in the HTTP User-Agent request header to announce what it is — the browser, its rendering engine, the operating system, and often the device — so the server can decide what to send back. A typical Chrome-on-Windows value looks like Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36. It is defined in RFC 9110, sent on essentially every request, and — critically — fully controlled by the client, so it can be changed to say anything. That last fact is why you should treat it as a hint, never as proof.

That is the summary an AI Overview will give you. Here is what it can't show you: why that string is a museum of 30-year-old compatibility hacks, how to read each token, exactly how servers parse it, and why the whole mechanism is being dismantled in favor of Client Hints. Below is a labeled anatomy of a real UA, an animated request/parse flow, a token cheat-sheet, and a decision guide for when (rarely) UA detection is still the right call.

Anatomy of a real User-Agent string

Every modern desktop UA follows the same skeleton, and almost none of it means what it literally says. Here is the Chrome example above, dissected token by token:

Anatomy of a Chrome User-Agent string Each token of the string Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 labeled with what it actually means. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36 Mozilla/5.0 Legacy fossil (all browsers lie here) Windows NT 10.0; Win64; x64 Platform / OS token (this part is real) AppleWebKit/537.36 Engine claim — frozen, Chrome isn't WebKit Chrome/120 The one token that names the real browser Why so much of it is fake Browsers copy each other's tokens so old server-side sniffing code keeps serving the full experience. Chrome claims Mozilla, AppleWebKit, KHTML, Gecko, AND Safari — five identities in one line. Trust ranking of the tokens Real browser name/version (Chrome/120) — most reliable, still spoofable Platform token (Windows NT 10.0) — usually real, coarse-grained by design Mozilla / AppleWebKit / Gecko — pure compatibility theater

The single most important takeaway: the only token that reliably names the browser is the vendor token near the end (Chrome/120, Firefox/121, Edg/120, OPR/106). Everything to its left is a compatibility ritual. Note also that Edge appends Edg/120 after Chrome/120, and Opera appends OPR/106 — order matters when you parse, because a naive "contains Chrome" check will misclassify both.

Advertisement

How a server actually uses the User-Agent

The header travels with the request, the server (or a reverse proxy in front of it) reads it, runs it through a parser library, and branches on the result. Here is the round trip:

Request flow: how a server reads and acts on the User-Agent header Browser sends a request with a User-Agent header; a reverse proxy and server parse it and return tailored content. Browser sets User-Agent on the request Proxy / Server reads header, runs UA parser Response tailored content, Vary: User-Agent

GET / User-Agent: Mozilla/5.0…

Why the Vary header matters If a response changes based on the UA, send `Vary: User-Agent` so caches and CDNs don't serve the desktop page to a mobile client. Forgetting it is the classic cause of "wrong layout after a CDN cache hit."

The parsing itself is almost never done by hand. Regex-parsing UA strings yourself is a well-known trap — the format has no strict grammar, tokens appear in vendor-specific orders, and new device strings ship weekly. Use a maintained library (ua-parser-js, woothee, device-detector) that ships a regularly-updated regex database, or paste a string into our client-side parser to see the fields broken out:

Loading interactive tool...

Token cheat-sheet: what each part means

When you do need to read a UA by eye, this table covers the tokens you will actually encounter.

TokenAppears inWhat it really meansTrust it?
Mozilla/5.0Every browserFrozen legacy prefix from the Netscape era. Says nothing.No — ignore
Windows NT 10.0Windows browsersOS platform + version. NT 10.0 = Windows 10 and 11 (they share it).Mostly — coarse
Macintosh; Intel Mac OS X 10_15_7macOS browsersFrozen at 10_15_7 on modern Safari/Chrome to limit fingerprinting.Version is fake now
AppleWebKit/537.36Chrome, Edge, SafariRendering-engine claim. Frozen number; Chrome uses Blink, not WebKit.No
(KHTML, like Gecko)Chromium browsersPure compatibility padding.No — ignore
Chrome/120.0.0.0Chrome + ChromiumThe real browser + major version. Minor digits now zeroed out.Yes (major only)
Edg/120.0.0.0Microsoft EdgeEdge marker, appended after Chrome/. Note: Edg, not Edge.Yes
OPR/106.0.0.0OperaOpera marker, appended after Chrome/.Yes
Version/17.0 Safari/605SafariVersion/ holds Safari's real version; Safari/605 is the engine build.Yes
Firefox/121.0 + rv:121.0Firefoxrv: = Gecko engine revision; Firefox/ = browser version.Yes
MobilePhone browsersHints a mobile viewport. Easily absent or faked.Weak signal
bot, crawler, spiderBotsWell-behaved crawlers self-identify (Googlebot, bingbot). Malicious ones lie.Only for good bots

When should you use User-Agent detection at all?

UA sniffing has a bad reputation because it is overused. Most of what people reach for it to do is better solved another way. Use this to decide:

GoalUse the User-Agent?Better approach
Change layout for phones vs desktopNoCSS media queries + responsive design
Check if a browser supports a featureNoFeature detection (if ('IntersectionObserver' in window))
Detect mobile server-sideRarelySec-CH-UA-Mobile Client Hint (clean boolean)
Serve the right OS-specific download (.dmg vs .exe)YesPlatform token or Sec-CH-UA-Platform
Analytics: which browsers do my users runYesParse UA (or Client Hints) into aggregate stats
Block or throttle known bad botsPartlyUA is one signal; combine with IP reputation + behavior
Access control / licensing / security gateNeverThe UA is client-controlled and trivially spoofed

The rule of thumb: UA detection is fine for optimization and analytics, and wrong for anything that must be correct or secure. If a wrong answer merely means a suboptimal layout, sniffing is acceptable. If a wrong answer means a security bypass or a broken feature, use detection or Client Hints instead.

The future: User-Agent Client Hints

Browsers are actively shrinking the classic UA because it is a fingerprinting liability — that one string leaks enough entropy to help identify individual users. The replacement is User-Agent Client Hints (UA-CH): instead of one bloated string, the browser exposes structured, opt-in headers.

  • Sec-CH-UA — brand + significant version list, e.g. "Chromium";v="120", "Google Chrome";v="120"
  • Sec-CH-UA-Mobile — a boolean, ?0 or ?1
  • Sec-CH-UA-Platform"Windows", "macOS", "Android", etc.

Low-entropy hints (brand, mobile, platform) are sent by default. High-entropy hints (full version, exact model, architecture) are sent only when a server asks via the Accept-CH response header. Chrome has already "reduced" its UA string so minor versions and device details are stripped; Firefox and Safari froze large chunks of theirs years ago. The practical implication: any code that pattern-matches specific version numbers or device names out of the UA is on borrowed time — migrate to Client Hints, which are documented in our guide to handling User-Agent Client Hints in modern browsers.

Key takeaways

  • A User-Agent string identifies the client in the HTTP User-Agent header (RFC 9110), and the client fully controls it — treat it as a hint, never as proof of identity.
  • Most of the string is legacy compatibility theater; the vendor token near the end (Chrome/, Firefox/, Edg/, OPR/) is the only reliable browser name.
  • Parse with a maintained library, not hand-rolled regex, and send Vary: User-Agent whenever the response depends on it so CDNs don't serve the wrong variant.
  • Prefer feature detection and CSS media queries over sniffing; reserve UA logic for OS-specific downloads and analytics.
  • The classic UA is being frozen and reduced in favor of structured Client Hints (Sec-CH-UA*) — migrate version- and device-specific logic accordingly.

Paste any string into our User-Agent parser to break it into browser, engine, OS, and device fields — all client-side, nothing sent to a server.

Frequently Asked Questions

What is a User-Agent string?

A User-Agent string is a text value sent in the HTTP User-Agent request header that identifies the client software making the request — the browser, its rendering engine, the operating system, and often the device. Servers read it to decide what content, layout, or downloads to return. It is defined in RFC 9110 (HTTP Semantics) and is one of the oldest request headers on the web.

Why does Chrome's User-Agent still say "Mozilla/5.0"?

For historical compatibility. In the 1990s servers checked for "Mozilla" to decide whether a browser could handle frames and other features, so every competing browser started claiming to be Mozilla to avoid being served a degraded page. Chrome, Edge, Safari, and Firefox all still begin their UA with Mozilla/5.0 — it is a frozen fossil, not a statement about the actual browser.

Can a User-Agent string be faked or spoofed?

Yes, trivially. The User-Agent is just a request header the client controls, so any browser extension, curl --user-agent, bot, or scraper can set it to any value. Never use the UA string alone for security decisions, licensing, or access control — treat it as a hint, not proof of identity.

What is the difference between User-Agent and User-Agent Client Hints?

The classic User-Agent packs everything into one long, easily-spoofed string that leaks a lot of fingerprinting entropy. User-Agent Client Hints (UA-CH) split that data into discrete, structured headers such as Sec-CH-UA, Sec-CH-UA-Platform, and Sec-CH-UA-Mobile, and send only low-entropy values by default. High-entropy details like the full OS version are sent only when the server explicitly requests them.

How do I read my own User-Agent string?

In the browser console, run navigator.userAgent. On the command line, run curl -s https://httpbin.org/user-agent. To decode what each token means, paste the string into a User-Agent parser, which breaks it into browser, engine, OS, and device fields.

Is the User-Agent string being removed from browsers?

No — it is being frozen and reduced, not removed. Chrome has "reduced" the UA so that minor version numbers and detailed device/OS data are stripped, while keeping the header present for compatibility. The remaining detail moves to Client Hints. Firefox and Safari have also frozen large parts of their UA strings to limit fingerprinting.

What is the "rv:" token in a Firefox User-Agent?

rv: stands for "revision" and reports the version of Firefox's Gecko rendering engine, e.g. rv:121.0. Historically it tracked the Gecko version independently of the browser version, but in modern Firefox the two numbers usually match.

Should I use User-Agent sniffing to detect mobile devices?

Prefer feature detection and CSS media queries over UA sniffing. UA strings for mobile detection break constantly as new devices ship and as browsers freeze their strings. If you must check server-side, use the Sec-CH-UA-Mobile Client Hint (a clean boolean) instead of pattern- matching the word "Mobile" in the UA.

user-agent-parser