Command Palette

Search for a command to run...

User Agent Parser: Read Any Browser String the Right Way

User Agent Parser: Read Any Browser String the Right Way

T
Toolz Team
|Aug 31, 2026|16 최소 읽기

웹 도구 모음의 일부

The first time I had to make sense of a User-Agent string in bulk was during an SEO project on wpadminify.com, staring at a server access log trying to work out how much of the traffic was real people and how much was crawlers. I had a column of strings that all started with Mozilla/5.0, all mentioned Safari, and half of them were lying about being one browser while actually being another. Reading them by eye was hopeless. That is the job a User-Agent parser does, and after doing it the hard way too many times I built one into toolz.dev. This is the guide to it, and to the surprisingly messy header behind it.

TL;DR: The Toolz user agent parser takes a User-Agent string and splits it into browser, rendering engine, operating system, device type, and CPU architecture. It applies the detection order the header's quirks demand, so Edge is not misread as Chrome and mobile Safari is read from its real version token. It also flags known bots. Everything runs client-side: no upload, no signup, safe for real log lines.

What is a User-Agent string?

A User-Agent string is the value of the User-Agent request header that a browser or HTTP client sends with almost every request. The header is defined in RFC 9110, the HTTP Semantics specification, which describes it as a sequence of product identifiers and comments that let a server identify the software making the request. In practice it names the browser, its version, the rendering engine, the operating system, and often the device.

The intent was reasonable: give servers a way to know what is connecting so they can adapt responses or gather statistics. The reality is that the string has become one of the least trustworthy pieces of self-reported data on the web, not because it is malicious but because two decades of compatibility hacks have layered token upon token until the obvious reading is usually the wrong one.

Here is a modern Chrome string on Windows:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36

It claims to be Mozilla, mentions AppleWebKit, and ends with the word Safari. It is none of those things; it is Chrome. Every token before Chrome/126 is historical sediment. A parser exists precisely because you cannot trust the tokens that look most authoritative.

Why is parsing a User-Agent so error-prone?

The header grew by imitation. In the early browser wars, servers checked the User-Agent to decide which version of a page to send, and they checked clumsily, often with a simple substring match. A new browser that wanted to receive the good, modern page had to contain the token the server was looking for, so each browser copied the previous winner. Netscape called itself Mozilla, so Internet Explorer claimed to be Mozilla-compatible. When WebKit browsers arrived they carried the Mozilla and KHTML tokens. Chrome forked from WebKit and kept both AppleWebKit and Safari so that WebKit-sniffing servers would treat it well. The result is that a single string can honestly contain the names of four different browser lineages.

This creates concrete traps for anyone reading the string:

  • Edge and Opera both contain Chrome. Microsoft Edge appends Edg/126.0.0.0 and Opera appends OPR/, but both also carry the full Chrome/126 token because they are Chromium-based. Test for Chrome first and you will label every Edge and Opera user as Chrome.
  • Safari hides its real version. On the desktop and on iOS, Safari reports its user-facing version in a Version/17.5 token, while the Safari/604.1 token near the end is the WebKit build number, not the browser version. Read Safari/ as the version and you get a meaningless number.
  • Chrome on iOS is not Chrome's engine. Apple requires all iOS browsers to use WebKit, so Chrome on an iPhone reports CriOS and runs WebKit, not Blink. Firefox on iOS is FxiOS, also WebKit.
  • Windows 11 does not exist in the string. Microsoft never bumped the NT kernel token, so both Windows 10 and Windows 11 report Windows NT 10.0. The string cannot tell them apart at all.

A parser is a small pile of ordered rules that know about these traps. That is really all it is, but getting the order right is the whole game.

How does the Toolz user agent parser work?

The parser runs a sequence of checks whose order encodes the traps above. It looks for the browsers that embed another browser's token first. Edge before Chrome, Opera before Chrome, Samsung Internet and UC Browser before Chrome, so the borrowed Chrome token never wins by accident. It reads Safari from its Version/ token rather than its Safari/ build token. It recognises the iOS variants CriOS and FxiOS as Chrome and Firefox respectively while correctly reporting their engine as WebKit.

For the operating system it maps the Windows NT kernel number to the marketing name, so Windows NT 6.1 becomes Windows 7 and Windows NT 10.0 becomes Windows 10 or 11, stated honestly as a pair because the string genuinely cannot distinguish them. It restores the dotted form of iOS and macOS versions, which the header writes with underscores like 17_5, and it recognises Android, Chrome OS, and Linux.

