client hints and user agentsEngineering

Client Hints & User-Agents in Chrome, Safari & Firefox

Learn about User-Agent & Client Hints API support in Chrome, Safari & Firefox and how we use them for passkeys & device detection in JavaScript components.

Blog-Post-Author

Vincent

Created: July 2, 2024

Updated: September 10, 2024


Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understand passkeys and its characteristics better.

Overview#

1. Introduction: What are Client Hints and User-Agent Reduction?#

Methods for detecting and responding to different user environments are constantly changing. Traditionally, User-Agent strings have been the way for identifying browser and device information, allowing websites to tailor experiences accordingly. However, these strings have often been used for fingerprinting and identifying users without their consent for marketing reasons raising privacy concerns.

In this context, Client Hints as JavaScript APIs have emerged as a tool, providing a more controlled and privacy-respecting way to share necessary information about the user's device and preferences. This article concentrates on the consequences of User-Agent reduction and explores how Client Hints help adapt to this new situation.

Key points we will address:

  • What is User-Agent reduction: Understanding the shift towards reduced User-Agent strings and its implications.
  • How Do Client Hints Work: Exploring the mechanisms behind Client Hints and how they can be implemented effectively.

As browsers and operating systems have different stands and adapt their approaches differently, software developers face the challenge of ensuring their applications can still detect and respond to varying user environments accurately across browsers and operating systems.

This article aims to provide a comprehensive overview of these changes, offering insights and practical guidance to help developers in case their use case or software depends on device or operating systems details (e.g. detailed device management, detect known devices, fraud prevention or other feature detections) or like in our own case optimize passkey experience with User-Agent and Client Hints.

Before we dive into the technical details about Client Hints, we’ll briefly explore the history of the User-Agent and how the different User-Agent reduction efforts work.

1.1 A Brief History of the User-Agent#

The history of User-Agent strings can be traced back to the inception of early web browsers. Tim Berners-Lee developed the first web browser, WorldWideWeb (later renamed Nexus) in 1990. This was soon followed by other pioneering browsers like Line Mode Browser in 1991, and subsequently, browsers such as MidasWWW, ViolaWWW, Erwise, and Cello emerged.

In 1993, the release of NCSA Mosaic, often simply referred to as Mosaic, is credited with igniting the initial surge in web popularity. Mosaic’s User-Agent string was quite straightforward, typically formatted as NCSA_Mosaic/1.0 featuring the product name followed by an optional slash and version number.

Initially, the User-Agent field was introduced for analytical purposes and to help identify issues. It was explicitly recommended that this field "should be included" in HTTP requests, as noted in the W3C HTTP archive from 1992. This straightforward field provided a simple yet effective way to convey the product name and version, aiding in the understanding and troubleshooting of browser-related issues.

As the web evolved, so did the complexity and usage of User-Agent strings. They became more detailed and began to include a wealth of information about the browser, operating system, and device. While this information was valuable for web analytics and optimizing user experiences, it also posed significant privacy concerns. Detailed User-Agent strings allowed for device fingerprinting, enabling advertisers and trackers to create unique profiles of users and track their online activities across different websites.

In the modern era, where privacy has become an important concern for users and regulators alike, the detailed nature of User-Agent strings has increasingly been viewed as problematic. This realization has led to efforts to reduce the granularity of User-Agent strings, aiming to strike a balance between providing necessary information for web functionality and protecting user privacy. This transition marks the beginning of User-Agent reduction, a movement towards minimizing the information shared in User-Agent strings to mitigate privacy risks and enhance security.

1.2 User-Agent Reduction & Client Hints Introduction#

The movement towards User-Agent reduction began as a response to growing privacy concerns. Here is a chronological overview of key milestones in this evolution:

1.2.1 User-Agents in Safari#

In 2017, Apple initiated the User-Agent reduction movement with a famous Twitter post announcing that Safari would freeze the User-Agent string in Safari Technology Preview 46 (STP 46), aiming to combat fingerprinting and improve privacy.

twitter safari user agent reduction

However, this decision was later partially reversed in 2021 due to significant compatibility issues with websites relying on up-to-date User-Agent information.

1.2.2 User-Agents in Chrome (+ Edge)#

In 2019/2020, Google announced plans to reduce the granularity of User-Agent strings in Chrome, introducing User-Agent Client Hints (UA-CH) as a flexible and controlled way to request specific browser and device information. Google began testing User-Agent reduction in Chrome Canary and Beta versions, gathering feedback to ensure compatibility and functionality and was completed in 2023 for Android and all other Chrome platforms. At the same time, Chrome introduced Client Hints as a new way to access that information. As Microsoft Edge is based on Chromium, Microsoft Edge behaves like Chrome on all platforms.

