Understanding the User-Agent Client Hints Revolution
User-Agent Client Hints (UA-CH) are the Chromium standard that replaces the frozen User-Agent string: instead of broadcasting your full browser, OS, and version details on every request, the browser sends only three low-entropy headers by default (Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform) and reveals higher-entropy details — architecture, device model, full version — only when a server opts in with an Accept-CH response header. In practice you handle them by sending Accept-CH from your server for the hints you need, reading the returned Sec-CH-* request headers, and keeping a User-Agent string fallback for Safari and Firefox, which do not implement UA-CH.
That is the summary an AI Overview gives you. What it can't give you is the request/response handshake that makes the opt-in work, a header-by-header map of exactly what each hint exposes, or the delegation rule that decides whether your analytics vendor sees anything at all. Those are below — along with a live parser you can paste headers into.
The web standards community has recognized that the traditional User-Agent string is problematic from both privacy and technical perspectives. The User-Agent is sent with every HTTP request, contains detailed information about the user's browser and operating system, and is often unreliable due to browser spoofing for compatibility reasons. To address these issues, User-Agent Client Hints were developed and are now the default in Chromium-based browsers.
User-Agent Client Hints represent a fundamental shift in how browsers communicate their capabilities and characteristics to servers. Rather than sending a single, complex, often-unreliable User-Agent string with every request, Client Hints provide a mechanism for servers to explicitly request specific information about the client, which browsers then provide transparently.
This approach offers significant benefits: it gives users more control over what information is shared, it makes server code more predictable and reliable, and it aligns with privacy-first principles that are becoming increasingly important in web development.
The Traditional Problem with User-Agent Strings
Before understanding the solution, it's important to understand the problem. The traditional User-Agent string looks something like:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
This string contains:
- Rendering engine information (WebKit)
- Browser name and version (Chrome 120)
- Operating system (Windows 10, 64-bit)
- Other identifiers and vendor information
The problems with this approach:
- Privacy: It reveals detailed information about every user's system to every server they visit
- Unreliability: Browsers lie about their identity for compatibility (notice Chrome claiming to be Safari)
- Inefficiency: All this information is sent with every request, even when the server doesn't need it
- Maintenance burden: Parsing these strings is error-prone and requires constant updates as new browser versions are released
User-Agent Client Hints address all these issues by making the process explicit and requesting only what's needed.
How User-Agent Client Hints Work
Client Hints work through HTTP headers. A server can indicate which Client Hints it wants by sending an Accept-CH header:
Accept-CH: sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform
The browser then responds with the requested information in subsequent requests:
sec-ch-ua: "Google Chrome";v="120", "Chromium";v="120", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
This approach is much more explicit and transparent than the old system.
Available Client Hints: what each header exposes
Several Client Hints are available, each providing specific information. The critical split is entropy: low-entropy hints ship automatically because they reveal little, while high-entropy hints wait for your Accept-CH opt-in (or a getHighEntropyValues() call in JavaScript) because they narrow down an individual user.
| Client Hint header | What it exposes | Example value | Entropy / opt-in |
|---|---|---|---|
Sec-CH-UA | Browser brand(s) + major version, with a GREASE decoy brand | "Chromium";v="120", "Google Chrome";v="120", ";Not A Brand";v="99" | Low — sent by default |
Sec-CH-UA-Mobile | Mobile device boolean (?1 true, ?0 false) | ?0 | Low — sent by default |
Sec-CH-UA-Platform | Operating system name | "Windows" | Low — sent by default |
Sec-CH-UA-Platform-Version | OS version string | "14.0.0" | High — needs Accept-CH |
Sec-CH-UA-Arch | CPU architecture | "x86", "arm" | High — needs Accept-CH |
Sec-CH-UA-Bitness | CPU bitness | "64" | High — needs Accept-CH |
Sec-CH-UA-Model | Device model (mostly mobile) | "Pixel 8" | High — needs Accept-CH |
Sec-CH-UA-Full-Version-List | Full version numbers for every brand | "Chromium";v="120.0.6099.109", … | High — needs Accept-CH |
Sec-CH-UA-WoW64 | Whether a 32-bit binary runs on 64-bit Windows | ?0 | High — needs Accept-CH |
Sec-CH-UA-Form-Factors | Reported form factors | "Desktop", "Tablet" | High — needs Accept-CH |
Each request header maps to a field in the navigator.userAgentData JavaScript API — low-entropy hints appear on brands, mobile, and platform directly, while every high-entropy header is retrieved through getHighEntropyValues(). Different browsers support different subsets, and the available hints are still evolving as the standard develops.
Server-Side Implementation
Implementing User-Agent Client Hints on the server requires:
- Sending Accept-CH header: Declare which hints you want
- Parsing the response headers: Extract the information from the returned hints
- Graceful fallback: Handle cases where hints aren't available
Here's a JavaScript/Node.js example:
app.use((req, res, next) => {
// Declare which hints we want
res.set('Accept-CH', 'sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform');
// Parse the hints from the request
const hints = {
ua: req.get('sec-ch-ua'),
isMobile: req.get('sec-ch-ua-mobile') === '?1',
platform: req.get('sec-ch-ua-platform'),
arch: req.get('sec-ch-ua-arch'),
};
// Use the hints for responsive serving
res.locals.isSmallScreen = hints.isMobile;
next();
});
PHP example:
header('Accept-CH: sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform');
$hints = [
'ua' => $_SERVER['HTTP_SEC_CH_UA'] ?? null,
'isMobile' => ($_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '') === '?1',
'platform' => $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? null,
];
// Use the hints for server-side logic
Client-Side JavaScript Access
Modern browsers also allow JavaScript to access Client Hints through the User-Agent data API:
async function getClientHints() {
if (!navigator.userAgentData) {
// Fallback for browsers that don't support User-Agent Client Hints
return null;
}
// Basic information is always available
const mobile = navigator.userAgentData.mobile;
const platform = navigator.userAgentData.platform;
const brands = navigator.userAgentData.brands;
// Request additional information
const fullData = await navigator.userAgentData.getHighEntropyValues([
'architecture',
'bitness',
'model',
'fullVersionList'
]);
return {
mobile,
platform,
brands,
...fullData
};
}
getClientHints().then(hints => {
if (hints) {
console.log('Device is mobile:', hints.mobile);
console.log('Platform:', hints.platform);
}
});
Note the distinction between "low entropy" values (always available without requesting, like mobile and platform) and "high entropy" values (require explicit request, like architecture and model). This design encourages privacy by making it clear when detailed information is being requested.
Want to see how the old string still decomposes next to these hints? Paste any User-Agent value below to break it into brand, engine, OS, and device — useful for building the fallback path that Safari and Firefox still need.
Privacy Benefits
User-Agent Client Hints provide several privacy improvements:
- User control: Users can configure which hints are sent and to which sites
- Explicit requests: Servers must explicitly declare which hints they need
- Limited sharing: Not all hints are sent with every request
- Fingerprinting resistance: The information provided is standardized, making it harder to fingerprint individual users
Browsers can also implement privacy features like reducing precision in some hints or adding noise to make fingerprinting less reliable.
Handling Missing Hint Support
Not all browsers support User-Agent Client Hints yet. Your code needs to gracefully handle cases where hints aren't available:
function getDeviceType() {
// Try Client Hints first
if (navigator.userAgentData && !navigator.userAgentData.mobile) {
return 'desktop';
}
// Fallback: use User-Agent string for older browsers
if (navigator.userAgent.match(/mobile/i)) {
return 'mobile';
}
// Or use other detection methods
return detectDeviceType();
}
This ensures your application works in both modern browsers with Client Hints support and older browsers that only have traditional User-Agent strings.
Sending Hints to Third-Party Services
A key consideration is how Client Hints interact with third-party resources. By default, hints are sent only to the origin that requested them. A cross-origin request — your analytics pixel, an ad tag, an image CDN on another domain — receives just the low-entropy defaults and none of the high-entropy hints, even if your own pages opted into them.
To share hints across origins you must delegate them, and delegation is controlled by the Permissions-Policy header (not by attributes on the <img> tag). List the third-party origins that are allowed to receive each hint:
Permissions-Policy: ch-ua-platform=(self "https://analytics.example.com"),
ch-ua-model=(self "https://analytics.example.com")
Only origins named in that policy will receive Sec-CH-UA-Platform and Sec-CH-UA-Model on subresource requests. This keeps delegation explicit: high-entropy data does not silently leak to every third party your page loads.
Migration Strategy from User-Agent Parsing
If you're currently using User-Agent parsing, here's a migration strategy:
- Phase 1: Implement Client Hints alongside existing User-Agent parsing
- Phase 2: Update feature detection code to prefer Client Hints
- Phase 3: Log which browsers still don't support Client Hints
- Phase 4: Gradually deprecate User-Agent parsing as browser support improves
function getBrowserInfo() {
// Prefer Client Hints
if (navigator.userAgentData) {
return {
isMobile: navigator.userAgentData.mobile,
platform: navigator.userAgentData.platform,
source: 'client-hints'
};
}
// Fallback to User-Agent parsing
return {
isMobile: navigator.userAgent.match(/mobile/i),
platform: getPlatformFromUA(navigator.userAgent),
source: 'user-agent'
};
}
Browser Support and Timeline
Current support for User-Agent Client Hints:
- Chromium-based browsers (Chrome, Edge, Opera, Brave, Samsung Internet): Full support for the
Sec-CH-UAheaders andnavigator.userAgentData. - Firefox (Gecko): No support. Firefox does not send
Sec-CH-UAheaders or implementnavigator.userAgentData, and has expressed reservations about the design. - Safari (WebKit): No support. Safari does not send Client Hints or expose
navigator.userAgentData.
Because UA-CH is effectively a Chromium-only feature today, roughly a third of real-world traffic — every Safari and Firefox user — will never send a Sec-CH-UA header. A User-Agent string fallback is not optional; it is the code path those browsers always take. Chromium has "reduced" (frozen) its User-Agent string so it no longer leaks fine-grained version and platform detail, but the string itself still ships with every request for backward compatibility, so there is no hard deprecation date to design around yet.
Common Use Cases
Responsive Design Decision Making: Use sec-ch-ua-mobile to determine whether to serve mobile or desktop layouts
Device-Specific Optimization: Use architecture and bitness hints to optimize binary downloads
Analytics: Replace User-Agent parsing with Client Hints for more reliable device detection
Security Decisions: Use hints to inform security policies (for example, requiring stronger authentication on mobile devices)
Best Practices
- Be explicit about what you need: Only request hints you actually use
- Respect user privacy: Avoid requesting high-entropy hints unless necessary
- Provide fallbacks: Always handle cases where hints aren't available
- Validate hint values: Client Hints can be spoofed; don't make critical security decisions based solely on them
- Monitor browser support: Track which hints different browsers support and plan accordingly
Conclusion
User-Agent Client Hints represent the future of how browsers communicate their capabilities to servers. By providing explicit, transparent, and privacy-conscious information sharing, they address the fundamental problems with the traditional User-Agent string. While browser support is still evolving, implementing support for Client Hints now—while maintaining fallbacks to User-Agent parsing—ensures your application works across current and future browsers. As the web community moves away from User-Agent string parsing, understanding and implementing Client Hints is becoming essential for modern web development.