The FingerprintJS demo reads "Chromium-Based Browser Not Available" when it can tell a browser is built on Chromium but cannot match it to a named product. For months we read that line on our own engine as a database lag, because Google's own unbranded build of the same version got the identical string. Then branded Google Chrome of that same version was named exactly, and the excuse fell apart. The variable was never the version. It was Google's branding.

When FingerprintJS reads "Chromium-Based Browser Not Available"

FingerprintJS is the commercial identifier many sites actually deploy, so its demo at fingerprint.com is a row in our detection catalogue. For a long stretch our engine, Tesseract Chrome, came back as:

Chromium-Based Browser Not Available on Mac OS X (10.15.7)

where the Google Chrome on the same Mac read Chrome 152.0.0 on Mac OS X.

The identification itself was fine. The demo issued a visitor ID, and its confidence read 0.99 to 1.0, the same as stock. Only the name failed to resolve. That made it easy to treat as cosmetic, and that was a mistake: a commercial identifier that cannot say "Chrome" about a browser claiming to be Chrome has noticed something.

The excuse, and why it looked solid

We had a control. We ran Google's own Chrome for Testing 153.0.8010.36, unmodified, through the same demo from the same machine, and it returned the byte-identical string. An untouched Google build doing exactly what ours did is normally the end of the question: the verdict is about the site, not the profile.

So the conclusion was written down as "their database has not ingested 153 yet", and the exemption was pinned to that version, set to expire on its own when the engine moved past 153.

Along the way we did fix real things. Our client hints had reported the full version as a bare 153, which no Chrome does; sending the full build number moved FingerprintJS's confidence from 1 to 0.99, which is stock's exact figure. We also tried the obvious suspects and ruled them out by measurement: Widevine made available, a 153/152/153 sweep of the claimed version on one profile, the client-hint metadata. The name did not move.

Every profile is drawn from one real computer, not from separate listsIn Mosaic: Machines that exist. GPU, screen, CPU and fonts from one real device. Free holds 3 profiles. Pro is $49 a month for any number.

How it works: Machines that exist

The control that was measuring something else

The control was taken while the Google Chrome on that Mac was still 152. The only 153 we had to compare against was Chrome for Testing, and Chrome for Testing is unbranded. So in our table, version and branding were one column, and we gave the credit to the wrong one.

Chrome updating itself to 153 split them:

BrowserFingerprintJS
Google Chrome 152, brandedChrome 152.0.0
Google Chrome 153.0.8010.52, brandedChrome 153.0.0, confidence 0.93
Chrome for Testing 153, unbrandedChromium-Based Browser
Chrome for Testing 153, field-trial config offChromium-Based Browser
Our engine 153, all switches onChromium-Based Browser

Two 153 binaries, opposite verdicts. The demo separates branded Google Chrome from unbranded Chromium, and it treats Google's own unbranded build exactly as it treats ours. IPHey was doing the same thing with its browser signal at the time, which is the other half of this story in IPHey's whale signal.

The control had a second flaw we found later. Chrome for Testing lists Chromium/153 in its brand list while its User-Agent says Chrome/153.0.0.0, so it contradicts itself, and a browser that contradicts itself cannot vouch for anyone else. Our engine launched without its brand switches has the same contradiction for the same reason. "The raw Google build fails too" was circular both times.

What we ruled out, one variable at a time

The fourth row of that table is the one worth having. --disable-field-trial-config had just removed twenty API-surface differences between our build and Chrome, so it was the obvious candidate, and it moved neither FingerprintJS nor IPHey. The twenty entries are in twenty APIs Chrome lacks; they were a real fix, just not this one.

The brand claim was ruled out too. navigator.userAgentData.brands and the User-Agent were byte-identical to branded Chrome's on the same origin: Google Chrome/153, Not_A Brand/8, Chromium/153. And a profile claiming 152, with the User-Agent and the client hints both moved, did not change the verdict.

So we stopped calling it a lag. The version gate came out of the code, because gating on the version was the wrong idea from the start: on 154 it would have expired, reopened two investigations and pointed them at something that was not the cause. The row was reported as needing attention, with the reason and the command that re-tests it, never as a pass.

Nineteen voices only Chrome lists

The largest branding difference a page can read turned out to be the speech voice list. speechSynthesis.getVoices() returned 199 entries in branded Chrome on our Mac and 180 in any unbranded build of the same version. The 180 are macOS's own voices and matched exactly. The other 19 are Google's network voices, Google US English, Google Deutsch and seventeen more, supplied by a component extension that is built in only when Chromium is compiled as Google Chrome.

One call with no permission reads the whole list. A User-Agent claiming Chrome beside a Chromium-sized voice list is not an ambiguity; it is an answer to the exact question this demo was failing to answer. Our comparison script had read that field and missed it, because it read the list before it filled in, got 0 from both browsers and called them equal; that part is in 199 voices.

Patch 0145-branded-tts-voices puts the 19 back where Chrome's own would arrive, in Chrome's order, with names recorded from a branded Chrome on the same machine. We are not claiming here that this alone makes the demo print "Chrome". What we can say is narrower: of the differences we measured between a branded and an unbranded build of one version, the voice list was the larger part, and it no longer differs.

What to take from it if you run your own checks

An excuse is only as good as the thing it controlled for. Ours had the right evidence and the wrong explanation, for as long as the machine happened to be one Chrome release behind. If FingerprintJS cannot name your Chromium-based browser, compare it with branded Google Chrome of the same version, not with Chrome for Testing or another Chromium build, because those share the very thing you are trying to find. How Mosaic draws the rest of a profile so its values agree with each other is on real fingerprints.