# Not A Brand in the Chrome user agent: how it is computed

> The Not A Brand entry in Chrome's user agent is computed from the major version by a fixed formula, so a label that doesn't fit the claimed major is a tell.

Source: https://mosaicbrowser.com/blog/not-a-brand-grease

## Not_A Brand: how Chrome's GREASE brand is computed

The Not A Brand entry in Chrome's user agent is computed from the major version by a fixed formula, so a label that doesn't fit the claimed major is a tell.

![8: Not_A Brand, version 8, at major 153, beside a screenshot: a profile fingerprint in Mosaic: GPU, screen, fonts, timezone and language matched to the exit](https://mosaicbrowser.com/covers/not-a-brand-grease.webp)

The "Not A Brand" entry in Chrome's user agent is not random and not a bug. It is a GREASE brand, a deliberately meaningless entry that Chrome adds to `navigator.userAgentData.brands` and the `Sec-CH-UA` header, and Chrome computes it from its own major version with a fixed formula. Every Chrome of one major sends the same label, the same version and the same order, which means a site can work out what that entry should be and check it.

GREASE stands for "generate random extensions and sustain extensibility". The idea comes from TLS: if clients always send a few junk values, servers that choke on anything unexpected get found and fixed early. The User-Agent Client Hints proposal asks browsers to do the same with brands, so that no site writes `if (brands.length === 2)` and breaks the day a third one appears.

## How Chrome computes the Not A Brand entry in its user agent

The code lives in Chromium's user agent utilities, and the patch our engine carries for the user agent uses the same tables. There are three inputs, and all of them come from the major version, which Chromium uses as the seed:

```
characters   " "  "("  ":"  "-"  "."  "/"  ")"  ";"  "="  "?"  "_"
versions     "8"  "99"  "24"

label    = "Not" + characters[major % 11] + "A" + characters[(major + 1) % 11] + "Brand"
version  = versions[major % 3]
order    = one of the 6 permutations of the three brands, picked by major % 6

```

In the full version list (`fullVersionList` in JavaScript, `Sec-CH-UA-Full-Version-List` on the wire) the GREASE version gets `.0.0.0` appended, so an 8 becomes `8.0.0.0`. The real brands carry the real build number there.

Worked through for a few majors:

| Major | major % 11 | Label | Version |
| --- | --- | --- | --- |
| 144 | 1 | `Not(A:Brand` | 8 |
| 152 | 9 | `Not?A_Brand` | 24 |
| 153 | 10 | `Not_A Brand` | 8 |
| 154 | 0 | `Not A(Brand` | 99 |
| 155 | 1 | `Not(A:Brand` | 24 |

The table has eleven characters and the versions repeat every three, so the same label comes back every eleven releases but with a different version beside it. That is why 144 and 155 share `Not(A:Brand` and still differ.

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)

## We checked it twice, because it looked wrong both times

While we were chasing a detector verdict in September 2026, our engine was on major 153 and the Google Chrome on the same Mac was on 152. Ours read `Not_A Brand` version 8. Stock read `Not?A_Brand` version 24. Two browsers that should match, with a different brand in the list, looks exactly like the cause you are hunting for.

It was arithmetic. 153 modulo 11 is 10, which is `_`; 154 modulo 11 is 0, which is a space; 153 modulo 3 is 0, which is `8`. The stock result works out the same way for 152. Read through the app on a real profile, the whole set came out as Chrome computes it:

```
brands           Google Chrome 153, Not_A Brand 8, Chromium 153
fullVersionList  Google Chrome 153.0.8010.37, Not_A Brand 8.0.0.0, Chromium 153.0.8010.37

```

The order checks out too. 153 modulo 6 is 3, and that permutation puts Google Chrome first and Chromium last, with the GREASE entry between them.

The second time was a bare launch of the engine binary without the switches Mosaic passes, used to start a bisect. It reported `Not(A:Brand` version 8 next to a Chromium 144 left in an old table. The brand matched the formula for 144, so the GREASE entry was consistent with the stale version. The stale table was the bug, and it sat on a path no profile takes: the launcher always passes the switches that replace it.

## What a site can check

