User Agent Client Hints
Replace UA string parsing with Client Hints: Sec-CH-UA headers, critical hints, and privacy-aware adaptation.
- browser
- client-hints
- user-agent
- http
- privacy
The classic User-Agent string is a frozen, spoofed, privacy-hostile mess. User-Agent Client Hints (UA-CH) expose brand, model, and platform via structured HTTP headers and navigator.userAgentData, behind explicit opt-in — so you stop regexing "Android" out of a novel.
Docs: MDN User-Agent Client Hints, web.dev UA-CH, GREASE brands.
Low-entropy vs high-entropy
Browsers send a minimum set by default (e.g. brand list, mobile bit). Details like full version, model, platform version need:
Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Full-Version-List
Or request via JS:
const ua = navigator.userAgentData;
console.log(ua.mobile, ua.platform, ua.brands);
const high = await ua.getHighEntropyValues([
'model',
'platformVersion',
'fullVersionList',
]);
console.log(high.model, high.platformVersion);
High-entropy values may prompt privacy restrictions; don’t demand them on every page view.
Headers you’ll see
Sec-CH-UA: "Chromium";v="128", "Not=A?Brand";v="24", "Google Chrome";v="128"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"
GREASE brands intentionally insert nonsense tokens so parsers don’t hardcode brittle lists.
Critical-CH
Critical-CH: Sec-CH-UA-Platform
Accept-CH: Sec-CH-UA-Platform
Tells the browser the response depends on that hint; may trigger a restart of the request with hints — use sparingly (extra latency). Prefer progressive enhancement without critical dependency.
Migration from UA sniffing
| Old | New |
|---|---|
| Regex Android | Sec-CH-UA-Mobile / platform |
| Full browser version for bugs | fullVersionList only when needed |
| Assume desktop width from UA | CSS media / container queries |
| OS-specific downloads | platform hint on download page only |
Prefer feature detection over any UA approach. Hints are for content negotiation (correct binary, analytics breakdowns), not capability checks.
Privacy and policy
Collect only what product needs. Client Hints are still fingerprinting surface — document retention, avoid shipping model+version to third parties without review. See Privacy and fingerprinting.
Safari / support
UA-CH is Chromium-led; other engines differ. Always keep a fallback path (userAgent string or neutral default).
Interview out-loud
“UA Client Hints replace brittle UA-string parsing with structured Sec-CH-UA headers and userAgentData. Low-entropy hints come by default; high-entropy need Accept-CH or getHighEntropyValues. Prefer feature detection; request only needed hints.”
Analytics migration
Map old UA-parser fields to Client Hints gradually. Keep dual collection until dashboards match. Stop storing raw full version lists longer than needed — they are fingerprint material under privacy reviews.
Downgrade path
If Client Hints are missing (unsupported browser, privacy reduction), serve a neutral default: responsive CSS first, no OS-specific binary until the user picks one. Never block rendering on getHighEntropyValues. Treat hints as progressive enhancement for analytics and download buttons only.
Related
- Privacy and fingerprinting basics
- Browser networking 101
- Responsive images performance
- Permissions policy
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Browser Networking 101DNS, TCP/TLS, HTTP/1.1 vs H2/H3, connection reuse, and what frontend code can actually influence.
- Content-Type and MIME SniffingWhy Content-Type matters, how MIME sniffing works, X-Content-Type-Options: nosniff, and XSS-ish pitfalls.
- CORS Explained for FrontendWhy the browser blocks cross-origin responses, what Access-Control-* headers mean, preflight, credentials, and how to fix real frontend errors.
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.