For the device it classifies the request as desktop, mobile, tablet, or bot. The tablet rule is the fiddly one: an iPad is a tablet, an Android device without the Mobile token is a tablet, and anything matching Mobile, iPhone, or Windows Phone is a phone. Where the string exposes a device model, such as an Android build string or an Apple product name, the parser surfaces it.

It also flags bots. This is the field I reach for most, because when you are reading an access log the single most useful question is how much of the traffic is automated. The parser matches a broad set of signatures covering search crawlers, social preview fetchers, and command-line clients.

What can a User-Agent tell you, and what can it not?

It is worth being precise about the limits, because treating the string as fact leads to bad decisions.

Question Can the UA answer it? Notes
Which browser family Usually yes With correct detection order
Exact browser version Usually yes Increasingly frozen or reduced
Operating system name Usually yes Windows 10 vs 11 is impossible
Device type Roughly Heuristic, not guaranteed
Exact device model Sometimes Only when the string includes it
Whether the client is genuine No Trivially spoofable
Screen size or capabilities No Use feature detection instead

The last two rows matter most. A User-Agent is self-reported and can be changed in one line of code, set by any HTTP client, or frozen by the browser for privacy. A scraper can announce itself as Chrome on Windows and there is nothing in the string to contradict it. So the parsed result tells you what the client claims to be, which is useful for statistics and debugging but is not proof of anything. When you need to know what a browser can actually do, feature-detect in JavaScript rather than inferring capabilities from the name. This is the same principle behind writing resilient front-end code that the web developer toolkit roundup returns to repeatedly.

Are User-Agent strings going away?

Not exactly, but they are being deliberately reduced. Chromium browsers have been freezing and trimming the legacy string for a few years, capping the level of detail it exposes, especially the minor version numbers and some platform specifics. The replacement is User-Agent Client Hints, a mechanism where the server asks for exactly the pieces of client information it needs through Sec-CH-UA request headers and the navigator.userAgentData JavaScript API, rather than receiving one long string it has to parse. Client Hints is also where the Windows 10 versus 11 distinction finally becomes available, through Sec-CH-UA-Platform-Version.

The practical upshot for the next several years is that both exist. The classic User-Agent header still ships on every request from every browser and every non-browser client, and a great deal of tooling, analytics, and server-side logic still reads it. So parsing the string remains the most portable way to identify a client, even as the richer data moves to Client Hints. If you are building something new and want the platform version precisely, read Client Hints; if you are analysing an existing log or supporting the widest range of clients, parse the string.

How do I use the parser?

The flow is deliberately simple. Paste a User-Agent string into the box, or click one of the built-in samples to see a representative desktop, mobile, or bot string. To grab your own, open your browser console and type navigator.userAgent, then paste the result. As you type, the browser, engine, operating system, device type, CPU architecture, and bot flag update live, with no button to press. When you want the result elsewhere, copy it as a tab-separated table that pastes cleanly into a spreadsheet or a bug report.

Because the whole thing runs in your browser, you can paste raw access-log lines or real visitor strings without any of them leaving your machine. That client-side model is deliberate and is the same one behind every tool on the site, explained in the data privacy online tools guide. For a credential you are debugging alongside a request, the basic auth generator and the JWT decoder follow the same no-upload approach.

Where the parser fits with the other web tools

The user agent parser sits in a small cluster of request-and-response tools on the site. When you are inspecting the traffic to a domain, the domain search tool answers who owns and operates it. When a request carries a bearer token you need to inspect, the JWT decoder reads the claims out of it. When you are constructing an authenticated request in the first place, the basic auth generator builds the Authorization header. And when you are working on how a page presents itself to crawlers, which read your pages under their own User-Agents, the meta tag generator shapes the tags they consume.

For anyone assembling a personal set of these, the developer productivity tools guide covers how the browser-based utilities on the site fit into a working day. The point of keeping them together is that debugging an HTTP interaction rarely involves just one of these questions.

A practical workflow: reading a traffic log

Let me make this concrete with the task that started me down this road. You have exported a slice of your access log and you want to understand it. The naive approach is to eyeball the User-Agent column, which is exactly where the traps bite. A crawler that identifies itself politely as Googlebot is easy, but a headless scraper announcing itself as a normal Chrome build looks identical to a real visitor until you check the other signals.

