User Agent and Client Hints Explained
For about thirty years, the first thing your browser said to every website it visited was a short line of text describing itself. Browser name, version, operating system, and a trail of legacy tokens nobody has needed since the nineties.
That line is the user agent. For most of the web’s history it was the main way a site knew what it was talking to. It’s also the single most lied about string in the entire browser, and changing it is close to the least useful thing an anti-detect setup can do.
I run real proxy and cloud phone farms and I test how these browsers handle identification. This piece is defensive and third person: how the mechanism works and how it’s defended, not a recipe against any particular site. No undetectable promises either. This is one signal among dozens, and understanding it mostly teaches you how little it does on its own.
What the string actually is
A typical user agent claims a browser engine, a version number, a platform, and then a pile of tokens that exist purely for historical compatibility. It will often claim to be several browsers at once.
That’s not a bug. It’s thirty years of websites sniffing for a competitor’s name and browsers pretending to be that competitor so the page would render. The result is part identification, part fossil record, and almost entirely unverified.
Unverified is the important word. The user agent isn’t measured, computed, or derived from anything. The browser simply asserts it, the same way you’d fill in a form. Nothing checks it. Any extension, automation tool, or browser setting can change it in a second, and the site receives the new claim exactly as sincerely as the old one.
Why that makes it a consistency check, not evidence
Because the user agent is so easy to change, it isn’t used to establish what you are. It’s used to establish whether you’re consistent. It’s a claim to be checked against everything else, and everything else is much harder to fake.
Concretely: a user agent says Windows. But the fonts the browser exposes ship with a Mac. The graphics renderer string names Apple silicon. Measurements follow the Mac convention. The timezone is one place, the language another, the network somewhere else entirely.
Not one of those values is forbidden. The finding is the disagreement. The profile claimed Windows and the machine underneath kept answering as a Mac, and the string was the only thing that lied because the string was the only thing that could.
This is why a setup that changes the user agent and nothing else is worse off than one that changed nothing. Before, it was an ordinary Mac. Now it’s a Mac claiming to be a Windows box, which is a much smaller and much more interesting group to belong to.
Version drift
Browsers update constantly. A real population sits across a handful of recent versions, with a distribution that shifts week by week as updates roll out.
A profile pinned to a version that stopped shipping two years ago isn’t just old, it’s statistically strange, and it stays strange forever because it never moves. Worse, an old claimed version paired with modern browser features that only exist in current releases is another flat contradiction. The string says one era, the capabilities say another.
Mobile, where the string still carries weight
On Android, the user agent has traditionally included a device model token: an actual hardware name sitting in plain text. That’s far more identifying than anything in a desktop string, because it narrows you to a specific handset rather than a broad platform.
It also has to agree with a long list of other things: the screen dimensions that model actually has, the pixel ratio it ships with, the graphics renderer inside it, and the browser versions it can actually run. A claimed flagship reporting a screen size that model never shipped with is one of the easier contradictions to catch, and it’s common, because picking a model name is easy and reproducing that model’s entire measurement profile is not.
A piece of history that explains a blind spot
For years, the simplest way to catch an automated browser was to read the user agent, because headless builds announced themselves in it. There was a literal token saying “this is a headless build.” An enormous amount of detection was built on that check, and an enormous amount of evasion was built on removing it.
Both are now largely irrelevant. The token was removed from default builds, and detection moved on to behavioural and rendering signals years ago. But the folklore survived. You still find guides treating the user agent as the thing that gives automation away, and setups that carefully sanitise the string while leaking through five other channels that are actually being measured.
The honest summary: the user agent was never a strong signal. It was a convenient one. When it stopped being convenient, detection replaced it quickly and without much difficulty, which tells you how little was resting on it.
What client hints actually changed
The industry is deliberately shrinking the user agent and replacing it with client hints.
The reasoning is straightforward. The old string leaked detail to every site automatically, whether the site needed it or not, and that detail fed fingerprinting. So the approach was inverted: the browser sends a small, deliberately boring summary by default, and a site that genuinely needs more has to ask explicitly.
Those requests split into two groups:
- Low entropy — safe enough to send to everybody because they barely narrow anything down: broad platform, whether the device is mobile, coarse brand and major version.
- High entropy — the identifying ones: full version numbers, platform version, processor architecture, specific mobile model. A site has to request these.
That sounds like a privacy improvement, and in one narrow sense it is. The default surface is smaller.
But it gets oversold, so be clear about what it doesn’t do. The detail didn’t disappear. It moved behind a request any site can make, and the sites most interested in identifying you are exactly the sites that will make it. Asking is not a meaningful barrier.
What genuinely changed is that there’s now a second surface that has to stay consistent with the first. This is where tooling falls behind. A browser describes itself in two places, the shrunken legacy string and the hint values, and those have to agree with each other and with the machine underneath. A tool that rewrites the old string but leaves the hints reporting the true platform has created a fresh contradiction that didn’t exist before client hints shipped. That’s a real failure mode, it’s been common, and it’s easy to test for.
There’s an ordering detail too. Some hints arrive with the first request, others only after the site asks and the browser responds on the next one. The picture develops over a couple of round trips rather than arriving complete. A setup that’s consistent on the first request and inconsistent on the second has still been caught, just a moment later.
How it gets handled properly
Good tools treat the user agent and the client hints as one description of a single machine, generated together from the same underlying profile, and consistent with the platform signals that aren’t declared at all. Browser build, platform, version, architecture, fonts, renderer, measurement conventions and a plausible timezone all describe the same computer. Unglamorous, and the entire job.
Weak tools offer a text box. You type a user agent, it sends that user agent, and nothing else in the browser moves. That isn’t spoofing a platform, it’s putting a label on a box and hoping nobody looks inside.
There’s a middle category worth watching, because it looks convincing on a feature list. These tools generate a coherent set of values, but they generate it once, from a template, and hand the same template to everyone. Every profile gets a plausible machine, and it’s the same plausible machine. Internally consistent, externally shared, and that shared combination becomes a link between accounts meant to look unrelated. Consistency alone isn’t the goal. Consistency plus a population you blend into is the goal.
And randomising the string per session is actively harmful. A user agent that changes every visit describes someone who reinstalls a different browser every morning. It also breaks version distribution logic, because a real user’s version moves forward slowly and never backwards.
Practical checks
- Does the declared platform match the platform signals you didn’t declare?
- Is the claimed version current, and does it move forward over time rather than staying frozen?
- Do the legacy string and the client hints tell the same story, including after the high entropy ones are requested?
- Stop treating the user agent as a disguise. It hasn’t functioned as one for years.
I test these browsers on real multi account setups, and the reviews show what each tool actually sends, on both surfaces, rather than repeating what the feature list claims. They’re all here.
Get new guides and videos first — join the Telegram channel.