From 7f30f4aacfc18cdc64697b79c63cf38b5b4f64b6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 23 Oct 2025 15:34:47 +0100 Subject: [PATCH 1/6] Add information to MDN about User-Agent reduction --- .../web/api/navigator/appversion/index.md | 62 ++++--- .../en-us/web/api/navigator/platform/index.md | 37 ++-- .../web/api/navigator/useragent/index.md | 55 +++--- .../web/http/guides/client_hints/index.md | 41 ++++- .../http/guides/user-agent_reduction/index.md | 174 ++++++++++++++++++ .../reference/headers/user-agent/index.md | 95 +++++++++- files/sidebars/http.yaml | 1 + 7 files changed, 394 insertions(+), 71 deletions(-) create mode 100644 files/en-us/web/http/guides/user-agent_reduction/index.md diff --git a/files/en-us/web/api/navigator/appversion/index.md b/files/en-us/web/api/navigator/appversion/index.md index ab68b69f8d11438..159ddf6887aa065 100644 --- a/files/en-us/web/api/navigator/appversion/index.md +++ b/files/en-us/web/api/navigator/appversion/index.md @@ -8,37 +8,50 @@ browser-compat: api.Navigator.appVersion {{APIRef("HTML DOM")}} -Returns either `"4.0"` or a string representing version information about -the browser. - -> [!NOTE] -> Do not rely on this property to return the correct browser version. +The **`Navigator.appVersion`** read-only property of the {{domxref("Navigator")}} interface returns a string representing version information about the browser. ## Value -Either `"4.0"` or a string representing version information about the -browser. +A string representing version information about the browser. -## Examples +## Description -```js -alert(`Your browser version is reported as ${navigator.appVersion}`); +The `appVersion` property returns some information indicating the browser version. + +In some browsers, such as Chrome, this is nearly the same as the value returned by {{domxref("Navigator.userAgent")}}, with the `Mozilla/` prefix removed. For example: + +```plain +5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 ``` -## Notes +In other browsers, such as Firefox, this is cut down to a short string that hints at the platform/OS. For example: + +```plain +5.0 (Macintosh) +``` + +### Browser detection + +Theoretically this information is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**: + +- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. +- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). +- Browser detection lead to a situation where browsers had to return fake values from such properties in order not to be locked out of some websites. -The `window.navigator.userAgent` property may also contain the version -number (for example -`"Mozilla/5.0 (Windows; U; Win98; en-US; rv:0.9.2) Gecko/20010725 Netscape 6/6.1"`), -but you should be aware of how easy it is to change the user agent string and "spoof" -other browsers, platforms, or user agents, and also how cavalier the browser vendor -themselves are with these properties. +See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. -The `window.navigator.appVersion`, `window.navigator.appName` and -`window.navigator.userAgent` properties have been used in "browser sniffing" -code: scripts that attempt to find out what kind of browser you are using and adjust -pages accordingly. This lead to the current situation, where browsers had to return fake -values from these properties in order not to be locked out of some websites. +### User-Agent reduction + +The information exposed in the `appVersion` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the {{domxref("Navigator.userAgent", "userAgent")}} property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). + +## Examples + +```js +console.log(navigator.appVersion); +// On Chrome, logs something like "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" (reduced UA string) + +// On Firefox, logs something like "5.0 (Macintosh)" +``` ## Specifications @@ -47,3 +60,8 @@ values from these properties in order not to be locked out of some websites. ## Browser compatibility {{Compat}} + +## See also + +- {{domxref("Navigator.userAgent")}} +- {{HTTPHeader("User-agent")}} HTTP header diff --git a/files/en-us/web/api/navigator/platform/index.md b/files/en-us/web/api/navigator/platform/index.md index 213b2391c2a9709..88ac189efee8525 100644 --- a/files/en-us/web/api/navigator/platform/index.md +++ b/files/en-us/web/api/navigator/platform/index.md @@ -10,29 +10,43 @@ browser-compat: api.Navigator.platform The **`platform`** property read-only property of the {{domxref("Navigator")}} interface returns a string identifying the platform on which the user's browser is running. +## Value + +A string identifying the platform on which the user's browser is running; for example: + +- `"MacIntel"` +- `"Win32"` +- `"Linux x86_64"` + > [!NOTE] -> In general, you should whenever possible avoid writing code that uses methods or properties like this one to try to find out information about the user's environment, and instead write code that does [feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection). +> On Windows, modern browsers return `"Win32"` even if running on a 64-bit version of Windows. -## Value +## Description + +The `appVersion` property returns some information indicating the platform/OS the browser is running on. -A string identifying the platform on which the user's browser is running; for example: `"MacIntel"`, `"Win32"`, `"Linux x86_64"`, `"Linux armv81"`. +### Browser detection + +Theoretically this information is useful for detecting the browser's underlying platform and serving code to work around OS-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**. Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. + +See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. + +### User-Agent reduction + +The information exposed in the `platform` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used (in part) to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the {{domxref("Navigator.userAgent", "userAgent")}} property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). ## Examples -`navigator.platform` should almost always be avoided in favor of [feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection). But there is one case where, among the options you could use, `navigator.platform` may be the least-bad option: When you need to show users advice about whether the modifier key for keyboard shortcuts is the `⌘` command key (found on Apple systems) rather than the `⌃` control key (on non-Apple systems): +One case where `navigator.platform` can be useful is when you need to show users advice about whether the modifier key for keyboard shortcuts is the `⌘` command key (found on Apple systems) rather than the `Ctrl` control key (on non-Apple systems): ```js const modifierKeyPrefix = navigator.platform.startsWith("Mac") || navigator.platform === "iPhone" ? "⌘" // command key - : "^"; // control key + : "Ctrl"; // control key ``` -That is, check if `navigator.platform` starts with `"Mac"` or else is an exact match for `"iPhone"`, and then based on whether either of those is true, choose the modifier key your web application's UI will advise users to press in keyboard shortcuts. - -## Usage notes - -On Windows, modern browsers return `"Win32"` even if running on a 64-bit version of Windows. +This code checks if `navigator.platform` starts with `"Mac"` or else is an exact match for `"iPhone"`, and then based on whether either of those is `true`, sets a `modifierKeyPrefix` variable to the appropriate modifier key for the user's platform. This could be used in a web UI to tell users which modifier key they need when using keyboard shortcuts. ## Specifications @@ -44,4 +58,5 @@ On Windows, modern browsers return `"Win32"` even if running on a 64-bit version ## See also -- [`navigator.userAgentData.platform`](/en-US/docs/Web/API/NavigatorUAData/platform) +- {{domxref("Navigator.userAgent")}} +- {{HTTPHeader("User-agent")}} HTTP header diff --git a/files/en-us/web/api/navigator/useragent/index.md b/files/en-us/web/api/navigator/useragent/index.md index f7c37c4318e0d97..7af1f9837cb4a51 100644 --- a/files/en-us/web/api/navigator/useragent/index.md +++ b/files/en-us/web/api/navigator/useragent/index.md @@ -8,46 +8,37 @@ browser-compat: api.Navigator.userAgent {{ApiRef("HTML DOM")}} -The **`Navigator.userAgent`** read-only property returns the -user agent string for the current browser. - -> [!NOTE] -> The specification asks browsers to provide as little information via this field as -> possible. Never assume that the value of this property will stay the same in future -> versions of the same browser. Try not to use it at all, or only for current and past -> versions of a browser. New browsers may start using the same UA, or part of it, as an -> older browser: you really have no guarantee that the browser agent is indeed the one -> advertised by this property. -> -> Also keep in mind that users of a browser can change the value of this field if they -> want (UA spoofing). - -Browser identification based on detecting the user agent string is -**unreliable** and **is not recommended**, as the user agent -string is user configurable. For example: - -- In Firefox, you can change the preference `general.useragent.override` in - `about:config`. Some Firefox extensions do that; however, this only changes - the HTTP header that gets sent and that is returned by `navigator.userAgent`. - There might be other methods that utilize JavaScript code to identify the browser. -- Opera 6+ allows users to set the browser identification string via a menu. +The **`Navigator.userAgent`** read-only property of the {{domxref("Navigator")}} interface returns the `User-Agent` (UA) string for the current browser. ## Value -A string specifying the complete user agent string the browser -provides both in {{Glossary("HTTP")}} headers and in response to this and other related -methods on the {{domxref("Navigator")}} object. +A string specifying the browser's complete UA string. -The user agent string is built on a formal structure which can be decomposed into -several pieces of info. Each of these pieces of info comes from other navigator -properties which are also settable by the user. For more information about the -form of the user agent string, see the {{HTTPHeader("User-agent")}} HTTP header. +The browser also provides this via the {{HTTPHeader("User-agent")}} HTTP header. Parts of this information are also available in {{Glossary("HTTP")}} headers such as [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints) and other related API features such as {{domxref("Navigator.appVersion")}} and {{domxref("Navigator.platform")}}. + +The UA string is built on a formal structure, which can be decomposed into several pieces of information. For more information about the form of the UA string, see the {{HTTPHeader("User-agent")}} HTTP header. + +## Description + +The `userAgent` property provides the current browser's UA string. Theoretically this is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, browser identification based on detecting the UA string is **unreliable** and **is not recommended**: + +- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. +- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). +- Even the specification asks browsers to provide as little information via this property as possible. + +See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. + +### User-Agent reduction + +The information exposed in the `userAgent` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the `userAgent` property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). ## Examples ```js -alert(window.navigator.userAgent); -// alerts "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0" +console.log(navigator.userAgent); +// On Chrome, logs something like "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" (reduced UA string) + +// On Firefox, logs something like "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0" ``` ## Specifications diff --git a/files/en-us/web/http/guides/client_hints/index.md b/files/en-us/web/http/guides/client_hints/index.md index eda0caa05628b2f..2ec3a0e796c2fea 100644 --- a/files/en-us/web/http/guides/client_hints/index.md +++ b/files/en-us/web/http/guides/client_hints/index.md @@ -13,7 +13,22 @@ The set of "hint" headers are listed in the topic [HTTP Headers](/en-US/docs/Web ## Overview -A server must announce that it supports client hints, using the {{HTTPHeader("Accept-CH")}} header to specify the hints that it is interested in receiving. +When the browser first makes a request to load a webpage, it will send a {{httpheader("User-Agent")}} header and a default set of `Sec-CH-UA-*` headers along with the initial request. An Android device, for example, might send the following: + +```http +User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 +Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA-Platform: "Android" +Sec-CH-UA-Mobile: ?1 +``` + +These `CH-UA` headers provide the following information: + +- {{httpheader("Sec-CH-UA")}}: The major browser version. +- {{httpheader("Sec-CH-UA-Platform")}}: The platform. +- {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is on a mobile device (`?1`) or not (`?0`). + +In response, the server can announce that it supports client hints and specify the hints that it is interested in receiving using the {{HTTPHeader("Accept-CH")}} header. When a client that supports client hints receives the `Accept-CH` header it can choose to append some or all of the listed client hint headers in its subsequent requests. For example, following `Accept-CH` in a response below, the client could append {{HTTPHeader("Width")}}, {{HTTPHeader("Downlink")}} and {{HTTPHeader("Sec-CH-UA")}} headers to all subsequent requests. @@ -141,6 +156,30 @@ Headers include: {{HTTPHeader("Device-Memory")}}, {{HTTPHeader("Width")}}, {{HTT Network client hints allow a server to vary responses based on the user's choice, network bandwidth, and latency. Headers include: {{HTTPHeader("Save-Data")}}, {{HTTPHeader("Downlink")}}, {{HTTPHeader("ECT")}}, {{HTTPHeader("RTT")}}. +## Using client hints for responsive design + +It's possible to use client hints for responsive design, for example to detect whether a mobile device or tablet is rendering your site. + +An Android phone would send the following default client hints: + +```http +Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA-Platform: "Android" +Sec-CH-UA-Mobile: ?1 +``` + +An Android tablet on the other hand would send the following: + +```http +Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA-Platform: "Android" +Sec-CH-UA-Mobile: ?0 +``` + +The {{httpheader("Sec-CH-UA-Mobile")}} header can be used to determine whether the device is a mobile device or not. For hardware-specific use cases, the device model name can be requested via the high-entropy {{httpheader("Sec-CH-UA-Model")}} hint. + +For many responsive design needs, [media queries](/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) would be more convenient and flexible. However, there may be cases where you don't have control over the individual stylesheets of a site, and need to vary the stylesheet served based on the device signature. + ## See also - [Client Hints headers](/en-US/docs/Web/HTTP/Reference/Headers#client_hints) diff --git a/files/en-us/web/http/guides/user-agent_reduction/index.md b/files/en-us/web/http/guides/user-agent_reduction/index.md new file mode 100644 index 000000000000000..55ad2feed0d076b --- /dev/null +++ b/files/en-us/web/http/guides/user-agent_reduction/index.md @@ -0,0 +1,174 @@ +--- +title: User-Agent reduction +slug: Web/HTTP/Guides/User-agent_reduction +page-type: guide +sidebar: http +--- + +The information exposed in the {{httpheader("User-Agent")}} HTTP header has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, **User-Agent reduction** provides a reduced set of information in the browser `User-Agent` header, and in related API features such as {{domxref("Navigator.userAgent")}}, {{domxref("Navigator.appVersion")}}, and {{domxref("Navigator.platform")}}. + +This article explains the differences in user agent (UA) strings as a result of User-Agent reduction, and explains modern strategies for accessing further UA information if required. + +## UA string differences resulting from User-Agent reduction + +In [supporting browsers](/en-US/docs/Web/HTTP/Reference/Headers/User-Agent#browser_compatibility), User-Agent reduction removes three pieces of information from the UA string — the exact platform/OS version, device model, and minor browser version. + +Let's look at an example so you can see what this looks like. Whereas previously the UA string for Chrome running on Android might have looked like this: + +```plain +Mozilla/5.0 (Linux; Android 16; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.12.45 Mobile Safari/537.36 +``` + +After the User-Agent reduction update, it now looks like this: + +```plain +Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 +``` + +The below sections provide more detail about each of the US string changes. + +### Platform/OS version and device model + +The platform version and devce model are always represented by fixed values: + +- `Android 10; K` on Android. +- `Macintosh; Intel Mac OS X 10_15_7` on macOS. +- `Windows NT 10.0; Win64; x64` on Windows. +- `X11; CrOS x86_64 14541.0.0` on ChromeOS. +- `X11; Linux x86_64` on Linux. + +### Minor browser version + +The major browser version number shows correctly, but the minor version numbers are always shown as zeros — `0.0.0`. + +## Alternatives to UA string browser sniffing + +Theoretically, the information available in the UA string is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, in addition to the privacy concerns mentioned earlier, browser identification based on detecting the UA string is **unreliable** and **is not recommended**: + +- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. +- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). + +The following are much more reliable strategies for working around bugs and differing browser support: + +- [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection): Detecting support for a feature, rather than the browser version. +- [Progressive enhancement](/en-US/docs/Glossary/Progressive_Enhancement): Providing a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience to browsers that can run all the required code. + +Also see [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea. + +## Requesting detailed UA information via client hints + +You may still have code that relies on detailed UA string data, which can't be coverted to use feature detection or progressive enhancement. Examples include fine-grained logging, fraud prevention measures, or a software help site that serves different content based on the user's device type. + +If this is the case, you can still access detailed UA string data via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers (aka **User-Agent client hints**) and other headers besides. The headers provide a safer, more privacy-preserving way to send such information because servers have to opt in to the pieces of information they want, rather it being sent all the time through the `User-Agent` string. It also provides access to a wider selection of information. + +Client hints are used like so: + +1. When the browser first makes a request to load a webpage, it will send the reduced `User-Agent` header (as detailed earlier) to the server. +2. Additionally, it will send the server a default set of `Sec-CH-UA-*` headers. The Android example we looked at earlier would send the following: + + ```http + Sec-CH-UA: "Chrome"; v="143" + Sec-CH-UA-Platform: "Android" + Sec-CH-UA-Mobile: ?1 + ``` + + These headers provide the following information: + - {{httpheader("Sec-CH-UA")}}: The major browser version. + - {{httpheader("Sec-CH-UA-Platform")}}: The platform. + - {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is running on a mobile device (`?1`) or not (`?0`). + +3. The server can request additional client hints using the {{httpheader("Accept-CH")}} response header, which contains a comma-delimited list of the headers it would like to receive in subsequent requests. For example: + + ```http + Accept-CH: Sec-CH-UA, Sec-CH-UA-Platform, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Form-Factors + ``` + + Here we've requested the default set of headers. We do this because each subsequent `Accept-CH` setting overrides the previous one, and we want to continue to receive the default information _in addition_ to the newly-requested information: + - {{httpheader("Sec-CH-UA-Model")}}: The device model the platform is running on. + - {{httpheader("Sec-CH-UA-Form-Factors")}}: The device's form factor(s), which indicate how the user interacts with the user-agent — the screen size, controls, etc. + +4. If the browser is permitted to send the server all the requested information, it will do so along with all subsequent requests until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: + + ```http + Sec-CH-UA: "Chrome"; v="143" + Sec-CH-UA-Platform: "Android" + Sec-CH-UA-Mobile: ?1 + Sec-CH-UA-Model: "Pixel 9" + Sec-CH-UA-Form-Factors: "Mobile" + ``` + +Since these are hints, the browser may choose to ignore some of all of the server's requests for more information. In addition, the browser may be blocked from sending some or all of the information by various security features such as {{httpheader("Permissions-Policy")}}. + +[EDITORIAL: IS THIS TRUE? I READ THIS SOMEWHERE, BUT I CAN'T FIND ANY INFO ANYWHERE ON WHAT CAN BLOCK BROWSERS FROM SENDING CLIENT HINTS. WHAT CLIENT FEATURES CAN BLOCK SENDING CLIENT HINTS?] + +For more information, see [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). + +### Critical client hints + +If you need a specific set of client hints sent in your initial request for the initial page rendering to work, you can use the {{httpheader("Critical-CH")}} response header. `Critical-CH` values must be a subset of the values requested by `Accept-CH`. + +For example, the initial response may include a request for {{httpheader("Device-Memory")}} and {{httpheader("Viewport-Width")}}, where `Device-Memory` is considered critical: + +```http +GET / HTTP/1.1 +Host: example.com + +HTTP/1.1 200 OK +Content-Type: text/html +Accept-CH: Device-Memory, Viewport-Width +Vary: Device-Memory, Viewport-Width +Critical-CH: Device-Memory +``` + +This will cause the browser to send a new request for the page, including the critical hint. + +In summary, `Accept-CH` requests all values you'd like for the page, while `Critical-CH` requests only the subset of values you must have on-load to properly load the page. + +## Accessing client hints via JavaScript + +The [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API) allows you to access client-hint information via JavaScript. The {{domxref("Navigator.userAgentData")}} property provides access to the {{domxref("NavigatorUAData")}} object, which contains the client hints. + +For example, if we consider our `Accept-CH` example from earlier: + +```http + Accept-CH: Sec-CH-UA, Sec-CH-UA-Platform, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Form-Factors +``` + +Once the server sends this header, provided there is nothing blocking the browser from providing this information, we can access the `Sec-CH-UA`, `Sec-CH-UA-Platform`, and `Sec-CH-UA-Mobile` values using properties on the `NavigatorUAData` object: + +```js +console.log(navigator.userAgentData.brands[0].brand); +console.log(navigator.userAgentData.brands[0].version); +// The browser and version +// For example "Chrome" and "143" + +console.log(navigator.userAgentData.platform); +// The platform/OS, for example "macOS" + +console.log(navigator.userAgentData.mobile); +// Whether the browser is running on a mobile device: true or false +``` + +To access so-called [high-entropy](/en-US/docs/Web/HTTP/Guides/Client_hints#high_entropy_hints) hints like `Sec-CH-UA-Model` and `Sec-CH-UA-Form-Factors`, you need to use the {{domxref("NavigatorUAData.getHighEntropyValues()")}} method. This takes an array of the requested hints as an argument and returns a promise that fulfills with an object containing the requested hint values. + +For example: + +```js +navigator.userAgentData + .getHighEntropyValues(["model", "formFactors"]) + .then((values) => { + console.log(values.model); + console.log(values.formFactors); + // For example + // "Pixel 9" + // ["Mobile"] + }); +``` + +## See also + +- {{httpheader("User-Agent")}} +- {{domxref("Navigator.userAgent")}}, {{domxref("Navigator.appVersion")}}, and {{domxref("Navigator.platform")}} +- [HTTP Client hints](/en-US/docs/Web/HTTP/Guides/Client_hints) +- [Implementing feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) +- [https://developer.chrome.com/docs/privacy-security/user-agent-client-hints](https://developer.chrome.com/docs/privacy-security/user-agent-client-hints) on developer.chrome.com (2020) diff --git a/files/en-us/web/http/reference/headers/user-agent/index.md b/files/en-us/web/http/reference/headers/user-agent/index.md index d4da876e2f4c03b..4dfddc587bf484a 100644 --- a/files/en-us/web/http/reference/headers/user-agent/index.md +++ b/files/en-us/web/http/reference/headers/user-agent/index.md @@ -46,6 +46,30 @@ User-Agent: Mozilla/5.0 () () < - `` - : Zero or more comments containing more details. For example, sub-product information. +## User-Agent reduction + +The information exposed in the `User-Agent` header has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their `User-Agent` header, and in related API features such as {{domxref("Navigator.userAgent")}}, {{domxref("Navigator.appVersion")}}, and {{domxref("Navigator.platform")}}. + +For example, whereas previously the `User-Agent` string for Chrome running on Android might have looked like this: + +```plain +Mozilla/5.0 (Linux; Android 16; Pixel 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.12.45 Mobile Safari/537.36 +``` + +After the User-Agent reduction update, it now looks like this: + +```plain +Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 +``` + +- The platform version is always a fixed value, in this case, `Android 10`. +- The device model is always a fixed value, in this case, `K`. +- The Chrome major version number shows correctly, but the minor version numbers are always shown as zeros — `0.0.0`. + +Servers that want to request more information can do so using [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). After the initial connection, the server can send an {{httpheader("Accept-CH")}} response header detailing the data items they want, and the client can then send the data back via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers. This information can also be accessed via the [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API). + +For more detailed information, including a guide to retrieving more information as required, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). You can also find examples of reduced `User-Agent` strings in the following sections. + ## Firefox UA string For more on Firefox- and Gecko-based user agent strings, see the [Firefox user agent string reference](/en-US/docs/Web/HTTP/Reference/Headers/User-Agent/Firefox). The UA string of Firefox is broken down into 4 components: @@ -55,7 +79,7 @@ Mozilla/5.0 (platform; rv:gecko-version) Gecko/gecko-trail Firefox/firefox-versi ``` 1. `Mozilla/5.0` is the general token that says that the browser is Mozilla-compatible. For historical reasons, almost every browser today sends it. -2. **_platform_** describes the native platform that the browser is running on (Windows, Mac, Linux, Android, etc.) and if it is a mobile phone. {{Glossary("Firefox OS")}} phones say `Mobile` — the web is the platform. Note that **_platform_** can consist of multiple `;`-separated tokens. See below for further details and examples. +2. **_platform_** describes the native platform that the browser is running on (Windows, Mac, Linux, Android, etc.) and if it is a mobile phone. Note that **_platform_** can consist of multiple `;`-separated tokens. See below for further details and examples. 3. **rv:_gecko-version_** indicates the release version of Gecko (such as "_17.0_"). In recent browsers, **_gecko-version_** is the same as **_firefox-version_**. 4. **_Gecko/gecko-trail_** indicates that the browser is based on Gecko. (On the desktop, **_gecko-trail_** is always the fixed string `20100101`.) 5. **_Firefox/firefox-version_** indicates that the browser is Firefox and provides the version (such as "_17.0_"). @@ -64,6 +88,7 @@ Mozilla/5.0 (platform; rv:gecko-version) Gecko/gecko-trail Firefox/firefox-versi ```plain Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 + Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0 ``` @@ -73,16 +98,48 @@ The Chrome (or Chromium/Blink-based engines) user agent string is similar to Fir ### Examples +Desktop example: + +```plain +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 + +Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 +``` + +Android phone example: + +```plain +Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 +``` + +#### Pre-User-Agent reduction example + ```plain Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36 ``` ## Opera UA string -The Opera browser is also based on the Blink engine, which is why it almost looks the same as the Chrome UA string, but adds `"OPR/"`. +The Opera browser is also based on the Blink engine, which is why it almost looks the same as the Chrome UA string, but adds `"OPR/"`. For preview versions, Opera also includes a description of the particular browser edition in parentheses, for example `(Edition developer)`. ### Examples +Desktop examples: + +```plain +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 OPR/124.0.0.0 (Edition developer) + +Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 OPR/124.0.0.0 (Edition developer) +``` + +Android phone example: + +```plain +Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Mobile Safari/537.36 OPR/92.0.0.0 +``` + +#### Pre-User-Agent reduction examples + ```plain Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41 ``` @@ -91,27 +148,55 @@ Older, Presto-based Opera releases used: ```plain Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00 + Opera/9.60 (Windows NT 6.0; U; en) Presto/2.1.1 ``` ## Microsoft Edge UA string -The Edge browser is also based on the Blink engine. It adds `"Edg/"`. +The Edge browser is also based on the Blink engine. It adds `"Edg/"` on desktop platforms, `"EdgA/"` on Android, and `"EdgiOS/"` on iPhone. ### Examples +Desktop examples: + +```plain +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0 + +Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0 +``` + +Android phone example: + +```plain +Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36 EdgA/141.0.0.0 +``` + +#### Pre-User-Agent reduction example + ```plain Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59 ``` ## Safari UA string -In this example, the user agent string is mobile Safari's version. It contains the word `"Mobile"`. +Safari is based on the WebKit engine, but its UA string is also similar to the Blink-based browsers. It tends to include a `Version/xxx` string before the actual engine build version to indicate the browser release version, which unlike Blink-based browsers is different. In the case of iPhone (Mobile) Safari, the string also includes `Mobile`. + +> [!NOTE] +> At the time of writing, non-Apple iPhone browsers (such as Firefox, Chrome, and Edge) are still based on WebKit, therefore their UA strings are the same or similar to the Safari UA string. ### Examples +Desktop example: + +```plain +Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15 +``` + +iPhone example: + ```plain -Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1 +Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1 ``` ## Crawler and bot UA strings diff --git a/files/sidebars/http.yaml b/files/sidebars/http.yaml index 05c3530746bcd7d..fb6943a1ff03493 100644 --- a/files/sidebars/http.yaml +++ b/files/sidebars/http.yaml @@ -21,6 +21,7 @@ sidebar: - /Web/HTTP/Guides/Conditional_requests - /Web/HTTP/Guides/Range_requests - /Web/HTTP/Guides/Client_hints + - /Web/HTTP/Guides/User-agent_reduction - /Web/HTTP/Guides/Compression_dictionary_transport - /Web/HTTP/Guides/Network_Error_Logging - type: listSubPages From 84d2df3f32682040ad59637729f1020ea08ed0a9 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 23 Oct 2025 15:46:24 +0100 Subject: [PATCH 2/6] Add information to MDN about User-Agent reduction --- files/en-us/web/http/guides/client_hints/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/http/guides/client_hints/index.md b/files/en-us/web/http/guides/client_hints/index.md index 2ec3a0e796c2fea..dfde34ec3a2c9d8 100644 --- a/files/en-us/web/http/guides/client_hints/index.md +++ b/files/en-us/web/http/guides/client_hints/index.md @@ -186,4 +186,5 @@ For many responsive design needs, [media queries](/en-US/docs/Web/CSS/CSS_media_ - [`Vary` HTTP Header](/en-US/docs/Web/HTTP/Reference/Headers/Vary) - [Client Hints Infrastructure](https://wicg.github.io/client-hints-infrastructure/) - [User Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API) -- [Improving user privacy and developer experience with User-Agent Client Hints](https://developer.chrome.com/docs/privacy-security/user-agent-client-hints) (developer.chrome.com) +- [Improving user privacy and developer experience with User-Agent Client Hints](https://developer.chrome.com/docs/privacy-security/user-agent-client-hints) on developer.chrome.com (2020) +- [Migrate to User-Agent Client Hints](https://web.dev/articles/migrate-to-ua-ch) on web.dev (2021) From 49b2d2529286578f43bfe5f6c3ea74a3dc84cd0f Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 Oct 2025 10:05:54 +0100 Subject: [PATCH 3/6] Fixes for miketaylr review comments --- .../web/api/navigator/useragent/index.md | 4 +-- .../web/http/guides/client_hints/index.md | 14 ++++----- .../http/guides/user-agent_reduction/index.md | 30 ++++++++++++------- .../reference/headers/user-agent/index.md | 6 ++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/files/en-us/web/api/navigator/useragent/index.md b/files/en-us/web/api/navigator/useragent/index.md index 7af1f9837cb4a51..3c1c2698bda7518 100644 --- a/files/en-us/web/api/navigator/useragent/index.md +++ b/files/en-us/web/api/navigator/useragent/index.md @@ -36,9 +36,9 @@ The information exposed in the `userAgent` property has historically raised [pri ```js console.log(navigator.userAgent); -// On Chrome, logs something like "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" (reduced UA string) +// On Chrome on macOS, logs something like "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" (reduced UA string) -// On Firefox, logs something like "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0" +// On Firefox on Windows, logs something like "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0" ``` ## Specifications diff --git a/files/en-us/web/http/guides/client_hints/index.md b/files/en-us/web/http/guides/client_hints/index.md index dfde34ec3a2c9d8..081801cb01e5dab 100644 --- a/files/en-us/web/http/guides/client_hints/index.md +++ b/files/en-us/web/http/guides/client_hints/index.md @@ -17,18 +17,18 @@ When the browser first makes a request to load a webpage, it will send a {{httph ```http User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 -Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" Sec-CH-UA-Platform: "Android" Sec-CH-UA-Mobile: ?1 ``` These `CH-UA` headers provide the following information: -- {{httpheader("Sec-CH-UA")}}: The major browser version. +- {{httpheader("Sec-CH-UA")}}: The major browser version and other brands associated with it. - {{httpheader("Sec-CH-UA-Platform")}}: The platform. - {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is on a mobile device (`?1`) or not (`?0`). -In response, the server can announce that it supports client hints and specify the hints that it is interested in receiving using the {{HTTPHeader("Accept-CH")}} header. +In response, the server can announce that it supports client hints and specify the hints that it is interested in receiving using the {{HTTPHeader("Accept-CH")}} header (or {{HTTPHeader("Critical-CH")}}; see [Critical client hints](#critical_client_hints)). When a client that supports client hints receives the `Accept-CH` header it can choose to append some or all of the listed client hint headers in its subsequent requests. For example, following `Accept-CH` in a response below, the client could append {{HTTPHeader("Width")}}, {{HTTPHeader("Downlink")}} and {{HTTPHeader("Sec-CH-UA")}} headers to all subsequent requests. @@ -163,7 +163,7 @@ It's possible to use client hints for responsive design, for example to detect w An Android phone would send the following default client hints: ```http -Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" Sec-CH-UA-Platform: "Android" Sec-CH-UA-Mobile: ?1 ``` @@ -171,14 +171,14 @@ Sec-CH-UA-Mobile: ?1 An Android tablet on the other hand would send the following: ```http -Sec-CH-UA: "Chrome"; v="143" +Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" Sec-CH-UA-Platform: "Android" Sec-CH-UA-Mobile: ?0 ``` -The {{httpheader("Sec-CH-UA-Mobile")}} header can be used to determine whether the device is a mobile device or not. For hardware-specific use cases, the device model name can be requested via the high-entropy {{httpheader("Sec-CH-UA-Model")}} hint. +The {{httpheader("Sec-CH-UA-Mobile")}} header can be used to determine whether the device is a mobile device or not. For hardware-specific use cases, the device model name and form factor can be requested via the high-entropy {{httpheader("Sec-CH-UA-Model")}} and {{httpheader("Sec-CH-UA-Form-Factors")}} hints. -For many responsive design needs, [media queries](/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) would be more convenient and flexible. However, there may be cases where you don't have control over the individual stylesheets of a site, and need to vary the stylesheet served based on the device signature. +For many responsive design needs, [media queries](/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) may be more convenient and flexible. However, there may be cases where you don't have control over the individual stylesheets of a site, and need to vary the stylesheet served based on the device signature or some kind of user preference. There are client hints that mirror some of the "user preference" media queries, such as {{httpheader("Sec-CH-Prefers-Color-Scheme")}}, {{httpheader("Sec-CH-Prefers-Reduced-Motion")}}, and {{httpheader("Sec-CH-Prefers-Reduced-Transparency")}}. ## See also diff --git a/files/en-us/web/http/guides/user-agent_reduction/index.md b/files/en-us/web/http/guides/user-agent_reduction/index.md index 55ad2feed0d076b..23975743e8158c6 100644 --- a/files/en-us/web/http/guides/user-agent_reduction/index.md +++ b/files/en-us/web/http/guides/user-agent_reduction/index.md @@ -59,7 +59,10 @@ Also see [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Br You may still have code that relies on detailed UA string data, which can't be coverted to use feature detection or progressive enhancement. Examples include fine-grained logging, fraud prevention measures, or a software help site that serves different content based on the user's device type. -If this is the case, you can still access detailed UA string data via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers (aka **User-Agent client hints**) and other headers besides. The headers provide a safer, more privacy-preserving way to send such information because servers have to opt in to the pieces of information they want, rather it being sent all the time through the `User-Agent` string. It also provides access to a wider selection of information. +If this is the case, you can still access detailed UA string data via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers (aka **User-Agent client hints**). The headers provide a safer, more privacy-preserving way to send such information because servers have to opt in to the pieces of information they want, rather it being sent all the time through the `User-Agent` string. It also provides access to a wider selection of information. + +> [!NOTE] +> You can also [access client hint information via JavaScript](#accessing_client_hints_via_javascript). Client hints are used like so: @@ -67,41 +70,46 @@ Client hints are used like so: 2. Additionally, it will send the server a default set of `Sec-CH-UA-*` headers. The Android example we looked at earlier would send the following: ```http - Sec-CH-UA: "Chrome"; v="143" + Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" Sec-CH-UA-Platform: "Android" Sec-CH-UA-Mobile: ?1 ``` These headers provide the following information: - - {{httpheader("Sec-CH-UA")}}: The major browser version. + - {{httpheader("Sec-CH-UA")}}: The major browser version and other brands associated with it. - {{httpheader("Sec-CH-UA-Platform")}}: The platform. - {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is running on a mobile device (`?1`) or not (`?0`). -3. The server can request additional client hints using the {{httpheader("Accept-CH")}} response header, which contains a comma-delimited list of the headers it would like to receive in subsequent requests. For example: +3. The server can request additional client hints using the {{httpheader("Accept-CH")}} response header, which contains a comma-delimited list of the additional headers it would like to receive in subsequent requests. For example: ```http - Accept-CH: Sec-CH-UA, Sec-CH-UA-Platform, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Form-Factors + Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Form-Factors ``` - Here we've requested the default set of headers. We do this because each subsequent `Accept-CH` setting overrides the previous one, and we want to continue to receive the default information _in addition_ to the newly-requested information: + The default set of headers are always sent. In addition to those, we've also requested: - {{httpheader("Sec-CH-UA-Model")}}: The device model the platform is running on. - {{httpheader("Sec-CH-UA-Form-Factors")}}: The device's form factor(s), which indicate how the user interacts with the user-agent — the screen size, controls, etc. 4. If the browser is permitted to send the server all the requested information, it will do so along with all subsequent requests until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: ```http - Sec-CH-UA: "Chrome"; v="143" + Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" Sec-CH-UA-Platform: "Android" Sec-CH-UA-Mobile: ?1 Sec-CH-UA-Model: "Pixel 9" Sec-CH-UA-Form-Factors: "Mobile" ``` -Since these are hints, the browser may choose to ignore some of all of the server's requests for more information. In addition, the browser may be blocked from sending some or all of the information by various security features such as {{httpheader("Permissions-Policy")}}. +For more information, see [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). -[EDITORIAL: IS THIS TRUE? I READ THIS SOMEWHERE, BUT I CAN'T FIND ANY INFO ANYWHERE ON WHAT CAN BLOCK BROWSERS FROM SENDING CLIENT HINTS. WHAT CLIENT FEATURES CAN BLOCK SENDING CLIENT HINTS?] +### Low- and high-entropy hints -For more information, see [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). +Client hints are divided in low-entropy and high-entropy hints: + +- The default hints are considered low-entropy hints because they don't give away much information that could be used to fingerprint a user. +- All other hints are considered high-entropy — they could potentially be used for fingerprinting, so they are controlled by user preferences or by preferences such as {{httpheader("Permissions-Policy")}}. + +By default, high-entropy hints can only be sent for the top-level site (you have to opt-in to send them across cross-site frame boundaries). See [Policy-controlled features](https://wicg.github.io/client-hints-infrastructure/#policy-controlled-features) for a list of the associated `Permissions-Policy` directives. ### Critical client hints @@ -149,7 +157,7 @@ console.log(navigator.userAgentData.mobile); // Whether the browser is running on a mobile device: true or false ``` -To access so-called [high-entropy](/en-US/docs/Web/HTTP/Guides/Client_hints#high_entropy_hints) hints like `Sec-CH-UA-Model` and `Sec-CH-UA-Form-Factors`, you need to use the {{domxref("NavigatorUAData.getHighEntropyValues()")}} method. This takes an array of the requested hints as an argument and returns a promise that fulfills with an object containing the requested hint values. +To access high-entropy hints like `Sec-CH-UA-Model` and `Sec-CH-UA-Form-Factors`, you need to use the {{domxref("NavigatorUAData.getHighEntropyValues()")}} method. This takes an array of the requested hints as an argument and returns a promise that fulfills with an object containing the requested hint values. For example: diff --git a/files/en-us/web/http/reference/headers/user-agent/index.md b/files/en-us/web/http/reference/headers/user-agent/index.md index 4dfddc587bf484a..033184fa5513f83 100644 --- a/files/en-us/web/http/reference/headers/user-agent/index.md +++ b/files/en-us/web/http/reference/headers/user-agent/index.md @@ -94,7 +94,7 @@ Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0 ## Chrome UA string -The Chrome (or Chromium/Blink-based engines) user agent string is similar to Firefox's. For compatibility, it adds strings like `KHTML, like Gecko` and `Safari`. +The Chrome (or Chromium/Blink-based engines) user agent string is similar to Firefox's. For compatibility, it adds strings like `KHTML, like Gecko` and `Safari`. It adds `"CriOS/"` on iPhone. ### Examples @@ -120,7 +120,7 @@ Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51 ## Opera UA string -The Opera browser is also based on the Blink engine, which is why it almost looks the same as the Chrome UA string, but adds `"OPR/"`. For preview versions, Opera also includes a description of the particular browser edition in parentheses, for example `(Edition developer)`. +The Opera browser is also based on the Blink engine, which is why it almost looks the same as the Chrome UA string, but adds `"OPR/"` on desktop and Android, and `"OPT/"` on iPhone. For preview versions, Opera also includes a description of the particular browser edition in parentheses, for example `(Edition developer)`. ### Examples @@ -183,7 +183,7 @@ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari is based on the WebKit engine, but its UA string is also similar to the Blink-based browsers. It tends to include a `Version/xxx` string before the actual engine build version to indicate the browser release version, which unlike Blink-based browsers is different. In the case of iPhone (Mobile) Safari, the string also includes `Mobile`. > [!NOTE] -> At the time of writing, non-Apple iPhone browsers (such as Firefox, Chrome, and Edge) are still based on WebKit, therefore their UA strings are the same or similar to the Safari UA string. +> At the time of writing, non-Apple iPhone browsers (such as Firefox, Chrome, and Edge) are still based on WebKit, therefore their UA strings are similar to the Safari UA string. ### Examples From 940d0664cd62183c47728b606fc2959efb6c014e Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 Oct 2025 17:37:11 +0100 Subject: [PATCH 4/6] remove bit that doesnt really exist --- files/en-us/web/http/guides/user-agent_reduction/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/http/guides/user-agent_reduction/index.md b/files/en-us/web/http/guides/user-agent_reduction/index.md index 23975743e8158c6..8d9ff21b70ce1df 100644 --- a/files/en-us/web/http/guides/user-agent_reduction/index.md +++ b/files/en-us/web/http/guides/user-agent_reduction/index.md @@ -107,7 +107,7 @@ For more information, see [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/ Client hints are divided in low-entropy and high-entropy hints: - The default hints are considered low-entropy hints because they don't give away much information that could be used to fingerprint a user. -- All other hints are considered high-entropy — they could potentially be used for fingerprinting, so they are controlled by user preferences or by preferences such as {{httpheader("Permissions-Policy")}}. +- All other hints are considered high-entropy — they could potentially be used for fingerprinting, so they are controlled by {{httpheader("Permissions-Policy")}} headers. By default, high-entropy hints can only be sent for the top-level site (you have to opt-in to send them across cross-site frame boundaries). See [Policy-controlled features](https://wicg.github.io/client-hints-infrastructure/#policy-controlled-features) for a list of the associated `Permissions-Policy` directives. From 16832b4916388fd6ed385a3141f5f6b8ac7ecce0 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 27 Oct 2025 14:34:31 +0000 Subject: [PATCH 5/6] Fixes for hamish review comments --- .../web/api/navigator/appversion/index.md | 18 +-- .../en-us/web/api/navigator/platform/index.md | 14 +- .../web/api/navigator/useragent/index.md | 16 +- .../web/http/guides/client_hints/index.md | 51 +++--- .../http/guides/user-agent_reduction/index.md | 153 ++++-------------- .../reference/headers/user-agent/index.md | 70 ++++---- 6 files changed, 106 insertions(+), 216 deletions(-) diff --git a/files/en-us/web/api/navigator/appversion/index.md b/files/en-us/web/api/navigator/appversion/index.md index 159ddf6887aa065..5aa2c2e68d330f6 100644 --- a/files/en-us/web/api/navigator/appversion/index.md +++ b/files/en-us/web/api/navigator/appversion/index.md @@ -16,9 +16,9 @@ A string representing version information about the browser. ## Description -The `appVersion` property returns some information indicating the browser version. +The `appVersion` property returns information indicating the browser version. -In some browsers, such as Chrome, this is nearly the same as the value returned by {{domxref("Navigator.userAgent")}}, with the `Mozilla/` prefix removed. For example: +Note that the information returned varies significantly by browser. In some browsers, such as Chrome, this is nearly the same as the value returned by {{domxref("Navigator.userAgent")}}, with the `Mozilla/` prefix removed. For example: ```plain 5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 @@ -30,19 +30,9 @@ In other browsers, such as Firefox, this is cut down to a short string that hint 5.0 (Macintosh) ``` -### Browser detection +Theoretically this information is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended** for the reasons given in [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction) and [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent). -Theoretically this information is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**: - -- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. -- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). -- Browser detection lead to a situation where browsers had to return fake values from such properties in order not to be locked out of some websites. - -See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. - -### User-Agent reduction - -The information exposed in the `appVersion` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the {{domxref("Navigator.userAgent", "userAgent")}} property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). +[Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. ## Examples diff --git a/files/en-us/web/api/navigator/platform/index.md b/files/en-us/web/api/navigator/platform/index.md index 88ac189efee8525..1b77cd3905b872e 100644 --- a/files/en-us/web/api/navigator/platform/index.md +++ b/files/en-us/web/api/navigator/platform/index.md @@ -23,20 +23,16 @@ A string identifying the platform on which the user's browser is running; for ex ## Description -The `appVersion` property returns some information indicating the platform/OS the browser is running on. +The `platform` property indicates the platform/OS the browser is running on. -### Browser detection +Theoretically this information is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended** for the reasons given in [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction) and [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent). -Theoretically this information is useful for detecting the browser's underlying platform and serving code to work around OS-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**. Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. - -See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. - -### User-Agent reduction - -The information exposed in the `platform` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used (in part) to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the {{domxref("Navigator.userAgent", "userAgent")}} property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). +[Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. ## Examples +### Determining the modifier key for the user's platform + One case where `navigator.platform` can be useful is when you need to show users advice about whether the modifier key for keyboard shortcuts is the `⌘` command key (found on Apple systems) rather than the `Ctrl` control key (on non-Apple systems): ```js diff --git a/files/en-us/web/api/navigator/useragent/index.md b/files/en-us/web/api/navigator/useragent/index.md index 3c1c2698bda7518..f0d6d63b0e95ac3 100644 --- a/files/en-us/web/api/navigator/useragent/index.md +++ b/files/en-us/web/api/navigator/useragent/index.md @@ -14,23 +14,15 @@ The **`Navigator.userAgent`** read-only property of the {{domxref("Navigator")}} A string specifying the browser's complete UA string. -The browser also provides this via the {{HTTPHeader("User-agent")}} HTTP header. Parts of this information are also available in {{Glossary("HTTP")}} headers such as [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints) and other related API features such as {{domxref("Navigator.appVersion")}} and {{domxref("Navigator.platform")}}. - -The UA string is built on a formal structure, which can be decomposed into several pieces of information. For more information about the form of the UA string, see the {{HTTPHeader("User-agent")}} HTTP header. - ## Description -The `userAgent` property provides the current browser's UA string. Theoretically this is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, browser identification based on detecting the UA string is **unreliable** and **is not recommended**: - -- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. -- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). -- Even the specification asks browsers to provide as little information via this property as possible. +The `userAgent` property provides the current browser's UA string. The UA string is built on a formal structure, which can be decomposed into several pieces of information. -See [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea, and recommendations for what you should do instead. +The browser also provides the UA string via the {{HTTPHeader("User-Agent")}} HTTP header. Parts of this information are also available in {{Glossary("HTTP")}} headers such as [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints) and other related API features such as {{domxref("Navigator.appVersion")}} and {{domxref("Navigator.platform")}}. -### User-Agent reduction +Theoretically this information is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended** for the reasons given in [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction) and [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent). -The information exposed in the `userAgent` property has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, [supporting browsers](#browser_compatibility) provide a reduced set of information in their {{HTTPHeader("User-agent")}} header, the `userAgent` property, and other related properties. For more information, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). +[Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. ## Examples diff --git a/files/en-us/web/http/guides/client_hints/index.md b/files/en-us/web/http/guides/client_hints/index.md index 081801cb01e5dab..1c388490c68513e 100644 --- a/files/en-us/web/http/guides/client_hints/index.md +++ b/files/en-us/web/http/guides/client_hints/index.md @@ -13,34 +13,41 @@ The set of "hint" headers are listed in the topic [HTTP Headers](/en-US/docs/Web ## Overview -When the browser first makes a request to load a webpage, it will send a {{httpheader("User-Agent")}} header and a default set of `Sec-CH-UA-*` headers along with the initial request. An Android device, for example, might send the following: +1. When the browser first makes a request to load a webpage, it will send the {{httpheader("User-Agent")}} header to the server. +2. Additionally, it will send the server a default set of `Sec-CH-UA-*` headers; this set of hints are referred to as the [low entropy hints](#low_entropy_hints). An Android device, for example, would send something like this: -```http -User-Agent: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 -Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" -Sec-CH-UA-Platform: "Android" -Sec-CH-UA-Mobile: ?1 -``` + ```http + Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" + Sec-CH-UA-Platform: "Android" + Sec-CH-UA-Mobile: ?1 + ``` -These `CH-UA` headers provide the following information: + These headers provide the following information: + - {{httpheader("Sec-CH-UA")}}: The major browser version and other brands associated with it. + - {{httpheader("Sec-CH-UA-Platform")}}: The platform. + - {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is running on a mobile device (`?1`) or not (`?0`). -- {{httpheader("Sec-CH-UA")}}: The major browser version and other brands associated with it. -- {{httpheader("Sec-CH-UA-Platform")}}: The platform. -- {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is on a mobile device (`?1`) or not (`?0`). +3. The server can announce that it supports client hints and request additional client hints using the {{httpheader("Accept-CH")}} response header, which contains a comma-delimited list of the additional headers it would like to receive in subsequent requests. For example: -In response, the server can announce that it supports client hints and specify the hints that it is interested in receiving using the {{HTTPHeader("Accept-CH")}} header (or {{HTTPHeader("Critical-CH")}}; see [Critical client hints](#critical_client_hints)). -When a client that supports client hints receives the `Accept-CH` header it can choose to append some or all of the listed client hint headers in its subsequent requests. + ```http + Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Form-Factors + ``` -For example, following `Accept-CH` in a response below, the client could append {{HTTPHeader("Width")}}, {{HTTPHeader("Downlink")}} and {{HTTPHeader("Sec-CH-UA")}} headers to all subsequent requests. + The default set of headers are always sent. In addition to those, we've also requested: + - {{httpheader("Sec-CH-UA-Model")}}: The device model the platform is running on. + - {{httpheader("Sec-CH-UA-Form-Factors")}}: The device's form factor(s), which indicate how the user interacts with the user-agent — the screen size, controls, etc. -```http -Accept-CH: Width, Downlink, Sec-CH-UA -``` +4. If the browser is permitted to send the server all the requested information, it will do so along with all subsequent requests until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: -This approach is efficient in that the server only requests the information that it is able to usefully handle. -It is also relatively "privacy-preserving", in that it is up to the client to decide what information it can safely share. + ```http + Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" + Sec-CH-UA-Platform: "Android" + Sec-CH-UA-Mobile: ?1 + Sec-CH-UA-Model: "Pixel 9" + Sec-CH-UA-Form-Factors: "Mobile" + ``` -There is a small set of [low entropy client hint headers](#low_entropy_hints) that may be sent by a client even if not requested. +This approach is efficient in that the server only requests the information that it is able to usefully handle. It is also relatively "privacy-preserving", in that it is up to the client to decide what information it can safely share. > [!NOTE] > Client hints can also be specified in HTML using the {{HTMLElement("meta")}} element with the [`http-equiv`](/en-US/docs/Web/HTML/Reference/Elements/meta/http-equiv) attribute. @@ -78,7 +85,7 @@ For example, to stop requesting any hints it would send `Accept-CH` with an empt ## Low entropy hints Client hints are broadly divided into high and low entropy hints. -The low entropy hints are those that don't give away much information that might be used to create a [fingerprinting](/en-US/docs/Glossary/Fingerprinting) for a user. +The low entropy hints are those that don't give away much information that might be used to [fingerprint](/en-US/docs/Glossary/Fingerprinting) a user. They may be sent by default on every client request, irrespective of the server `Accept-CH` response header, depending on the permission policy. Low entropy hints are: @@ -123,6 +130,8 @@ Host: example.com Sec-CH-Prefers-Reduced-Motion: "reduce" ``` +In summary, `Accept-CH` requests all values you'd like for the page, while `Critical-CH` requests only the subset of values you must have on-load to properly load the page. + ## Hint types ### User agent client hints diff --git a/files/en-us/web/http/guides/user-agent_reduction/index.md b/files/en-us/web/http/guides/user-agent_reduction/index.md index 8d9ff21b70ce1df..2731071f08e964e 100644 --- a/files/en-us/web/http/guides/user-agent_reduction/index.md +++ b/files/en-us/web/http/guides/user-agent_reduction/index.md @@ -5,9 +5,32 @@ page-type: guide sidebar: http --- -The information exposed in the {{httpheader("User-Agent")}} HTTP header has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. To mitigate such concerns, **User-Agent reduction** provides a reduced set of information in the browser `User-Agent` header, and in related API features such as {{domxref("Navigator.userAgent")}}, {{domxref("Navigator.appVersion")}}, and {{domxref("Navigator.platform")}}. +This article explains the differences in user agent (UA) strings as a result of **User-Agent reduction**, and explains how you can access both the redacted and additional UA information if it is needed. -This article explains the differences in user agent (UA) strings as a result of User-Agent reduction, and explains modern strategies for accessing further UA information if required. +## Background + +The user agent (UA) string — available in the {{httpheader("User-Agent")}} HTTP header and in related API features such as {{domxref("Navigator.userAgent")}}, {{domxref("Navigator.appVersion")}}, and {{domxref("Navigator.platform")}} — allows servers and network peers identify the application, operating system, vendor, and/or version of the requesting {{Glossary("user agent")}}. + +### Browser detection + +Theoretically the UA string is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**: + +- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. +- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). +- Browser detection lead to a situation where browsers had to return fake values from such properties in order not to be locked out of some websites. + +The following are much more reliable strategies for working around bugs and differing browser support: + +- [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection): Detecting support for a feature, rather than the browser version. +- [Progressive enhancement](/en-US/docs/Glossary/Progressive_Enhancement): Providing a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience to browsers that can run all the required code. + +Also see [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea. + +### Privacy concerns + +In addition, the information exposed in the UA string has historically raised [privacy](/en-US/docs/Web/Privacy) concerns — it can be used to identify a particular user agent, and can therefore be used for {{glossary("fingerprinting")}}. + +To mitigate such concerns, [supporting browsers](/en-US/docs/Web/HTTP/Reference/Headers/User-Agent#browser_compatibility) implement user-agent reduction, which updates the `User-agent` header and related API features to provide a reduced set of information. ## UA string differences resulting from User-Agent reduction @@ -29,7 +52,7 @@ The below sections provide more detail about each of the US string changes. ### Platform/OS version and device model -The platform version and devce model are always represented by fixed values: +The platform version and device model are always represented by fixed values: - `Android 10; K` on Android. - `Macintosh; Intel Mac OS X 10_15_7` on macOS. @@ -41,137 +64,21 @@ The platform version and devce model are always represented by fixed values: The major browser version number shows correctly, but the minor version numbers are always shown as zeros — `0.0.0`. -## Alternatives to UA string browser sniffing - -Theoretically, the information available in the UA string is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, in addition to the privacy concerns mentioned earlier, browser identification based on detecting the UA string is **unreliable** and **is not recommended**: - -- Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. -- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). - -The following are much more reliable strategies for working around bugs and differing browser support: - -- [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection): Detecting support for a feature, rather than the browser version. -- [Progressive enhancement](/en-US/docs/Glossary/Progressive_Enhancement): Providing a baseline of essential content and functionality to as many users as possible, while delivering the best possible experience to browsers that can run all the required code. - -Also see [Browser detection using the user agent](/en-US/docs/Web/HTTP/Guides/Browser_detection_using_the_user_agent) for more information on why serving different content to different browsers is usually a bad idea. - ## Requesting detailed UA information via client hints You may still have code that relies on detailed UA string data, which can't be coverted to use feature detection or progressive enhancement. Examples include fine-grained logging, fraud prevention measures, or a software help site that serves different content based on the user's device type. -If this is the case, you can still access detailed UA string data via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers (aka **User-Agent client hints**). The headers provide a safer, more privacy-preserving way to send such information because servers have to opt in to the pieces of information they want, rather it being sent all the time through the `User-Agent` string. It also provides access to a wider selection of information. - -> [!NOTE] -> You can also [access client hint information via JavaScript](#accessing_client_hints_via_javascript). - -Client hints are used like so: - -1. When the browser first makes a request to load a webpage, it will send the reduced `User-Agent` header (as detailed earlier) to the server. -2. Additionally, it will send the server a default set of `Sec-CH-UA-*` headers. The Android example we looked at earlier would send the following: - - ```http - Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" - Sec-CH-UA-Platform: "Android" - Sec-CH-UA-Mobile: ?1 - ``` - - These headers provide the following information: - - {{httpheader("Sec-CH-UA")}}: The major browser version and other brands associated with it. - - {{httpheader("Sec-CH-UA-Platform")}}: The platform. - - {{httpheader("Sec-CH-UA-Mobile")}}: A boolean that indicates whether the browser is running on a mobile device (`?1`) or not (`?0`). - -3. The server can request additional client hints using the {{httpheader("Accept-CH")}} response header, which contains a comma-delimited list of the additional headers it would like to receive in subsequent requests. For example: - - ```http - Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Form-Factors - ``` - - The default set of headers are always sent. In addition to those, we've also requested: - - {{httpheader("Sec-CH-UA-Model")}}: The device model the platform is running on. - - {{httpheader("Sec-CH-UA-Form-Factors")}}: The device's form factor(s), which indicate how the user interacts with the user-agent — the screen size, controls, etc. - -4. If the browser is permitted to send the server all the requested information, it will do so along with all subsequent requests until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: - - ```http - Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" - Sec-CH-UA-Platform: "Android" - Sec-CH-UA-Mobile: ?1 - Sec-CH-UA-Model: "Pixel 9" - Sec-CH-UA-Form-Factors: "Mobile" - ``` +If this is the case, you can still access detailed UA string data via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers (also known as **User-Agent client hints**). The headers provide a safer, more privacy-preserving way to send such information because servers have to opt in to the pieces of information they want, rather it being sent all the time through the `User-Agent` string. It also provides access to a wider selection of information. For more information, see [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). -### Low- and high-entropy hints - -Client hints are divided in low-entropy and high-entropy hints: - -- The default hints are considered low-entropy hints because they don't give away much information that could be used to fingerprint a user. -- All other hints are considered high-entropy — they could potentially be used for fingerprinting, so they are controlled by {{httpheader("Permissions-Policy")}} headers. - -By default, high-entropy hints can only be sent for the top-level site (you have to opt-in to send them across cross-site frame boundaries). See [Policy-controlled features](https://wicg.github.io/client-hints-infrastructure/#policy-controlled-features) for a list of the associated `Permissions-Policy` directives. - -### Critical client hints - -If you need a specific set of client hints sent in your initial request for the initial page rendering to work, you can use the {{httpheader("Critical-CH")}} response header. `Critical-CH` values must be a subset of the values requested by `Accept-CH`. - -For example, the initial response may include a request for {{httpheader("Device-Memory")}} and {{httpheader("Viewport-Width")}}, where `Device-Memory` is considered critical: - -```http -GET / HTTP/1.1 -Host: example.com - -HTTP/1.1 200 OK -Content-Type: text/html -Accept-CH: Device-Memory, Viewport-Width -Vary: Device-Memory, Viewport-Width -Critical-CH: Device-Memory -``` - -This will cause the browser to send a new request for the page, including the critical hint. - -In summary, `Accept-CH` requests all values you'd like for the page, while `Critical-CH` requests only the subset of values you must have on-load to properly load the page. - ## Accessing client hints via JavaScript -The [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API) allows you to access client-hint information via JavaScript. The {{domxref("Navigator.userAgentData")}} property provides access to the {{domxref("NavigatorUAData")}} object, which contains the client hints. - -For example, if we consider our `Accept-CH` example from earlier: - -```http - Accept-CH: Sec-CH-UA, Sec-CH-UA-Platform, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Form-Factors -``` - -Once the server sends this header, provided there is nothing blocking the browser from providing this information, we can access the `Sec-CH-UA`, `Sec-CH-UA-Platform`, and `Sec-CH-UA-Mobile` values using properties on the `NavigatorUAData` object: - -```js -console.log(navigator.userAgentData.brands[0].brand); -console.log(navigator.userAgentData.brands[0].version); -// The browser and version -// For example "Chrome" and "143" +The [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API) allows you to access client-hint information via JavaScript. The {{domxref("Navigator.userAgentData")}} property provides access to the {{domxref("NavigatorUAData")}} object, which contains properties representing the low-entropy client hints. -console.log(navigator.userAgentData.platform); -// The platform/OS, for example "macOS" - -console.log(navigator.userAgentData.mobile); -// Whether the browser is running on a mobile device: true or false -``` +To access high-entropy hints like `Sec-CH-UA-Model` and `Sec-CH-UA-Form-Factors`, you need to use the {{domxref("NavigatorUAData.getHighEntropyValues()")}} method. -To access high-entropy hints like `Sec-CH-UA-Model` and `Sec-CH-UA-Form-Factors`, you need to use the {{domxref("NavigatorUAData.getHighEntropyValues()")}} method. This takes an array of the requested hints as an argument and returns a promise that fulfills with an object containing the requested hint values. - -For example: - -```js -navigator.userAgentData - .getHighEntropyValues(["model", "formFactors"]) - .then((values) => { - console.log(values.model); - console.log(values.formFactors); - // For example - // "Pixel 9" - // ["Mobile"] - }); -``` +For more information, see the [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API). ## See also diff --git a/files/en-us/web/http/reference/headers/user-agent/index.md b/files/en-us/web/http/reference/headers/user-agent/index.md index 033184fa5513f83..ae5e32c6d76af07 100644 --- a/files/en-us/web/http/reference/headers/user-agent/index.md +++ b/files/en-us/web/http/reference/headers/user-agent/index.md @@ -66,7 +66,7 @@ Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome - The device model is always a fixed value, in this case, `K`. - The Chrome major version number shows correctly, but the minor version numbers are always shown as zeros — `0.0.0`. -Servers that want to request more information can do so using [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). After the initial connection, the server can send an {{httpheader("Accept-CH")}} response header detailing the data items they want, and the client can then send the data back via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers. This information can also be accessed via the [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API). +Servers that need more information can request it via [User-Agent client hints](/en-US/docs/Web/HTTP/Guides/Client_hints). After the initial connection, the server can send an {{httpheader("Accept-CH")}} response header detailing the data items they want, and the client can then send the data back via [`Sec-CH-UA-*`](/en-US/docs/Web/HTTP/Reference/Headers#user_agent_client_hints) headers. This information can also be accessed via the [User-Agent Client Hints API](/en-US/docs/Web/API/User-Agent_Client_Hints_API). For more detailed information, including a guide to retrieving more information as required, see [User-Agent reduction](/en-US/docs/Web/HTTP/Guides/User-agent_reduction). You can also find examples of reduced `User-Agent` strings in the following sections. @@ -84,7 +84,7 @@ Mozilla/5.0 (platform; rv:gecko-version) Gecko/gecko-trail Firefox/firefox-versi 4. **_Gecko/gecko-trail_** indicates that the browser is based on Gecko. (On the desktop, **_gecko-trail_** is always the fixed string `20100101`.) 5. **_Firefox/firefox-version_** indicates that the browser is Firefox and provides the version (such as "_17.0_"). -### Examples +Desktop examples: ```plain Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 @@ -96,9 +96,7 @@ Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0 The Chrome (or Chromium/Blink-based engines) user agent string is similar to Firefox's. For compatibility, it adds strings like `KHTML, like Gecko` and `Safari`. It adds `"CriOS/"` on iPhone. -### Examples - -Desktop example: +Desktop examples: ```plain Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 @@ -112,18 +110,10 @@ Android phone example: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 ``` -#### Pre-User-Agent reduction example - -```plain -Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36 -``` - ## Opera UA string The Opera browser is also based on the Blink engine, which is why it almost looks the same as the Chrome UA string, but adds `"OPR/"` on desktop and Android, and `"OPT/"` on iPhone. For preview versions, Opera also includes a description of the particular browser edition in parentheses, for example `(Edition developer)`. -### Examples - Desktop examples: ```plain @@ -138,26 +128,10 @@ Android phone example: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Mobile Safari/537.36 OPR/92.0.0.0 ``` -#### Pre-User-Agent reduction examples - -```plain -Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41 -``` - -Older, Presto-based Opera releases used: - -```plain -Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00 - -Opera/9.60 (Windows NT 6.0; U; en) Presto/2.1.1 -``` - ## Microsoft Edge UA string The Edge browser is also based on the Blink engine. It adds `"Edg/"` on desktop platforms, `"EdgA/"` on Android, and `"EdgiOS/"` on iPhone. -### Examples - Desktop examples: ```plain @@ -172,12 +146,6 @@ Android phone example: Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36 EdgA/141.0.0.0 ``` -#### Pre-User-Agent reduction example - -```plain -Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59 -``` - ## Safari UA string Safari is based on the WebKit engine, but its UA string is also similar to the Blink-based browsers. It tends to include a `Version/xxx` string before the actual engine build version to indicate the browser release version, which unlike Blink-based browsers is different. In the case of iPhone (Mobile) Safari, the string also includes `Mobile`. @@ -185,8 +153,6 @@ Safari is based on the WebKit engine, but its UA string is also similar to the B > [!NOTE] > At the time of writing, non-Apple iPhone browsers (such as Firefox, Chrome, and Edge) are still based on WebKit, therefore their UA strings are similar to the Safari UA string. -### Examples - Desktop example: ```plain @@ -199,6 +165,36 @@ iPhone example: Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 Safari/604.1 ``` +## Pre-user-agent reduction examples + +This section provides some examples of UA strings prior to user-agent reduction: + +Google Chrome: + +```plain +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36 +``` + +Microsoft Edge: + +```plain +Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59 +``` + +Opera: + +```plain +Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36 OPR/38.0.2220.41 +``` + +Older, Presto-based Opera releases used a structure like this: + +```plain +Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00 + +Opera/9.60 (Windows NT 6.0; U; en) Presto/2.1.1 +``` + ## Crawler and bot UA strings ### Examples From cbd5dd873586ca42ccab022705e48761f6165999 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 28 Oct 2025 11:16:44 +0000 Subject: [PATCH 6/6] A few more bits of clean-up --- files/en-us/web/api/navigator/appversion/index.md | 2 +- files/en-us/web/api/navigator/platform/index.md | 2 +- files/en-us/web/api/navigator/useragent/index.md | 2 +- files/en-us/web/http/guides/client_hints/index.md | 8 ++++---- .../web/http/guides/user-agent_reduction/index.md | 12 +++++++----- .../web/http/reference/headers/user-agent/index.md | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/files/en-us/web/api/navigator/appversion/index.md b/files/en-us/web/api/navigator/appversion/index.md index 5aa2c2e68d330f6..9740a99f3dd42e6 100644 --- a/files/en-us/web/api/navigator/appversion/index.md +++ b/files/en-us/web/api/navigator/appversion/index.md @@ -12,7 +12,7 @@ The **`Navigator.appVersion`** read-only property of the {{domxref("Navigator")} ## Value -A string representing version information about the browser. +A string. ## Description diff --git a/files/en-us/web/api/navigator/platform/index.md b/files/en-us/web/api/navigator/platform/index.md index 1b77cd3905b872e..4413419cc09c9ac 100644 --- a/files/en-us/web/api/navigator/platform/index.md +++ b/files/en-us/web/api/navigator/platform/index.md @@ -12,7 +12,7 @@ The **`platform`** property read-only property of the {{domxref("Navigator")}} i ## Value -A string identifying the platform on which the user's browser is running; for example: +A string indicating a platform, for example: - `"MacIntel"` - `"Win32"` diff --git a/files/en-us/web/api/navigator/useragent/index.md b/files/en-us/web/api/navigator/useragent/index.md index f0d6d63b0e95ac3..5d0ff00fabf983a 100644 --- a/files/en-us/web/api/navigator/useragent/index.md +++ b/files/en-us/web/api/navigator/useragent/index.md @@ -12,7 +12,7 @@ The **`Navigator.userAgent`** read-only property of the {{domxref("Navigator")}} ## Value -A string specifying the browser's complete UA string. +A string. ## Description diff --git a/files/en-us/web/http/guides/client_hints/index.md b/files/en-us/web/http/guides/client_hints/index.md index 1c388490c68513e..402754764be754a 100644 --- a/files/en-us/web/http/guides/client_hints/index.md +++ b/files/en-us/web/http/guides/client_hints/index.md @@ -33,11 +33,11 @@ The set of "hint" headers are listed in the topic [HTTP Headers](/en-US/docs/Web Accept-CH: Sec-CH-UA-Model, Sec-CH-UA-Form-Factors ``` - The default set of headers are always sent. In addition to those, we've also requested: + The default set of headers is always sent; in this case, we've also requested: - {{httpheader("Sec-CH-UA-Model")}}: The device model the platform is running on. - {{httpheader("Sec-CH-UA-Form-Factors")}}: The device's form factor(s), which indicate how the user interacts with the user-agent — the screen size, controls, etc. -4. If the browser is permitted to send the server all the requested information, it will do so along with all subsequent requests until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: +4. If the browser is permitted, it will send the requested headers in all subsequent requests, until the browser or tab is closed. For example, our example Android phone might send the following updated headers with subsequent requests: ```http Sec-CH-UA: "Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24" @@ -86,7 +86,7 @@ For example, to stop requesting any hints it would send `Accept-CH` with an empt Client hints are broadly divided into high and low entropy hints. The low entropy hints are those that don't give away much information that might be used to [fingerprint](/en-US/docs/Glossary/Fingerprinting) a user. -They may be sent by default on every client request, irrespective of the server `Accept-CH` response header, depending on the permission policy. +They may be sent by default on every client request, irrespective of the server `Accept-CH` response header, depending on the [permission policy](https://wicg.github.io/client-hints-infrastructure/#policy-controlled-features). Low entropy hints are: - {{HTTPHeader("Save-Data")}}, @@ -97,7 +97,7 @@ Low entropy hints are: ## High entropy hints The high entropy hints are those that have the potential to give away more information that can be used for user fingerprinting, and therefore are gated in such a way that the user agent can make a decision whether to provide them. -The decision might be based on user preferences, a permission request, or the permission policy. +The decision might be based on user preferences, a permission request, or a [permission policy](https://wicg.github.io/client-hints-infrastructure/#policy-controlled-features). All client hints that are not low entropy hints are considered high entropy hints. ## Critical client hints diff --git a/files/en-us/web/http/guides/user-agent_reduction/index.md b/files/en-us/web/http/guides/user-agent_reduction/index.md index 2731071f08e964e..46e357538194b2a 100644 --- a/files/en-us/web/http/guides/user-agent_reduction/index.md +++ b/files/en-us/web/http/guides/user-agent_reduction/index.md @@ -5,7 +5,9 @@ page-type: guide sidebar: http --- -This article explains the differences in user agent (UA) strings as a result of **User-Agent reduction**, and explains how you can access both the redacted and additional UA information if it is needed. +**User-Agent reduction** is a broadly accepted browser initiative to reduce the amount of privacy-sensitive information provided in user agent (UA) strings. + +This article shows the differences in UA strings as a result of User-Agent reduction, and explains how you can access both redacted and additional UA information when needed. ## Background @@ -16,8 +18,8 @@ The user agent (UA) string — available in the {{httpheader("User-Agent")}} HTT Theoretically the UA string is useful for detecting the browser and serving code to work around browser-specific bugs or lack of feature support. However, this is **unreliable** and **is not recommended**: - Future browsers will fix bugs and add support for new features, so your browser detection code will need to be regularly updated to avoid locking out browsers that do actually support the features you are testing for. [Feature detection](/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection) is a much more reliable strategy. -- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and some browsers enable users to change the value of this field if they want (**UA spoofing**). -- Browser detection lead to a situation where browsers had to return fake values from such properties in order not to be locked out of some websites. +- You really have no guarantee that the user agent advertised by this property is really the one your site is loaded in. Browser vendors can basically do what they like with the UA string, and historically would return fake values from such properties in order not to be locked out of some websites. +- Some browsers enable users to change the value of this field if they want (**UA spoofing**). The following are much more reliable strategies for working around bugs and differing browser support: @@ -32,7 +34,7 @@ In addition, the information exposed in the UA string has historically raised [p To mitigate such concerns, [supporting browsers](/en-US/docs/Web/HTTP/Reference/Headers/User-Agent#browser_compatibility) implement user-agent reduction, which updates the `User-agent` header and related API features to provide a reduced set of information. -## UA string differences resulting from User-Agent reduction +## UA string changes after reduction In [supporting browsers](/en-US/docs/Web/HTTP/Reference/Headers/User-Agent#browser_compatibility), User-Agent reduction removes three pieces of information from the UA string — the exact platform/OS version, device model, and minor browser version. @@ -64,7 +66,7 @@ The platform version and device model are always represented by fixed values: The major browser version number shows correctly, but the minor version numbers are always shown as zeros — `0.0.0`. -## Requesting detailed UA information via client hints +## Requesting UA information via client hints You may still have code that relies on detailed UA string data, which can't be coverted to use feature detection or progressive enhancement. Examples include fine-grained logging, fraud prevention measures, or a software help site that serves different content based on the user's device type. diff --git a/files/en-us/web/http/reference/headers/user-agent/index.md b/files/en-us/web/http/reference/headers/user-agent/index.md index ae5e32c6d76af07..09c4a717de03eee 100644 --- a/files/en-us/web/http/reference/headers/user-agent/index.md +++ b/files/en-us/web/http/reference/headers/user-agent/index.md @@ -167,7 +167,7 @@ Mozilla/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit/605.1.15 (KHT ## Pre-user-agent reduction examples -This section provides some examples of UA strings prior to user-agent reduction: +This section provides some examples of UA strings in earlier browser versions, prior to the introduction of user-agent reduction: Google Chrome: