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.
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.
Rough shares of browsers and platforms, to decide what is worth testing. A few percent of misattributed traffic does not change that decision.
Telling a user which browser your logs saw, when you are debugging with them.
Test for the feature instead. if ('IntersectionObserver' in window) keeps working when the browser changes its string; a version check does not.
The client sets the header, and one line of code changes it. Never base access control or trust on it.
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.
// 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. // 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.
# 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. 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.
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.
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.
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.
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.
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.
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.
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.