None of this identifies a person. What it does is give a site a free consistency test, because the right answer can be derived from the version the browser claims. A browser fails it in a few distinct ways:

- The label belongs to a different major. A spoof that copied a brand list from one Chrome and bumped the version numbers keeps the old punctuation.
- The version is not 8, 99 or 24, or is the wrong one of the three for that major.
- The three entries are in an order Chrome would not produce for that major, or the list has two entries where branded Chrome has three.
- The full version list gives the GREASE entry a real build number, or gives the real brands none.
- The page says one thing and a service worker says another, because the spoof lived in page JavaScript and the worker never ran it.

The fourth item has a sibling we got wrong ourselves. Our engine was once sent the major alone where it needed the full version, so `uaFullVersion` read `153` where a stock Chrome reads something like `152.0.7977.83`. No Chrome has ever reported a full version with no build number. Once the launcher sent all four parts, FingerprintJS's confidence moved from 1 to 0.99, which was the exact figure stock Chrome got. A field nobody looks at was being read.

## How Mosaic gets it right

Tesseract Chrome, our own Chromium, computes the brand list in C++ from the version the profile claims, using Chrome's own tables. The page, every frame, every worker and the `Sec-CH-UA` header are all built from that one list, so there is no second copy to disagree with the first. Nothing is overridden in JavaScript, which is the reason in [why we change fingerprints in C++](https://mosaicbrowser.com/blog/cpp-not-javascript). Mosaic also refuses to claim Edge, because one switch feeds both the client-hint versions and the User-Agent suffix and Edge needs them in two different shapes.

If you want to check a browser yourself, read `navigator.userAgentData.getHighEntropyValues(['fullVersionList'])` in its console, take the major, and run the formula above. The label, the version and the position should all come out the same. When they do and a detector still complains, the next suspect is branding rather than the brand list: [the FingerprintJS demo that could not name our browser](https://mosaicbrowser.com/blog/fingerprintjs-cannot-name-browser) turned out to be about Google's branded build, and [running Google's own unbranded build as the control](https://mosaicbrowser.com/blog/the-control-is-googles-build) is how we told the two apart. The other values that make up a [browser fingerprint](https://mosaicbrowser.com/glossary/browser-fingerprint) are worth the same kind of check.

## Questions

### What is "Not A Brand" in Chrome's user agent?

It is a GREASE entry: a fake brand Chrome adds to navigator.userAgentData.brands and the Sec-CH-UA header so that sites cannot rely on an exact brand list. It carries no information about you.

### Is the Not_A Brand entry random?

No. Chrome computes the punctuation, the version and the position in the list from the major version number. Every Chrome of one major sends the same entry in the same place.

### Why does my Chrome say Not?A_Brand and another says Not_A Brand?

They are different major versions. The two punctuation characters are picked from an 11-character table by the major modulo 11, so the label changes with every release.

### Can a site use the GREASE brand to spot a fake browser?

It can check that the label, its version and the order of the brands are the ones Chrome would compute for the major the browser claims. A spoof that copies an entry from a different version, or invents one, fails that check.

## Related

[When the FingerprintJS demo can't name your browser](https://mosaicbrowser.com/blog/fingerprintjs-cannot-name-browser): FingerprintJS read 'Chromium-Based Browser Not Available' for our engine. We blamed the version; the real variable was Google's branding.

[The control that settles "is it our patches?"](https://mosaicbrowser.com/blog/the-control-is-googles-build): Unpatched Chrome for Testing got the same IPHey verdict as our engine, so our patches were not the cause. Its voice list still differs from Chrome's.

[Why we change fingerprints in C++, not JavaScript](https://mosaicbrowser.com/blog/cpp-not-javascript): A JavaScript spoof is one realm deep. An iframe read the real source of 33 of our patched functions; the same values changed in C++ agree everywhere.

[Browser fingerprint: what a site can read about your machine](https://mosaicbrowser.com/glossary/browser-fingerprint): A browser fingerprint is the set of values a site reads about your browser and computer, which together recognize you without cookies. What goes into one.

[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.

[Why Chrome's User-Agent says 0.0.0](https://mosaicbrowser.com/blog/chrome-user-agent-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.

[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.
