User-Agent Client Hints and On-Demand Metadata in Chromium

This article explores User-Agent Client Hints (UA-CH), a modern web standard designed to replace the traditional User-Agent string. It explains what these hints are, why they were introduced to improve user privacy, and the exact mechanisms the Chromium web browser uses to deliver specific device and browser metadata to servers and web applications strictly on an on-demand basis.

What Are User-Agent Client Hints?

User-Agent Client Hints (UA-CH) are a set of HTTP request headers and a JavaScript API that allow web browsers to share information about the user's device, operating system, and browser with a web server.

Historically, browsers sent a monolithic User-Agent (UA) string with every single HTTP request. This string broadcasted detailed system data—such as exact OS versions and phone models—to every website visited. While useful for tailoring content to specific devices, the legacy UA string created two major problems:

  1. Privacy Vulnerabilities: It enabled passive browser fingerprinting, allowing trackers to uniquely identify users across the web without their consent.
  2. Parsing Complexity: The string grew overly complex and spoofed over decades, causing frequent bugs when developers tried to parse it.

UA-CH solves these issues by replacing the complex UA string with structured, standardized data points that are largely withheld unless a server explicitly asks for them.

Default vs. On-Demand Data in Chromium

To balance functionality with privacy, Chromium divides User-Agent metadata into two categories: low-entropy (basic) and high-entropy (detailed) hints.

Low-Entropy Hints (Sent by Default) With every HTTP request, Chromium automatically sends three basic headers. These do not reveal enough information to fingerprint a user, but they give servers enough context for basic content negotiation:

  • Sec-CH-UA: The browser brand and its major version number.
  • Sec-CH-UA-Mobile: A boolean (?1 or ?0) indicating if the browser is on a mobile device.
  • Sec-CH-UA-Platform: The broad operating system (e.g., "Windows", "macOS", "Android").

High-Entropy Hints (Delivered On Demand) Detailed information that could be used to identify an individual user is classified as high-entropy. Chromium withholds this data by default. Examples include:

  • Sec-CH-UA-Platform-Version: The exact OS version.
  • Sec-CH-UA-Model: The specific hardware model (e.g., "Pixel 7").
  • Sec-CH-UA-Arch: The underlying CPU architecture (e.g., "x86" or "arm").
  • Sec-CH-UA-Full-Version-List: The full version numbers of the browser rather than just the major version.

How Chromium Delivers Metadata On Demand

Chromium provides two methods for websites to request high-entropy device metadata on demand: via HTTP headers for server-side adaptation, and via a JavaScript API for client-side logic.

1. The HTTP Header Mechanism

For a server to receive high-entropy hints, a negotiation must take place between the server and the Chromium browser:

  • Step 1 (The Opt-In): When a user visits a website, the server responds to the initial request with an Accept-CH header. This header contains a comma-separated list of the exact metadata the server wants. For example: Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Platform-Version.
  • Step 2 (The Delivery): Chromium reads the Accept-CH header and remembers this preference for the duration of the session. On all subsequent requests to that specific website, Chromium attaches the requested Sec-CH-UA-Model and Sec-CH-UA-Platform-Version headers.

If a server requires this data on the very first page load to render the page correctly, it can also send a Critical-CH header. This instructs Chromium to immediately retry the initial request with the newly requested hints attached.

2. The JavaScript API Mechanism

Web applications often need device metadata dynamically via scripts rather than during the initial server request. Chromium facilitates this through the navigator.userAgentData API.

  • Accessing Default Data: Scripts can read low-entropy data synchronously by calling properties like navigator.userAgentData.mobile or navigator.userAgentData.platform.
  • Requesting On-Demand Data: To get high-entropy data, the script must call the navigator.userAgentData.getHighEntropyValues() method and pass an array of the specific hints it needs (e.g., ['model', 'architecture', 'bitness']).

Because this method is asynchronous and returns a JavaScript Promise, it gives Chromium a control point. Before resolving the Promise and handing over the sensitive metadata, Chromium can audit the request, log it for security purposes, or apply user-defined privacy blocks.