The parser helps in two ways. First, the bot flag catches the honest crawlers and the common automation clients immediately, so you can separate the obvious machine traffic from the human traffic in one pass. Second, the correct browser and OS breakdown of the remaining traffic tells you something real about your audience: whether it skews mobile, which operating systems dominate, whether an old browser still matters enough to test against. On the WP Adminify work, that breakdown changed which browsers we prioritised for testing and confirmed that a chunk of what looked like organic traffic was preview and monitoring bots rather than readers. Parsing the strings turned a wall of noise into a decision.

The one discipline to keep is the one from the limits section: the parsed result is a claim, not proof. A determined scraper will forge a convincing string, and no parser can catch that from the User-Agent alone. Combine the parse with request patterns, rate, and other signals when the stakes are high. For everyday statistics and debugging, though, a correct parse is exactly what you need, and doing it by hand is the mistake.

What do the rendering engine and CPU fields tell me?

Two of the parsed fields get less attention than the browser and OS, but both are useful. The rendering engine is the component that actually turns HTML and CSS into pixels, and it is a better predictor of how a page behaves than the browser name. Chrome, Edge, Opera, Brave, Samsung Internet, and most others share the Blink engine, so a rendering bug that appears in one usually appears in all of them; Firefox uses Gecko; and Safari, along with every browser on iOS, uses WebKit. When you are triaging a layout bug, grouping your traffic by engine rather than by browser name tells you how many genuinely distinct rendering paths you have to test, which is often just three.

The parser derives the engine from the platform tokens rather than the browser label, which is why it can report Blink for a Chromium browser and WebKit for Safari even though both descend from the same AppleWebKit token. It also catches the older engines, Trident for Internet Explorer and EdgeHTML for legacy Edge, which still show up in enterprise logs.

The CPU architecture field reads the platform tokens for x86_64, Win64, arm64, and their relatives, reporting whether the client is a 64-bit, 32-bit, or ARM machine. It is the field to check when you serve platform-specific downloads and need to know which build a visitor can run, and it is a quiet signal of how modern your audience's hardware is.

Frequently Asked Questions

What is a User-Agent string? A User-Agent string is the value of the User-Agent HTTP header that a browser or client sends with each request. It is a list of product tokens naming the browser, its rendering engine, the operating system, and often the device, defined in RFC 9110. Servers read it to identify the software connecting to them.

How do I find my own User-Agent? Open your browser's developer console and type navigator.userAgent, then press Enter. The string it prints is exactly what your browser sends to servers. Paste it into the user agent parser to see the browser, operating system, and device it decodes to.

Why does Chrome's User-Agent contain the word Safari? For backward compatibility. Chrome forked its engine from Apple's WebKit, and early servers checked for the Safari token before serving modern pages, so Chrome kept it to avoid being downgraded. The same history is why nearly every browser still begins its string with Mozilla/5.0.

Can a User-Agent tell Windows 10 from Windows 11? No. Both report Windows NT 10.0 because Microsoft never incremented the NT kernel token for Windows 11, so the string alone cannot distinguish the two. The modern way to tell them apart is User-Agent Client Hints, specifically the Sec-CH-UA-Platform-Version header.

Is a User-Agent reliable for identifying a device? It is a useful hint, not proof. User-Agents can be changed in one line of code, set by any HTTP client, spoofed by scrapers, or frozen by the browser for privacy. Treat the parsed result as what the client claims to be, and combine it with other signals when accuracy matters.

How does the parser detect bots and crawlers? It matches the string against a broad list of known signatures, including search crawlers like Googlebot and Bingbot, social preview fetchers, and automation clients like curl, wget, and headless Chrome. Any match sets the bot flag and classifies the device as a crawler.

Is it safe to paste production log User-Agents here? Yes. All parsing happens in your browser with JavaScript, and the string is never sent to any server. You can paste raw access-log lines or real visitor User-Agents without them leaving your device.

Are User-Agent strings being deprecated? The header is being frozen and reduced, not removed. Chromium browsers now cap the detail in the legacy string and expose richer data through User-Agent Client Hints instead. The classic string still ships on every request, so parsing it remains the most portable way to read client details.

Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!