# Why Chrome's User-Agent says 0.0.0

> Chrome zeroes everything after the major, so the User-Agent says 0.0.0 and the build moves to Sec-CH-UA-Full-Version-List. A real build in the UA is a tell.

Source: https://mosaicbrowser.com/blog/chrome-user-agent-0-0-0

## Why Chrome's User-Agent says 0.0.0

Chrome zeroes everything after the major, so the User-Agent says 0.0.0 and the build moves to Sec-CH-UA-Full-Version-List. A real build in the UA is a tell.

![.0.0.0: The major is real, the rest is frozen](https://mosaicbrowser.com/covers/chrome-user-agent-0-0-0.webp)

Chrome's User-Agent says `0.0.0` because Chrome freezes the minor, build and patch numbers on purpose. Only the major version in `Chrome/<major>.0.0.0` is real. This is User-Agent reduction, Chromium's change to stop every request from carrying a precise version for free. The full version still exists, in client hints a site has to ask for, so a User-Agent with a real build number in it is now the anomaly.

## Why the Chrome User-Agent says 0.0.0: the reduced string

A desktop Chrome on a Mac sends this, give or take the major:

```
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<major>.0.0.0 Safari/537.36

```

Two parts of that are fixed. The version is the major followed by `.0.0.0`. The platform is frozen too: every Mac Chrome says `Intel Mac OS X 10_15_7`, on any macOS release and on Apple silicon as well as Intel. Windows Chrome says `Windows NT 10.0; Win64; x64` on Windows 10 and Windows 11 alike. Android Chrome says `Linux; Android 10; K`, with the real Android version and the phone model gone.

None of this is a bug or an old browser. If you want your real version, it is on `chrome://version`, with all four numbers.

## Where the full version went

Chrome splits what it says about itself by how much a site has to do to read it.

```
User-Agent string           Chrome/<major>.0.0.0      sent on every request
Sec-CH-UA, brands           major only                sent on every request
Sec-CH-UA-Full-Version-List major.minor.build.patch   only when the site asks

```

The bottom row is a high-entropy client hint. A server gets it by sending an `Accept-CH` response header that names it; Chrome then includes it on later requests to that site. A page gets it from JavaScript:

```
await navigator.userAgentData.getHighEntropyValues(['fullVersionList'])

```

That resolves to the brand list with full versions: `Google Chrome`, `Chromium` and a GREASE entry, the two real brands carrying the same four-part build. The older single-string field, `uaFullVersion`, still answers with the main brand's version. How each hint is requested, with the ones that must agree with the headers, is in [getHighEntropyValues explained](https://mosaicbrowser.com/blog/gethighentropyvalues-explained).

The reason for the split is passive fingerprinting. A version string with a build number on every request lets any server in the chain sort visitors by exact release without running a line of script. With reduction, a site that wants the detail has to ask, and the request sits in its response headers where anyone auditing the site can read it.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: Machines that exist](https://mosaicbrowser.com/features/real-fingerprints)

## Why a real build number in a User-Agent is the tell

Reduction turned an old habit into a mistake. User-Agent lists copied off the web, scraping libraries and browser extensions that switch the User-Agent often carry strings like `Chrome/<major>.0.<build>.<patch>`, with every number filled in. They look more real. No current Chrome sends one.

We sent one ourselves, by accident. A profile in our own app once wore a User-Agent of `Edg/153.0.8010.37` on its first launch of each session and `Edg/153.0.0.0` on every later one, because a cache decided whether the flag was passed. The first form is a version string no Edge release has put in its User-Agent. Pixelscan called the browser inconsistent. The whole run, and the cache behind it, is in [a fingerprint that depended on launch order](https://mosaicbrowser.com/blog/user-agent-launch-order).

The opposite mistake is just as visible. A browser whose full-version hint reads `153`, or `153.0.0.0`, has put the User-Agent's shape where the build belongs. Our engine once did the first of those, and fixing it moved FingerprintJS's confidence to the figure stock Chrome scored on the same machine ([a full Chrome version with no build number](https://mosaicbrowser.com/blog/full-version-without-build-number)).

So there are two shapes, and each belongs in one place:

| Where | Shape | Example |
| --- | --- | --- |
| User-Agent string, `brands` | `major.0.0.0`, or the major alone | `Chrome/153.0.0.0` |
| `fullVersionList`, `uaFullVersion` | four real numbers | `153.0.8010.37` |

A checker needs no database to compare them. It reads the major from the User-Agent, the major from `brands` and the major from the full version, and they agree or they do not. It checks that the User-Agent's tail is `.0.0.0` and the hint's tail is not.

## How Mosaic writes the two shapes

Our engine, Tesseract Chrome, takes a profile's browser version from one switch and builds both shapes from it: the User-Agent and `brands` get the major with zeros, and the full-version hints get the whole build. By default a profile claims the engine's own major, and its full version is a build Google actually shipped for that major, taken from a version table, or the engine's own build string when the table does not know it yet.

The same two shapes are why Mosaic refuses the Edge brand. One switch feeds both the User-Agent suffix and the client-hint lists, and for Edge the two could not both come out right, so a profile could have a correct User-Agent or correct hints and never both ([why we don't claim Edge](https://mosaicbrowser.com/blog/why-not-edge)).

## Checking your own browser

On any https page, open DevTools and compare the two readings:

```
navigator.userAgent
await navigator.userAgentData.getHighEntropyValues(['fullVersionList', 'platformVersion'])

```

In a stock Chrome, the User-Agent ends in `.0.0.0`, the full version list has four numbers per real brand, and all three majors match. The platform version hint carries the real OS version the User-Agent no longer does; on a Mac the processor goes the same way, which is why [an Apple silicon Mac says arm in its hints](https://mosaicbrowser.com/blog/ua-architecture-x86-arm) under an Intel User-Agent. If a browser you are testing breaks any of those, that is the finding.

## Questions

### Is my Chrome out of date if the User-Agent says 0.0.0?

No. Every current Chrome sends zeros after the major version. Your real version, with its build and patch numbers, is on chrome://version and chrome://settings/help.

### How do I get Chrome's full version number from JavaScript?

Call navigator.userAgentData.getHighEntropyValues(['fullVersionList']) on an https page. It resolves to every brand the browser lists with its four-part version, such as Google Chrome and Chromium with the same build.

### Can a server see the full Chrome version?

Only if it asks. The server sends an Accept-CH response header naming Sec-CH-UA-Full-Version-List, and Chrome includes that header on later requests to the same site. Without the request, the server sees the major alone.

### Does Chrome freeze the operating system in the User-Agent too?

Yes. Mac Chrome says Intel Mac OS X 10_15_7 whatever the macOS version and processor, Windows Chrome says Windows NT 10.0 on Windows 10 and 11, and Android Chrome says Android 10 with the model replaced by K.

## Related

[A full Chrome version with no build number is one no Chrome shipped](https://mosaicbrowser.com/blog/full-version-without-build-number): Our engine reported uaFullVersion as "153". Real Chrome always sends four numbers. Sending the full build moved FingerprintJS's confidence to stock's 0.99.

[getHighEntropyValues: what a page can ask for and what it gets](https://mosaicbrowser.com/blog/gethighentropyvalues-explained): getHighEntropyValues hands a page architecture, bitness, model and full versions on request, and each answer must match the headers Chrome sends.

[A fingerprint that depended on launch order](https://mosaicbrowser.com/blog/user-agent-launch-order): Chrome's --user-agent flag left Sec-CH-UA-Bitness empty, and a cache empty at every app start decided when we sent it. One profile wore two identities.

[Why Mosaic profiles never claim Edge](https://mosaicbrowser.com/blog/why-not-edge): Our Edge profiles sent either a full build in the User-Agent or an empty Sec-CH-UA-Bitness client hint. No real Edge sends either, so we refuse Edge.

[Our profiles said x86 and the browser said arm](https://mosaicbrowser.com/blog/ua-architecture-x86-arm): Chrome on an Apple silicon Mac sends Sec-CH-UA-Arch "arm". Our profile records said "x86", read by nothing, so we fixed the record, not the browser.

[Why every Mac's Chrome says Mac OS X 10_15_7](https://mosaicbrowser.com/blog/mac-os-x-10-15-7): Chrome froze the macOS version in its User-Agent, so every Mac claims 10.15.7. The real one is in Sec-CH-UA-Platform-Version, a hint sites must ask for.

[Why the User-Agent says Windows 10 on Windows 11](https://mosaicbrowser.com/blog/windows-11-user-agent-windows-10): Windows 11 and 10 both send Windows NT 10.0 in the User-Agent. Only the platformVersion client hint, 13 or higher, says Windows 11.

[Privacy Sandbox is retired, and its APIs are a version tell](https://mosaicbrowser.com/blog/privacy-sandbox-apis-removed): Chrome is removing Topics and Protected Audience release by release, so whether runAdAuction exists tells a page which Chrome you really are.

## Mosaic, on your own computer

The browser this blog is about: its own Chromium, fingerprints from real machines and a proxy exit per profile. Free holds 3 profiles. Pro is $49 a month for any number.

Mosaic is a desktop app

Email yourself the link and open it on your computer.
