Web Development

How do I handle User-Agent Client Hints in modern browsers?

Master User-Agent Client Hints, understand the privacy benefits and implementation requirements, and prepare for the future of browser identification.

By Inventive HQ Team

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 Accept-CH opt-in handshake A server sends an Accept-CH header requesting specific Client Hints, and the browser responds on the next request with the matching Sec-CH-UA headers. Browser Chromium client navigator.userAgentData Server sets Accept-CH reads Sec-CH-* 1. Accept-CH: Sec-CH-UA-Platform, -Arch, -Model 2. Sec-CH-UA-Platform: "Windows" · -Arch: "x86" · -Model: ""

The Accept-CH opt-in handshake Low-entropy hints ship by default; high-entropy hints wait for this request. The browser caches the Accept-CH request per origin, so hints arrive on every following request.

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:

  1. Privacy: It reveals detailed information about every user's system to every server they visit
  2. Unreliability: Browsers lie about their identity for compatibility (notice Chrome claiming to be Safari)
  3. Inefficiency: All this information is sent with every request, even when the server doesn't need it
  4. 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 headerWhat it exposesExample valueEntropy / opt-in
Sec-CH-UABrowser 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-MobileMobile device boolean (?1 true, ?0 false)?0Low — sent by default
Sec-CH-UA-PlatformOperating system name"Windows"Low — sent by default
Sec-CH-UA-Platform-VersionOS version string"14.0.0"High — needs Accept-CH
Sec-CH-UA-ArchCPU architecture"x86", "arm"High — needs Accept-CH
Sec-CH-UA-BitnessCPU bitness"64"High — needs Accept-CH
Sec-CH-UA-ModelDevice model (mostly mobile)"Pixel 8"High — needs Accept-CH
Sec-CH-UA-Full-Version-ListFull version numbers for every brand"Chromium";v="120.0.6099.109", …High — needs Accept-CH
Sec-CH-UA-WoW64Whether a 32-bit binary runs on 64-bit Windows?0High — needs Accept-CH
Sec-CH-UA-Form-FactorsReported 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.

Advertisement

Server-Side Implementation

Implementing User-Agent Client Hints on the server requires:

  1. Sending Accept-CH header: Declare which hints you want
  2. Parsing the response headers: Extract the information from the returned hints
  3. 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.

Loading interactive tool...

Privacy Benefits

User-Agent Client Hints provide several privacy improvements:

  1. User control: Users can configure which hints are sent and to which sites
  2. Explicit requests: Servers must explicitly declare which hints they need
  3. Limited sharing: Not all hints are sent with every request
  4. 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:

  1. Phase 1: Implement Client Hints alongside existing User-Agent parsing
  2. Phase 2: Update feature detection code to prefer Client Hints
  3. Phase 3: Log which browsers still don't support Client Hints
  4. 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-UA headers and navigator.userAgentData.
  • Firefox (Gecko): No support. Firefox does not send Sec-CH-UA headers or implement navigator.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

  1. Be explicit about what you need: Only request hints you actually use
  2. Respect user privacy: Avoid requesting high-entropy hints unless necessary
  3. Provide fallbacks: Always handle cases where hints aren't available
  4. Validate hint values: Client Hints can be spoofed; don't make critical security decisions based solely on them
  5. 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.

Frequently Asked Questions

What are User-Agent Client Hints?

User-Agent Client Hints (UA-CH) are a set of HTTP request headers and a JavaScript API (navigator.userAgentData) that let a browser report specific facts about itself — brand, version, platform, mobile flag, architecture — only when a server explicitly asks. They are Chromium's replacement for the frozen, monolithic User-Agent string, designed to reduce passive fingerprinting by sending detailed data on request instead of on every request.

How do I enable User-Agent Client Hints on my server?

Send an Accept-CH response header listing the hints you want, for example "Accept-CH: Sec-CH-UA-Platform, Sec-CH-UA-Arch, Sec-CH-UA-Model". The browser stores that request for the origin and includes those headers on subsequent requests. Low-entropy hints (Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform) are sent by default and need no opt-in.

What is the difference between low-entropy and high-entropy Client Hints?

Low-entropy hints (Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform) reveal little identifying detail and are sent automatically. High-entropy hints (architecture, bitness, full version list, device model, platform version) are more identifying, so they are only sent after a server opts in via Accept-CH, or when JavaScript calls getHighEntropyValues().

Are Client Hints available in Safari and Firefox?

No, not meaningfully. As of 2026 UA-CH is a Chromium feature — Chrome, Edge, Opera and other Chromium browsers support it fully. Safari (WebKit) and Firefox (Gecko) do not send Sec-CH-UA headers or implement navigator.userAgentData, so you must keep a User-Agent string fallback for those engines.

Do Client Hints replace the User-Agent string?

Not yet. Chromium has "reduced" (frozen) the User-Agent string so it no longer exposes fine-grained version and platform detail, but the string still ships with every request for backward compatibility. Client Hints are the forward-looking source of detail; the string remains as a legacy fallback.

Can User-Agent Client Hints be spoofed?

Yes. Like the User-Agent string, Client Hints are client-supplied and can be altered by extensions, dev tools, headless automation, or a modified browser. Use them for feature detection and analytics, never as the sole basis for a security or authentication decision.

How do I send Client Hints to a third-party domain?

Hints are sent only to the origin that requested them. To share them with a third party (analytics, ads, a CDN), delegate with a Permissions-Policy header that names the allowed origin for each hint, such as ch-ua-platform and ch-ua-model. Without that delegation, cross-origin requests receive only the low-entropy defaults.

Why does Sec-CH-UA include a fake brand like 'Not A Brand'?

The Sec-CH-UA header deliberately includes a randomized "GREASE" brand (such as ";Not A Brand";v="99") alongside real brands. This forces servers to parse the list generically rather than hardcoding brand names, preventing the ecosystem ossification that made the old User-Agent string impossible to change.

user agent client hintsprivacybrowser compatibilityHTTP headersweb standards
Advertisement