Sign up below to view device data and get your trial account.

We communicate via email to process your request in line with our privacy policy. Please check the box to give us your permission to do this.

Cancel

User-Agent Client-Hints Implementation Guide

This page summarises some considerations for developers preparing for the rollout of Google's User-Agent Client-Hints (UA-CH) proposal. We recently recorded a webinar on this topic: User Agent strings and User Agent Client Hints - navigating the new landscape.

The first request issue

High entropy UA-CH headers are sent by browsers only on request by the server. This means that servers receive the full set of requested headers only in the second request from a newly-seen browser.

If a web application needs full device information in order to build a meaningful response to a browser it is recommended to force a retry of the first request in the case where a request from a browser supporting UA-CH does not have the required hints present. Subsequent requests and future visits should contain any requested UA-CH headers, as long as the user or browser has not deliberately limited this.

Google have proposed a mechanism to work around the first request issue called Critical CH, discussed below.

Critical-CH

The Critical-CH response header from a server requests that, if a particular Client Hint header was not received but could have been sent according to the browser's policies, a new request should automatically be made that includes the requested Client Hints header. This proposal makes handling the first-request problem slightly easier since the client will know to try the request again without an explicit redirect request from the server.

The details of this proposal are documented in the Client Hint Reliability RFC.

Critical-CH is currently supported in Chrome and Chrome Mobile. The only other browser to support UA-CH, Microsoft Edge, does not currently support this.

Quoted header values

UA-CH headers follow RFC8941, a standard for structured field values for HTTP. This means that header values are wrapped in double quotes, unlike the more traditional HTTP headers such as User-Agent. Thus, the Sec-CH-UA-Model header value for a Google Pixel 6 is "Pixel 6", not Pixel 6. The same applies to all other new headers mentioned in the UA-CH proposal. DeviceAtlas requires the header value as received in order to work correctly.

Web server configuration

By design, browsers default to not sending the high-entropy UA-CH headers that DeviceAtlas needs to recognise devices fully—this is the whole point of the UA-CH proposal. These headers carry information about the device model, architecture, "bitness" and the full version of the user agent and underlying platform. Web servers need to be configured to request the additional UA-CH headers from browsers in their responses to requests. Then the next request from the browser should send the required headers (unless configured not to).

DeviceAtlas recommends requesting the full set of UA-CH headers to ensure all information is available to DeviceAtlas should it be needed. Thus we recommend that web servers are configured to request the following headers via the Accept-CH response header:

  • Sec-CH-Save-Data
  • Sec-CH-DPR
  • Sec-CH-Width
  • Sec-CH-Viewport-Width
  • Sec-CH-Viewport-Height
  • Sec-CH-Device-Memory
  • Sec-CH-RTT
  • Sec-CH-Downlink
  • Sec-CH-ECT
  • Sec-CH-Prefers-Color-Scheme
  • Sec-CH-UA-Arch
  • Sec-CH-UA-Bitness
  • Sec-CH-UA-Full-Version-List
  • Sec-CH-UA-Model
  • Sec-CH-UA-Platform-Version

The following headers need not be requested since they should be sent by default by browsers:

  • Sec-CH-UA
  • Sec-CH-UA-Mobile
  • Sec-CH-UA-Platform

The actual configuration required for each web server or application varies but, as an example, the following configuration works for the NGINX web server:

server {
    …
    add_header Accept-CH Sec-CH-Save-Data, Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height,
        Sec-CH-Device-Memory, Sec-CH-RTT, Sec-CH-Downlink, Sec-CH-ECT, Sec-CH-Prefers-Color-Scheme, Sec-CH-UA-Arch,
        Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version;
    …
}

In Apache the equivalent looks something like this:

<Location "/">
    …
    Header set Accept-CH "Sec-CH-Save-Data, Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width, Sec-CH-Viewport-Height, \
        Sec-CH-Device-Memory, Sec-CH-RTT, Sec-CH-Downlink, Sec-CH-ECT, Sec-CH-Prefers-Color-Scheme, Sec-CH-UA-Arch, \
        Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version"
    …
</Location>

For quick testing a meta header can be added to pages in place of adding a HTTP response header:

<head>
    …
    <meta http-equiv="Accept-CH" content="Sec-CH-Save-Data, Sec-CH-DPR, Sec-CH-Width, Sec-CH-Viewport-Width,
        Sec-CH-Viewport-Height, Sec-CH-Device-Memory, Sec-CH-RTT, Sec-CH-Downlink, Sec-CH-ECT, Sec-CH-Prefers-Color-Scheme, 
        Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version">
    …
</head>

Cross-origin requests and iFrames

The UA-CH proposal requires that pages explicitly grant permission for cross-origin requests and iframes to obtain UA-CH headers from the browser. This mechanism to do this is part of the broader Permissions Policy standard in development by the W3C. This permission can be granted via response headers sent by the origin server or <meta> tags in the origin page HTML.

permissions-policy: ch-ua-platform-version=(self "example.com"), sec-ch-ua-model=(self "example.com" "anotherexample.com");
<meta name="accept-ch" content="sec-ch-ua-model=( https://example.com )">

