Improving user privacy and developer experience with User-Agent Client Hints

User-Agent Client Hints are a new expansion to the Client Hints API, that enables developers to access information about a user's browser in a privacy-preserving and ergonomic way.

Client Hints enable developers to actively request information about the user's device or conditions, rather than needing to parse it out of the User-Agent (UA) string. Providing this alternative route is the first step to eventually reducing User-Agent string granularity.

Learn how to update your existing functionality that relies on parsing the User-Agent string to make use of User-Agent Client Hints instead.

Background

When web browsers make requests they include information about the browser and its environment so that servers can enable analytics and customize the response. This was defined all the way back in 1996 (RFC 1945 for HTTP/1.0), where you can find the original definition for the User-Agent string, which includes an example:

User-Agent: CERN-LineMode/2.15 libwww/2.17b3

This header was intended to specify, in order of significance, the product (e.g. browser or library) and a comment (e.g. version).

The state of the User-Agent string

Over the intervening decades, this string has accrued a variety of additional details about the client making the request (as well as cruft, due to backwards compatibility). We can see that when looking at Chrome's current User-Agent string:

Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4076.0 Mobile Safari/537.36

The above string contains information about the user's operating system and version, the device model, the browser's brand and full version, enough clues to infer it's a mobile browser, and not to mention a number of references to other browsers for historical reasons.

The combination of these parameters with the sheer diversity of possible values means the User-Agent string could contain enough information to allow individual users to be uniquely identified.

The User-Agent string enables many legitimate use cases, and serves an important purpose for developers and site owners. However, it is also critical that users' privacy is protected against covert tracking methods, and sending UA information by default goes against that goal.

There's also a need to improve web compatibility when it comes to the User-Agent string. It is unstructured, so parsing it results in unnecessary complexity, which is often the cause for bugs and site compatibility issues that hurt users. These issues also disproportionately hurt users of less common browsers, as sites may have failed to test against their configuration.

Introducing the new User-Agent Client Hints

User-Agent Client Hints enable access to the same information but in a more privacy-preserving way, in turn enabling browsers to eventually reduce the User-Agent string's default of broadcasting everything. Client Hints enforce a model where the server must ask the browser for a set of data about the client (the hints) and the browser applies its own policies or user configuration to determine what data is returned. This means that rather than exposing all the User-Agent information by default, access is now managed in an explicit and auditable fashion. Developers also benefit from a simpler API - no more regular expressions!

The current set of Client Hints primarily describes the browser's display and connection capabilities. You can explore the details in Automating Resource Selection with Client Hints, but here's a quick refresher on the process.

The server asks for specific Client Hints via a header:

⬇️ Response from server

Accept-CH: Viewport-Width, Width

Or a meta tag:

<meta http-equiv="Accept-CH" content="Viewport-Width, Width" />

The browser can then choose to send the following headers back in subsequent requests:

⬆️ Subsequent request

Viewport-Width: 460
Width: 230

The server can choose to vary its responses, for example by serving images at an appropriate resolution.

User-Agent Client Hints expand the range of properties with the Sec-CH-UA prefix that can be specified via the Accept-CH server response header. For all the details, start with the explainer and then dive into the full proposal.

User-Agent Client Hints from Chromium 89

User-Agent Client Hints have been default enabled in Chrome since version 89.

By default, the browser returns the browser brand, significant / major version, platform, and an indicator if the client is a mobile device:

⬆️ All requests

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?0
Sec-CH-UA-Platform: "macOS"

User-Agent response and request headers

⬇️ Response Accept-CH
⬆️ Request header
⬆️ Request
Example value
Description
Sec-CH-UA "Chromium";v="84",
"Google Chrome";v="84"
List of browser brands and their significant version.
Sec-CH-UA-Mobile ?1 Boolean indicating if the browser is on a mobile device (?1 for true) or not (?0 for false).
Sec-CH-UA-Full-Version "84.0.4143.2" [Deprecated]The complete version for the browser.
Sec-CH-UA-Full-Version-List "Chromium";v="84.0.4143.2",
"Google Chrome";v="84.0.4143.2"
List of browser brands and their full version.
Sec-CH-UA-Platform "Android" The platform for the device, usually the operating system (OS).
Sec-CH-UA-Platform-Version "10" The version for the platform or OS.
Sec-CH-UA-Arch "arm" The underlying architecture for the device. While this may not be relevant to displaying the page, the site may want to offer a download which defaults to the right format.
Sec-CH-UA-Model "Pixel 3" The device model.
Sec-CH-UA-Bitness "64" The underlying architecture's bitness (i.e., the size in bits of an integer or memory address)

Example exchange

An example exchange would look like this:

⬆️ Initial request from browser
The browser is requesting the /downloads page from the site and sends its default basic User-Agent.

GET /downloads HTTP/1.1
Host: example.site

Sec-CH-UA: "Chromium";v="93", "Google Chrome";v="93", " Not;A Brand";v="99"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Platform: "Android"

⬇️ Response from server
The server sends the page back and additionally asks for the full browser version and the platform.

HTTP/1.1 200 OK
Accept-CH: Sec-CH-UA-Full-Version-List

⬆️ Subsequent requests
The browser grants the server access to the additional information and sends the extra hints back in all subsequent requests.

GET /downloads/app1 HTTP/1.1
Host: example.site

Sec-CH-UA: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-CH-UA-Mobile: ?1
Sec-CH-UA-Full-Version-List: " Not A;Brand";v="99.0.0.0", "Chromium";v="98.0.4738.0", "Google Chrome";v="98.0.4738.0"
Sec-CH-UA-Platform: "Android"

JavaScript API

Alongside the headers, the User-Agent can also be accessed in JavaScript via navigator.userAgentData. The default Sec-CH-UA, Sec-CH-UA-Mobile, and Sec-CH-UA-Platform header information can be accessed via the brands and mobile properties, respectively:

// Log the brand data
console.log(navigator.userAgentData.brands);

// output
[
  {
    brand: 'Chromium',
    version: '93',
  },
  {
    brand: 'Google Chrome',
    version: '93',
  },
  {
    brand: ' Not;A Brand',
    version: '99',
  },
];

// Log the mobile indicator
console.log(navigator.userAgentData.mobile);

// output
false;

// Log the platform value
console.log(navigator.userAgentData.platform);

// output
"macOS";

The additional values are accessed via the getHighEntropyValues() call. The "high entropy" term is a reference to information entropy, in other words - the amount of information that these values reveal about the user's browser. As with requesting the additional headers, it's down to the browser what values, if any, are returned.

// Log the full user-agent data
navigator
  .userAgentData.getHighEntropyValues