ESC

Type to search the knowledge base.

User Agent Client Hints

Replace UA string parsing with Client Hints: Sec-CH-UA headers, critical hints, and privacy-aware adaptation.

advanced3 min read
  • 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.

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