Skip to content

Glossary

User-Agent

The HTTP header that lies about itself

By Published Updated

The User-Agent header is supposed to identify the client making an HTTP request — browser name, version, OS, etc. It is also the most overgrown header in HTTP history, lying about its own contents for backwards-compatibility reasons that compound year over year.

A typical modern Chrome User-Agent string:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

Chrome claims to be Mozilla, Apple WebKit, and Safari, all at the same time. None of those tokens are accurate — they exist because some 1998 server-side code checked for “Mozilla” before serving modern HTML, so every subsequent browser added “Mozilla/5.0” to avoid being downgraded. The string has been a museum of compatibility hacks ever since.

Modern alternatives:

  • User-Agent Client Hints (Sec-CH-UA family of headers) — Chrome started sending structured client hints in 2020. Servers can opt in via Accept-CH. Cleaner data, smaller default footprint.
  • Feature detection instead of UA sniffing — check whether the API you need exists rather than guessing from the browser version.

User-Agent strings can be spoofed trivially; treat them as a hint, not a security boundary. For analytics, the UA gives a rough breakdown of client share; for actual decisions, feature-detect.

The Chrome User-Agent reduction project: Google began phasing down UA-string entropy in 2022, freezing the minor version, dropping the precise OS version, and unifying mobile/desktop strings. The goal was to reduce passive fingerprinting — a UA string can identify a unique browser among hundreds of thousands of others purely from its build-version tokens. By 2025 the Chrome UA string is meaningfully shorter and less identifying. Firefox and Safari have followed at slower paces. Sites that still depend on parsing the UA for browser detection are slowly breaking — the modern Client Hints API (Sec-CH-UA, Sec-CH-UA-Platform, etc.) is the supported replacement.

Bot user-agents — convention, not enforcement: Googlebot, Bingbot, GPTBot, ClaudeBot, and most commercial crawlers identify themselves honestly in the UA string because they need to be allowed past robots.txt and rate-limited fairly. Scrapers that don’t identify often spoof a browser UA — which is the reason rate-limiting and bot-detection cannot rely on UA strings alone. Modern bot management combines UA with TLS fingerprinting (JA3/JA4), HTTP/2 settings, mouse/keyboard signals, and headless-browser markers. A site choosing to allow only listed bots should match on multiple signals, not just the UA. Reference: RFC 9110 §10.1.5 — User-Agent.

Worked example

You want to detect “the user is on iOS Safari” for a Web Push compatibility check. Naive UA sniff: /iPhone|iPad|iPod/.test(ua) && /Safari/.test(ua) && !/CriOS|FxiOS/.test(ua). Except: iPadOS 13+ ships the “desktop” UA by default, so iPad is not in the string. Except: Chrome on iOS contains “CriOS” but is actually WebKit underneath (Apple platform policy), so the negation is wrong. Except: a privacy-extension user may spoof their UA to Firefox-on-Linux. Feature-detect instead: 'serviceWorker' in navigator && 'PushManager' in window && Notification.permission !== 'denied' — three line checks, works on every browser, doesn’t break when Apple ships iOS 18 next year. The UA-sniff version was already broken for ~6% of users by the time it shipped.

When and why it matters

UA-based logic is the single biggest source of “works in Chrome, broken in Safari” bugs that aren’t actually browser-engine bugs. Server-side, treat the UA as a coarse analytics signal only — never gate features, content, or security checks on it. Client-side, prefer feature detection (Modernizr or hand-rolled checks for the specific API you need). For bot mitigation, combine UA with TLS fingerprinting (akamai-bot-manager, Cloudflare bot fight mode), behavioural signals (mouse-movement entropy), and proof-of-work challenges (hCaptcha, Turnstile). The Client Hints story is improving — Sec-CH-UA-Platform is reliable, Sec-CH-UA-Mobile is reliable for mobile/desktop distinction, but anything more specific still requires user opt-in via Accept-CH. Reference: W3C WICG — User-Agent Client Hints.

Frequently asked questions

What is the User-Agent HTTP header?
The User-Agent header is sent by browsers and HTTP clients with every request to identify the software making the request -- typically including browser name, version, engine, and OS. Servers use it to tailor responses or analytics.
Why is the User-Agent string notoriously unreliable?
For backwards-compatibility, browsers historically claimed to be other browsers (Chrome says it is Mozilla/5.0; Safari; Chrome). This accumulated over decades as sites served content only to recognised strings. Modern User-Agent strings contain tokens for multiple browsers they are not, making parsing them for feature detection unreliable.
What is the difference between User-Agent and Client Hints?
User-Agent is a single header string sent automatically with every request, containing everything at once. Client Hints (Sec-CH-UA-*) is a newer API that allows servers to request only the specific device attributes they need, reducing fingerprinting surface and giving browsers more privacy control.

Related

Published May 15, 2026 · Last reviewed May 31, 2026