User Agent Parser

Break a user agent string into browser, engine, operating system and device. Paste one from a log, or parse your own. Use it for analytics and support tickets, never for anything that has to be correct.

Browser

Engine

Operating system

Device

Reading the string

Parsed JSON

1 Every browser claims to be Mozilla

Your string starts with Mozilla/5.0. So does Chrome's, Safari's, Edge's and every crawler's. The reason is a fight from 1995: Netscape called itself Mozilla, servers started sending the good version of pages only to Mozilla, so Internet Explorer began claiming to be Mozilla as well. Every browser since has kept the claim so that old server checks still send it the full page.

The same instinct produced KHTML, like Gecko in WebKit's string and Safari/537.36 in Chrome's. None of it describes the browser you are using. Those tokens exist because servers once sniffed for the wrong thing, and they are why a UA parser has to guess from patterns.

2 Use it for statistics, not decisions

Fine: analytics

Rough shares of browsers and platforms, to decide what is worth testing. A few percent of misattributed traffic does not change that decision.

Fine: a support note

Telling a user which browser your logs saw, when you are debugging with them.

Not fine: feature decisions

Test for the feature instead. if ('IntersectionObserver' in window) keeps working when the browser changes its string; a version check does not.

Not fine: anything security

The client sets the header, and one line of code changes it. Never base access control or trust on it.

3 UA strings carry less detail every year

Before Chrome reached version 100 in 2022, Google found enough sites whose version checks broke at three digits that it kept a fallback ready to freeze the major version at 99. Since then Chrome has been reducing the detail in the UA string and moving it into Client Hints, the Sec-CH-UA headers a server has to ask for explicitly. Platform version and device model are already coarsened or gone.

In practice, a parser that is accurate today will get vaguer over time, and code that depends on the detail will start returning wrong answers without throwing an error. Feature detection does not have that problem.

How to use the User Agent Parser tool

  1. The page starts with your own user agent already parsed; Use mine brings it back.
  2. Paste any other string over it, from a log file or an analytics export.
  3. Sample cycles through Chrome, iPhone Safari, Mac Safari, Android, Firefox, Googlebot and curl.
  4. The Reading the string note explains the legacy tokens: the Mozilla claim, the KHTML claim, and what they mean.

Detect features, not browsers

The right way

// Test for the thing you need
if ("IntersectionObserver" in window) {
    observeLazyImages();
} else {
    loadEverything();
}

if (CSS.supports("selector(:has(a))")) { /* ... */ }
if ("share" in navigator) { /* ... */ }

// This keeps working when a browser changes its UA string,
// which they do constantly. A version check does not.

Client Hints, the replacement

// The server asks for what it wants
// Accept-CH: Sec-CH-UA-Platform-Version, Sec-CH-UA-Model

// In the browser, high-entropy values must be requested and awaited
const data = await navigator.userAgentData.getHighEntropyValues([
    "platformVersion",
    "model",
    "fullVersionList",
]);
console.log(data.platform, data.platformVersion);

// navigator.userAgentData is Chromium-only. Safari and Firefox
// have declined to implement it, so this is not a general answer.

Chrome is reducing the detail in the UA string over time and moving it here, so UA parsing gets less precise by design.

Parsing server-side, for analytics

# pip install ua-parser
from ua_parser import user_agent_parser

ua = request.headers.get("User-Agent", "")
parsed = user_agent_parser.Parse(ua)

print(parsed["user_agent"]["family"])   # Chrome
print(parsed["os"]["family"])           # Mac OS X
print(parsed["device"]["family"])       # Other

# Fine for a dashboard. Never for an authorisation decision:
# the header is set by the client and can say anything.

Common errors and how to fix them

An iPad is detected as a Mac
iPadOS 13 and later request desktop sites by default and send a Macintosh user agent. Check for touch support instead: navigator.maxTouchPoints > 1 on a reported Mac.
Chrome is detected as Safari
Chrome's string has contained a Safari token since Chrome launched on WebKit in 2008. Order your checks so the more specific token wins, or use a real parser.
Version comparison broke at 100
String comparison, so "100" sorted below "99". Before Chrome 100 shipped in 2022, Google prepared a fallback that would freeze the major version at 99 because so much code did this. Parse to a number, or stop comparing versions.
A bot is not being detected
Well-behaved crawlers identify themselves; badly-behaved ones copy a browser string exactly. Do not rely on the UA for bot detection.
Detection stopped working after a browser update
UA strings change without notice, and Client Hints is removing detail step by step. Feature detection is the only approach that survives browser updates.

Good to know

The format is an accident of the 1995 browser war. Netscape called itself Mozilla, servers began sending frames only to Mozilla, and Internet Explorer started claiming to be Mozilla to get the same pages. Every browser since has kept the claim rather than risk being served a worse page, so every modern string begins Mozilla/5.0 and the token carries no information. The KHTML, like Gecko in WebKit strings is the same story one generation later.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Why does every browser claim to be Mozilla?

Because of the 1995 browser war. Netscape identified as Mozilla, servers started sending frames only to Mozilla, so Internet Explorer began claiming to be Mozilla too, and every browser since has kept the claim. Every modern UA string starts with Mozilla/5.0, so the token tells you nothing.

Can I trust a user agent string?

No. It is set by the client and anyone can change it in one line. Use it for analytics and rough compatibility notes, never for security decisions or access control.

Should I use this for feature detection?

No. Test for the feature instead: if ('IntersectionObserver' in window). UA sniffing breaks whenever a browser changes its string, as many version checks did when Chrome reached version 100 in 2022.

What is Client Hints?

The replacement. Chrome is reducing the detail in the UA string step by step and moving it to Sec-CH-UA headers that a server has to request. As a result, UA parsing gets less accurate over time, by design.

Why does my iPad say it is a Mac?

iPadOS 13 and later request desktop sites by default, so Safari on an iPad sends a Macintosh user agent. Distinguishing them needs a touch-support check, which is another reason to detect features rather than devices.

Related

The user agent arrives in a request header; the response you send back carries the status code and the content type. For the URL side of the same request, the URL parser breaks it apart.

More Developer Reference

Browse all developer reference

Copied to clipboard!