User-Agent and Client Hints: what your browser announces to every site

Before a website shows you a single pixel, your browser has already announced who it is. The User-Agent string and the newer User-Agent Client Hints travel with every request, describing your browser, version, operating system, and sometimes your device and CPU architecture. This article explains what these signals actually contain, how the industry shifted from the bloated old User-Agent to a structured Client Hints system, where each is readable, and why the common reflex to spoof your User-Agent usually makes your fingerprint worse rather than better.

The User-Agent string and its baggage

The User-Agent (UA) is an HTTP header sent with every request and also readable in JavaScript via navigator.userAgent. A typical desktop Chrome string looks like Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36.

Almost none of that is honest. The Mozilla/5.0 prefix, the AppleWebKit and KHTML, like Gecko tokens, and the trailing Safari are historical fictions that browsers carry to avoid being mis-served by old sites that sniff for specific keywords. Buried in the noise is the genuinely identifying information: the platform (Windows NT 10.0; Win64; x64), the engine, and the browser version. A detailed UA string can carry on the order of 10 bits of entropy, especially when it includes a precise version number and an unusual platform such as a specific Linux distribution or an older OS release.

The shift to UA reduction

The fine-grained detail in the UA, in particular the exact patch version and the full OS version, was a privacy liability and was rarely needed for legitimate purposes. Chrome led a multi-year programme of User-Agent reduction, freezing and truncating the string so it reveals far less. In reduced form the minor version is zeroed (you see 124.0.0.0 rather than the true build), the OS version is capped, and device model details on mobile are replaced with a generic token. Other Chromium-based browsers followed, and the practical effect is that the legacy UA now leaks less than it once did.

Reduction does not abolish the UA, because too much of the web still parses it. Instead the precise details migrated into a new, opt-in mechanism designed to hand out information only when a site actually asks: User-Agent Client Hints.

User-Agent Client Hints (UA-CH)

Client Hints are a set of HTTP request headers, prefixed Sec-CH-UA, plus a matching JavaScript API at navigator.userAgentData. The design splits the data into low-entropy hints sent by default and high-entropy hints provided only on demand.

Low-entropy hints, sent by default

These are considered safe enough to send with every request because they barely narrow you down:

  • Sec-CH-UA — the browser brand and major version, e.g. "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99". The deliberately fake "Not-A.Brand" entry exists to stop sites hard-coding brand lists.
  • Sec-CH-UA-Mobile — a boolean, ?0 or ?1, indicating mobile or not.
  • Sec-CH-UA-Platform — the OS family, e.g. "Windows" or "macOS", but not the version.

High-entropy hints, requested on demand

The detailed values are withheld unless a site explicitly asks for them, by sending an Accept-CH response header listing the hints it wants, after which the browser includes them on subsequent requests. These include:

  • Sec-CH-UA-Platform-Version — the precise OS version.
  • Sec-CH-UA-Arch — CPU architecture, e.g. "x86" or "arm".
  • Sec-CH-UA-Bitness — 32 or 64 bit.
  • Sec-CH-UA-Model — the device model, chiefly relevant on mobile.
  • Sec-CH-UA-Full-Version-List — the full, unredacted version numbers of each brand.

In JavaScript the same split appears: navigator.userAgentData exposes the low-entropy fields synchronously, while getHighEntropyValues(['platformVersion', 'architecture', 'model', 'fullVersionList']) returns the detailed set via a promise.

How this helps and how it hurts privacy

The on-demand model is a genuine improvement in principle. By default a site learns only your browser brand, major version, platform family, and mobile status, which is much less than the old UA leaked. Sites that never request high-entropy hints simply never receive the precise version or architecture.

The catch is that asking is cheap and invisible to the user. A fingerprinting script only has to send one Accept-CH header or make one getHighEntropyValues call to recover essentially everything the old UA exposed, with no prompt and no indication to you. There is no consent dialog. So for a site that wants the data, UA-CH provides it just as readily; the privacy gain accrues mainly against passive collectors and lazy third parties that never bother to ask. privacyscore.dev checks both your legacy UA and the high-entropy Client Hints your browser will surrender on request, so the score reflects what a determined site can actually obtain, not just what is sent by default.

Server-side versus client-side access

An important and often missed detail: Client Hints distinguish where data can be read. The headers are sent to the top-level site and, with delegation, to specific third parties the site permits via the Accept-CH and Permissions-Policy mechanism. This gives the first-party server some control over which embedded third parties receive hints, which is more than the old UA allowed, since the UA header went to everyone unconditionally. The JavaScript API, by contrast, is available to any script running in the page, including third-party scripts, subject to the same delegation rules for high-entropy values. The upshot is that hint delivery is more governable than the legacy UA, but a script you have allowed to run can still ask.

Why spoofing your User-Agent usually backfires

The intuitive defence is to change your UA to something common or misleading. In practice this is one of the most reliable ways to make your fingerprint worse, for three reasons.

Inconsistency is itself a signal

Your UA is only one of dozens of observable properties. If your UA claims Windows but navigator.platform, your Client Hints platform, your font rendering, your WebGL renderer string, and your timezone all say macOS or Linux, the contradiction is glaring. Genuine users almost never present these mismatches, so a contradictory configuration is rarer, and therefore more identifiable, than an honest one. Fingerprinters actively look for UA-versus-reality mismatches as a high-confidence flag.

UA and UA-CH can disagree

A naive spoofer changes the legacy UA string but forgets navigator.userAgentData, or vice versa. A site that reads both immediately sees that your old UA says one thing and your Client Hints say another, which no normal browser does. The two surfaces must agree, and keeping them perfectly consistent across every property is far harder than it looks.

You leave the herd

The goal of anti-fingerprinting is to look like as many other people as possible. A custom or rotating UA, especially a rare or malformed one, puts you in a tiny bucket of users who present that exact string. Rotation is worse still: a browser whose UA changes between requests but whose canvas hash, fonts, and timezone stay fixed is trivially re-linked and now also flagged as suspicious.

What to do instead

  • Use a browser that normalises these signals for everyone. Tor Browser presents a uniform UA and platform across its entire user base, so you blend in by design rather than by hand-editing strings.
  • Prefer built-in protections over manual spoofing. Firefox's resistFingerprinting spoofs the UA and related values in a coordinated, consistent way so the surfaces do not contradict each other.
  • If you must change the UA, change everything together. A serious anti-fingerprinting tool aligns the legacy UA, navigator.userAgentData, platform, and related properties so they tell one coherent story. Half-measures are detectable.
  • Measure before and after. Confirm with a tool such as privacyscore.dev that a change actually lowered your uniqueness, rather than swapping one rare signal for another.

The honest summary is that your browser tells every site a great deal about itself, the platform has made that disclosure more structured and slightly more private, and the worst thing you can do is lie clumsily. Consistency and crowd-blending beat clever spoofing every time.