1.2.3 User-Agents in Firefox#

In 2021, Mozilla joined the effort, gradually reducing the User-Agent string granularity but Mozilla decided to not support Client Hints in Firefox.

1.2.4 User-Agents Today (July 2024)#

  • User-Agent Reduction is complete: The transitions to reduce User-Agents is complete on all major browsers.

  • Client Hints have evolved within Chromium: All browsers still send a User-Agent header, but in most of them it’s frozen to an older version (see table below). For Chromium, Client Hints can be used to get more information.

Let’s look what browser currently send as User-Agents in the following chapter.

Substack Icon

Subscribe to our Passkeys Substack for the latest news, insights and strategies.

Subscribe

2. What is User-Agent Reduction?#

When talking about User-Agent Reduction what is meant to reduce the information within the User-Agent string. Let’s dive deeper to find out what was embedded into the User-Agent prior to reduction.

2.1 What’s a Classical User-Agent?#

A classical User-Agent string typically included the following components, that could be used to detect functionality:

Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.2.1.0 Mobile Safari/537.36

  • Operating System: The name of the operating system (e.g., Windows, macOS, Linux).
  • Operating System Version Number: The specific version of the operating system.
  • Browser Name: The name of the browser (e.g., Chrome, Firefox, Safari).
  • Browser Version: The specific version of the browser.
  • Architecture: The architecture of the system (e.g., x86, ARM).
  • Device Type/Model: Information about the device type or model (e.g., iPhone, Pixel).
  • Other Information: This can include additional details like platform, build number, etc.
Slack Icon

Become part of our Passkeys Community for updates and support.

Join

2.1.1 Why Use User-Agent for Feature Detection?#

Historically, User-Agent strings were often used for feature and platform detection, allowing websites to tailor their content and functionality based on the detected browser and device characteristics (e.g. determine which download for specific binary to offer). This became especially important with the rise of mobile phones and tablets for layouts that were not built responsive to be able to redirect mobiles phones to their specific version.

However, this approach is now considered suboptimal, as it relies on assumptions about browser capabilities that may not hold true or be not specific enough. Modern web development practices advocate for using** feature detection via browser APIs** where possible to directly check for specific browser features and capabilities. This method is more reliable and ensures that websites work correctly regardless of the User-Agent string or browser version. Feature detection focuses on the actual capabilities of the browser, providing a more robust and future-proof way to handle differences in browser behavior and functionality.

Up to today, this is not fully possible as new browser APIs to detect functionality are implemented at different times and often there is a different approach between the larger (e.g. Chromium-based browsers) and smaller browser teams (e.g. Firefox).

2.1.2 Understanding Entropy in Fingerprinting: Why is Providing Much Information a Problem?#

More information gives a website a wider possibility to create a fingerprint with more “entropy”. Entropy in this context is the amount of variation that can be used to generate a unique fingerprint among different visitors from a website.

A fingerprint can be used for different purposes. It can be used for protective purposes like detecting fraud and stopping account takeovers by identifying new devices, but it can also be used to identify visitors without their consent or for more specific ad targeting.

In the context of User-Agent strings, entropy refers to the amount of unique, identifiable information that can be used to track and distinguish individual users.

  • High entropy information: Such as specific browser and OS versions, contributes significantly to the uniqueness of a user’s fingerprint, making it easier to track them across different websites.
  • Low entropy information: General browser name or operating system names, provide less detailed data and contributes less to user tracking as more users carry those combinations.

There is a lot of further information that can be used as a source of entropy beneath User-Agent. For example, you can find different sources of entropy on https://coveryourtracks.eff.org.

2.2 Reduction of User-Agent Entropy#

Therefore, when browser talk about User-Agent reduction, they primarily target to reduce the high entropy information. Here are different examples for the reduction:

2.2.1 Example 1: Chrome User-Agent Reduction#

In the following, you find an example for Google’s Chrome User-Agent reduction on an Android phone:

Before: Mozilla/5.0 (Linux; Android <span style={{color: '#016F01' }}>13; Pixel 7</span>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.0.0 Mobile Safari/537.36

After: Mozilla/5.0 (Linux; Android <span style={{color: '#016F01' }}>10; K</span>) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.0.0 Mobile Safari/537.36

The format of the User-Agent remained unchanged in order not to interfere with existing parsing logic of libraries. The following values were reduced:

  • Operating system version
  • Browser minor version
  • Hardware model user agent

The graphic details which values will continue to be updates based on the operating system and the green values show which values will be constant on all platforms. For different operating system values there will be only a variant available that stays constant:

Operating systemReduced/fixed name
MacMacintosh; Intel Mac OS X 10_15_7
WindowsWindows NT 10.0; Win64; x64
ChromeOSX11; CrOS x86_64 14541.0.0
LinuxX11; Linux x86_64
AndroidLinux; Android 10; K
iOSnot reduced

2.2.2 Example 2: Firefox User-Agent Reduction#

In the following, you find an example for Mozilla Firefox’s User-Agent reduction that follows most of Google’s positions on User-Agent reduction.

Here is an example of a User-Agent on Windows 11 with a current Firefox version:

Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0

In this User-Agent, the CPU Architecture, the operating system version and browser minor version have been frozen.

2.2.3 Example 3: Safari User-Agent Reduction on macOS#

In the following, you find an example of a Safari User-Agent reduction on macOS.

First, let’s start with a Safari User-Agent on a macOS Sonoma Version 14.5 on Mac Silicon M2.

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15

You can see that the macOS Version is capped to 10_15_07 and the architecture is also fixed to Intel not reporting the Mac CPU architecture. This is also true for Firefox and Chrome on macOS.

2.2.4 Example 4: Safari User-Agent on iOS (Not Reduced)#

In contrast to the example provided for macOS, on iOS, Safari continues to expose the correct operating system version number (17_5_1):

Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1

Chrome and Firefox show a comparable behavior on iOS exposing the actual operating system version. :

Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/126.0.6478.153 Mobile/15E148 Safari/604.1

Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/127.1 Mobile/15E148 Safari/605.1.15

It seems that this is due to the large backlash Safari had received on changing User-Agent in 2017 on iOS that Apple refrains from adjusting the operating system version on iOS.

2.3 Detection Limitations with User-Agent Reduction#

Overall, it is obvious that the User-Agent is reduced specifically on high entropy information. The following overview shows on which platform / operating system combinations the User-Agent is reduced.

BrowserWindowsMacOSiOSAndroid
Chromereducedreducednot reducedreduced
Edgereducedreducednot reducedreduced
Firefoxreducedreducednot reducedreduced
Safari-reducednot reduced-
WebViews--not reducednot reduced

Therefore, the most important detection problems with a reduced User-Agent are:

  • Windows 10 and Windows 11 cannot be distinguished: You cannot distinguish Windows 10 and Windows 11 systems based on User-Agent anymore
  • Android devices & operating system version cannot be distinguished: In contrast to Apple, Android used to include the actual hardware model into the User-Agent. This is not the case anymore. Therefore, different hardware models cannot be distinguished anymore only via User-Agent. With Apple this has never been possible.
  • macOS version & architecture cannot be distinguished: There is no way to differentiate macOS versions and platform architectures based on User-Agent.

There are other ways to detect operating systems and browsers based on elaborated fingerprinting techniques, like TLS fingerprinting. As there are legitimate scenarios where a deeper operating system detection would make sense, Google introduced Client Hints to be able to receive this information programmatically. We will see how Client Hints work in the next chapter.

3. How Do Client Hints Work?#

Client Hints enable websites to access high entropy information that was removed from the User-Agent string in a privacy-friendly manner. There are two primary methods to access Client Hints:

  • HTTP Header: Using HTTP request headers, which is available only for first-party contexts.
  • JavaScript API: Using a JavaScript API, which can be used by an embedded script.

Client hints can also be used to retrieve the low entropy information that is already included in the User-Agent. This implies that on Chrome, where client hints are supported, user-agents are not needed anymore.

3.1 Which Client Hints Do Exist?#

Depending on which access method is used, the naming of the Client hints slightly differs. We have listed the most important name of Client Hints:

HTTP UA-CH tokenUA-CH JS APIEntropy
Sec-CH-UA-Platform-VersionUADataValues.platformVersionHigh
Sec -CH-UA-MobileNavigatorUAData.mobileLow
Sec-CH-UA-ModelUADataValues.modelHigh
Sec-CH-UANavigatorUAData.brandsLow
Sec-CH-UA-ArchUADataValues. architectureHigh

3.2 How to Access Client Hints via HTTP Request Headers#

In a first-party context, websites can request specific information about the user's browser and device using HTTP request headers. This approach involves setting the correct header in the server's HTTP response, indicating which Client Hints the server is interested in. The browser then includes these hints in subsequent requests to the same origin.

This header signals the browser to send detailed user information in future requests, allowing the server to tailor responses accordingly. This method ensures that detailed user information is only accessible to the first-party website, preventing third-party resources from obtaining high entropy data. There are two types of request headers available which we will discuss now:

  • Regular Client Hint Headers
  • Critical (Client) Hint Headers

3.2.1 How to Use Regular Client Hint Headers?#

Regular Client Hints are headers that a server can request from the browser to gather information about the user's environment in subsequent requests.

Example: Chrome on macOS 14.5 with regular Client Hints on corbado.com

  1. On the first request for corbado.com, Chrome will already include the following low entropy headers as this information is also included in the User-Agent.
HeaderValue
Sec-Ch-Ua"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"
Sec-Ch-Ua-Mobile?0
Sec-Ch-Ua-Platform"macOS"
  1. Let’s say corbado.com would like to receive the operating system version (platform version) on subsequent requests. Therefore, it would then set the appropriate “Sec-CH-UA-Platform-Version” header in the response to the first request:
HeaderValue
Accept-CHSec-CH-UA-Platform-Version
  1. On subsequent requests*,* corbado.com would then receive one additional header with the platform version:
HeaderValue
Sec-Ch-Ua"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"
Sec-Ch-Ua-Mobile?0
Sec-Ch-Ua-Platform"macOS"
Sec-Ch-Ua-Platform"14.5.0"

At the same time, the User-Agent for this request will remain the same (without platform version):

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

Using https://user-agent-client-hints.glitch.me/headers, you can actually play around how different layouts of information would look like for regular hints (keep in mind you must use Chrome). See here for more details. In case corbado.com would need this information on the very first page request, this using regular Client Hints would not be sufficient, but there is a way to expedite this process with critical (client) hints.

3.2.2 How to use Critical (Client) Hint Headers?#

Lets say corbado.com would need the platform-version on the first request to render an appropriate download page tailored to the exact macOS version. It could use the Critical (client) hints which would lead to an immedate retry of the request to only render the page including the header:

Example: Chrome on macOS 14.5 with critical Client Hints on corbado.com

  1. On the first request for corbado.com, Chrome will already include the following low entropy headers as this information is also included in the User-Agent.
HeaderValue
Sec-CH-UA"Google Chrome";v="125", "Chromium";v="125", "Not_A/Brand";v="24"
Sec-CH-UA-Mobile?0
Sec-CH-UA-Platform"macOS"
  1. Let’s say corbado.com would like to receive the operating system version (platform version) on the first rendering of the page. It would then set the critical client hint header “Sec-CH-UA-Platform-Version” in the response to the first request:
HeaderValue
Accept-CHSec-CH-UA-Platform-Version
  1. Chrome would not start rendering and immediately retry the request, so that the header is available on first rendering of corbado.com. It would then receive the additional header with the platform version:
HeaderValue
Sec-CH-UA"Google Chrome";v="125", "Chromium";v="125", "Not_A/Brand";v="24"
Sec-CH-UA-Mobile?0
Sec-CH-UA-Platform"macOS"
Sec-CH-UA-Platform-Version"14.5.0"

In the following charts, we see another example where the website requests the device model as critical part with the Critical-CH header. As we can see, the client retries the request like in the example above (left sequence chart).

chromium user agent flow completeClient hints with Chromium: https://developers.google.com/privacy-sandbox/protections/User-Agent

Using critical Client Hints therefore adds latency because the browser must start a second request immediately adding roundtrips. There is a way to optimize the transfer by facilitating the TLS handshake (the green box at the top of the chart) to already transmit the details. This approach facilitating ALPN (Application-Layer Protocol Negotiation) can be found here in detail but is beyond the purpose of this article.

To receive additional information using headers, configuration needs to be added either to the backend or to the webserver / load balancers. This is easily done in a first-party context, when you have full control over the website as company. For example, our UI components at corbado.com require the platform version to increase the precision of our passkey intelligence. Developers integrate our components on various pages and requiring them to add headers and then pass that information to our components would be an unpleased overhead. For SPAs and other embedded JavaScript applications, there is another interface that can be used, which will be explained in the next section.

3.3 How to Access Client hints via JavaScript API (Embedded Scripts)#

Using the navigator.userAgentData.getHighEntropyValues() function, Client hints can also be accessed via a JavaScript API, providing a flexible and dynamic way to request specific information about the user's browser and device. This method involves using the navigator.userAgentData object within the web page's script to query for Client Hints. This method does not require the Client hint headers to be set in any way, it just always works.

For example, when executing this code in a Chrome Console on macOS:

if (navigator.userAgentData) { navigator.userAgentData.getHighEntropyValues(['architecture', 'model', 'platformVersion']) .then(ua = \ > { console.log(ua); }); }

When the promise resolves, the relevant information is returned. As we outlined above, the names are not completely identical to the headers but are very close.

platform version

The platformVersion is then returned in the promise and it can be accessed directly from the embedded JavaScript code. The coverage for this function is much lower than the actual User-Agent reduction low:

get high entropy list

Additionally, Chrome does not offer this functionality on iOS because it deploys WebKit on iOS due to Apple's limitations.

We now have put together the most important facts about User-Agent reduction and how Client hints offer a way around it in Chrome.

4. Recommendation for Approaching User-Agents Today#

Depending on your use case, you should use a different approach to ensure your application gets the best result possible:

  • Feature Detection: Use existing browser JavaScript APIs wherever possible. Whenever feasible, rely on browser APIs to detect functionality directly, rather than using the User-Agent. This is more reliable and future-proof.
  • For low entropy, hints like device type: User-Agent is sufficient. If your application only needs to determine the device type or other low entropy details, the User-Agent string will be sufficiently detailed. You can also use existing APIs for these purposes.
  • For high entropy information and domain control: Use the header approach. If you require detailed information and have control over the domain, utilize the HTTP header approach to request high entropy information where supported (Chrome, Edge). On all other browsers (that do not send Client hint headers) use the classic User-Agent. Decide if you need to use critical Client Hints based on whether you need the information immediately or can afford a slight delay.
  • For JavaScript libraries: Use getHighEntropyValues. If you are developing a JavaScript library, the best option is to use the navigator.userAgentData.getHighEntropyValues() function to dynamically request specific information about the user's browser and device whenever this function is defined and fallback on User-Agent parsing libraries on other cases.

By choosing the appropriate method based on your specific needs, you can effectively balance the need for detailed user information with privacy and performance considerations. If you highly depend on information that is difficult to extract or is really device based fall back to professional libraries like wurfl or 51degrees.com that do the heavy lifting for you. Both libraries support integrating client links into the detection and also have their own propriatry way to even detect iPhone models.

5. How to Use User-Agents and Client Hints for Passkeys#

At Corbado, we focus on developing solutions around passkeys using UI components primarily developed with React. Our components are embedded into various websites, so we follow our own recommendation and use getHighEntropyValues()wherever it is available, falling back on classic User-Agent parsing for all other cases. We primarily use this for:

  • Passkey management: On our passkey management site, we display all available information about the device where the passkey was created.
  • Cross-Device-Authentication: For cross-device authentication, we use information about the operating system to determine how likely it is that the client supports leveraging CDA. This is especially important when differentiating between Windows 10 and 11, which is only possible with Client Hints on Chrome and Edge:

get high entropy valueMore details on: https://learn.microsoft.com/en-us/microsoft-edge/web-platform/how-to-detect-win11

  • Passkey intelligence: We believe that the platform should decide whether a passkey login should be initiated. Therefore, we integrate as much logic as possible into our components to detect if a new device is being used. In such scenarios, a new or smaller operating system version is a valuable hint that things might have changed.

When we started compiling information for our components, we found a lot of fragmented data created during or before the start of User-Agent reduction. Therefore, we thought a summary would help developers who want to improve detection but do not work with User-Agents or Client Hints regularly.

6. Conclusion#

After user User-Agent based detection was the standard for decades User-Agent strings have become less detailed to protect user privacy. In this article we covered:

  • What is User-Agent Reduction? User-Agent reduction is the process of minimizing the amount of information shared through User-Agent strings to protect user privacy. This transition reduces the granularity of data such as the operating system version and hardware model, which were previously used for fingerprinting and tracking users across different websites. We explored how this reduction affects developers and how they can adapt to these changes.
  • How Do Client Hints Work? Client hints provide a mechanism to request specific, high-entropy information about the user's device in a more privacy-conscious manner. By using HTTP headers and JavaScript APIs, developers can access detailed data about the user's environment when necessary. We discussed how Client Hints are implemented, the types of hints available, and the methods to access them via HTTP request headers and JavaScript.

Client hints are continuing to evolve, and their adoption may increase as more browsers and developers recognize their benefits. However, it remains to be seen whether their support will become widespread or if the web will continue to diverge on this topic.

Share this article


LinkedInTwitterFacebook

Enjoyed this read?

🤝 Join our Passkeys Community

Share passkeys implementation tips and get support to free the world from passwords.

🚀 Subscribe to Substack

Get the latest news, strategies, and insights about passkeys sent straight to your inbox.


We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour

Start for free