It is not possible to delegate to all third-party domains via * in the meta tag.

De-duplicating server requests

If the Critical-CH is utilised as decribed above, Chrome will automatically retry requests if doing so would provide the server with the critical hints it has requested. Depending on the application, server-side logic may be required to ensure that requests are appropriately treated at the server. As an example, for web analytics purposes or non-idempotent requests it may be necessary to ignore the initial request and act only on the second one.

Note that in the case of a Critical-CH induced retry, the Network panel of the Chrome inspector currently does not show the second request request taking place—you will only see evidence of this in your server logs. We have mentioned this to Google. The Chromium team have logged bug 1176879 to track it.

UA-CH preference lifetime

The lifetime of client hint preferences is the "browser session", which is generally fairly long-lived. The current implementation in Chrome clears the preferences on browser restart and if origin-specific information is cleared (e.g. cookies, storage, cache). Opening a new incognito window in Chrome does not clear these preferences.

Configuring Chrome to behave like it's 2023

If you wish to test Chrome as it will behave once the UA-CH functionality has been fully rolled out you can do so today via an experimental setting in Chrome or Chrome Mobile. The setting is available here: chrome://flags/#freeze-user-agent. Changing this flag from Default to Enabled will change the user-agent string to the final format.

Note: at the time of writing setting the freeze-user-agent flag produces an intermediate format frozen UA, not quite inline with the specification:

Desktop

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.0.0 Safari/537.36

Mobile

Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.0.0 Mobile Safari/537.36

Microsoft Edge

Microsoft has supported UA-CH in Edge since version 90 and have stated that UA-CH is their preferred way to detect Edge. Microsoft have not yet settled on the final reduced format of the Edge user-agent string.

Frozen/reduced User-Agent Strings

At the time of writing only Chrome has published their final frozen/reduced user-agent strings. The general format is as follows:

Mozilla/5.0 (<unifiedPlatform>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<majorVersion>.0.0.0 <deviceCompat> Safari/537.36

Where:

  • <deviceCompat> = "Mobile" or ""
  • <majorVersion> = Chrome major version
  • <unifiedPlatform> = a combination of platform, OS/CPU, Android Version, and deviceModel. It has two sets of possible values:
    • Desktop
      • Windows NT 10.0; Win64; x64
      • Macintosh; Intel Mac OS X 10_15_7
      • X11; Linux x86_64
      • X11; CrOS x86_64
    • Mobile
      • Linux; Android 10; K

Some examples of this follow.

MacOS desktop, before and after:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36

Android phone (Huawei P30 Pro), before and after:

Mozilla/5.0 (Linux; Android 11; VOG-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36

Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Mobile Safari/537.36

FAQ

What about the Android WebView? Will it follow the path of Chome?

In a Chromium Blog blog post published on May 19th 2021 it was stated that "We have no plans to change the User-Agent string on Android WebView or Chrome for iOS at this time, but will make public updates if and when that changes."

For how long will browsers retain UA-CH preferences for an origin?

This is an issue with the HTTP Client Hints more than this definition of particular hints; this is defined in RFC 8942. The relevant section of the spec says

"[the opt in] SHOULD be persisted and bound to the origin to enable delivery of Client Hints on subsequent requests to the server's origin, for the duration of the user's session (as defined by the user agent)."

The current implementation in Chrome clears the preferences on browser restart and if origin-specific information is cleared (e.g. cookies, storage, cache).

Is there any loss of functionality in DeviceAtlas resulting from the move to UA-CH?

DeviceAtlas's accuracy will be not be impacted except for a handful of phone models which share identical model names e.g. "M1" or "X1". In the current UA-CH proposal there is no way to distinguish between identical model names from different manufacturers since the Sec-CH-UA-Model client hint specification does not include manufacturer.

How can I leave feedback for the WICG and the W3C?

DeviceAtlas recommends that any feedback for the WICG on the UA-CH proposal should be left on the GitHub issues page. Customers can also provide feedback to the W3C's Technical Architecture Group review of the proposal.

Are other browsers likely to support UA-CH?

It's unclear at this point. Apart from Chrome, of the major browsers only Edge supports the UA-CH, and only on the desktop version right now. Mozilla has declared UA-CH as harmful. This probably means that more general support for UA-CH will be slow to arrive, if it arrives at all.

References

The phases of the Chrome user-agent string reduction are as follows:

Reduction phase   Chrome version   Date Change
Phase 2  Chrome 95 October 2021 Origin trial to experiment with Client Hints and provide feedback
Phase 3  Chrome 100 March 2022 Deprecation trial (opt-in)
Phase 4  Chrome 101 April 2022 Reduced Chrome version number rollout. MINOR.BUILD.PATCH version numbers becomes “0.0.0”.
Phase 5  Chrome 107 October 2022 Reduced Desktop User-agent string rollout
Phase 6 Chrome 110 February 2023   Reduced Mobile User-agent string rollout
Phase 7 Chrome 113 May 2023 Deprecation trial ends. Everyone receives reduced user-agents