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:

  1. Paste a UA from server logs, CDN analytics, or an API gateway—or click This browser to inspect the current tab.
  2. Review browser, major version, OS, device type, vendor/model, engine, CPU, and likely bot flags.
  3. 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

All learn articles