Parsing User-Agent strings for browser, OS, and bot signals
Published: 2026-09-05
How HTTP User-Agent strings encode browser, OS, device, engine, and bot hints—why order of tokens matters, what “frozen” UAs change, and how to break a log line into fields without uploading it.
The User-Agent (User-Agent) header is a free-form string that HTTP clients send so servers can guess the browser family, OS, device class, and sometimes whether the caller is a crawler. It shows up in access logs, CDN analytics, WAF rules, and support tickets—often as one opaque line. Parsing that line into structured fields is useful for debugging and triage; treating it as hard identity is not.
This guide explains how common UA strings are shaped, which tokens mean what, how bot heuristics work, and how to inspect a string locally with the same local-only model as other LocalTools utilities. For the broader privacy picture of UA as one fingerprint signal among many, see Browser fingerprinting: what sites can infer.
What a User-Agent is (and is not)
| Claim | Reality |
|---|---|
| “UA proves the browser” | No — clients can spoof or freeze any string |
| “UA is required for HTTP” | No — some clients omit or minimize it; servers still respond |
| “Same browser ⇒ same UA forever” | No — versions change; Chromium reduced UAs; privacy modes rewrite it |
| “Useful for coarse bucketing” | Yes — desktop vs mobile, Chrome-major vs Safari, Googlebot vs human |
Use parsed fields for routing hints, analytics buckets, and log reading—not for authentication, license enforcement, or “this is definitely that person’s phone.”
Anatomy of a typical browser UA
Most desktop and mobile browsers still start with a historical Mozilla/5.0 prefix, then a parenthetical platform block, then product tokens:
Mozilla/5.0 (<platform>) <engine> … <browser>/<version> …
Example (Chrome on Windows):
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/120.0.0.0 Safari/537.36
| Part | Example | What parsers usually extract |
|---|---|---|
| Compatibility prefix | Mozilla/5.0 |
Historical; rarely useful alone |
| Platform / OS | Windows NT 10.0; Win64; x64 |
OS name/version, CPU architecture (amd64) |
| Layout engine claims | AppleWebKit/537.36, KHTML, like Gecko |
Often compatibility theater—Chromium still advertises WebKit |
| Real browser product | Chrome/120.0.0.0 |
Browser name + version + major |
| Trailing Safari token | Safari/537.36 |
Present on Chrome/Edge; do not treat as Safari |
Token order matters. Edge and Opera ship Chromium-based UAs that include Chrome/… and a more specific product (Edg/…, OPR/…). A naive “first match wins on Chrome” rule mislabels Edge as Chrome. Robust parsers check Edge / Opera / Samsung Internet / Firefox before Chrome, and Safari only when a Version/… + Safari pattern appears without a Chrome token.
Mobile and device hints
iPhone Safari often looks like:
Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15
(KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1
Here the platform block carries device model (iPhone) and OS (iOS with underscores turned into dots). Android strings may include Linux; Android … plus a device model token. Heuristic parsers map these into device types such as desktop, mobile, tablet, console, smart TV, or wearable—plus optional vendor/model when the string includes them.
Engines vs browsers
| Field | Meaning | Common values |
|---|---|---|
| Browser | Product the user (or bot) claims | Chrome, Safari, Firefox, Edge, Opera |
| Engine | Rendering / JS stack hint | Blink, WebKit, Gecko, Trident |
| CPU | Architecture token from the platform block | amd64, arm64, etc. |
Chromium browsers often claim AppleWebKit for legacy CSS sniffing while the effective engine is Blink. When reading a parse result, prefer the browser product token for “what is this?” and treat the engine as secondary context.
Bot and crawler signals
Crawlers usually advertise themselves more honestly than browsers—SEO and rate-limit tooling depend on it:
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Offline parsers flag likely bot / crawler with keyword heuristics: bot, crawler, spider, Googlebot, bingpreview, facebookexternalhit, GPTBot, HeadlessChrome, curl/, wget, and similar. That yields a boolean plus a device type of “bot” for common cases.
Caveats:
- Spoofed bots — a scraper can paste a Googlebot UA; reverse-DNS / IP allowlists are the real verification for search crawlers.
- Headless browsers — may look almost human; some include
HeadlessChrome, others do not. - Privacy-hardened browsers — may look like a generic Chrome desktop string and omit device model detail.
Treat “is bot” as a triage signal for logs, not proof of intent.
Frozen UAs, Client Hints, and missing fields
Browsers have been reducing the information in User-Agent:
- Reduced / frozen UAs — Chromium may report a fixed OS version or a coarse Chrome major so sites stop depending on every minor build.
- Client Hints (
Sec-CH-UA,Sec-CH-UA-Platform,Sec-CH-UA-Mobile, …) — structured replacements sent only when the server opts in (and subject to privacy policies). Logs that only store the classic header will not see those hints. - Empty or custom UAs — scripts, IoT devices, and privacy tools may send
curl/8.x, a single token, or nothing useful.
A local heuristic parser will leave fields blank rather than invent them. That is expected: exotic, frozen, or minimal strings simply do not encode a full browser/OS/device matrix.
Why parse locally
UA strings from production logs can include internal hostnames in Referer-adjacent exports, customer IPs in the same CSV, or rare enterprise clients. Pasting rows into a third-party “UA lookup” API uploads that context. A browser-only parser runs regex rules in your tab—no UA database call, no network lookup—so the string never leaves the device. See also Why “local only” matters for developer tools.
Try it on LocalTools
Open the User agent parser:
- Paste a UA from server logs, CDN analytics, or an API gateway—or click This browser to inspect the current tab.
- Review browser, major version, OS, device type, vendor/model, engine, CPU, and likely bot flags.
- Copy individual fields or the full JSON for tickets, feature-flag notes, or analytics debugging.
Results are heuristic: common desktop, mobile, and bot patterns work well; custom or heavily reduced UAs may omit fields. Nothing is sent to an external UA lookup service.
Related reading
- User agent parser — break down a UA string in your browser
- Browser fingerprinting: what sites can infer — UA as one of many tracking signals
- Why “local only” matters for developer tools
- Converting curl to JavaScript fetch — another place request headers (including UA) show up when debugging HTTP
- MIME types and file extensions — parallel story of labels that hint at content without proving it