# Chrome for Testing vs Chrome as a fingerprint control

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

Source: https://mosaicbrowser.com/blog/the-control-is-googles-build

## The control that settles "is it our patches?"

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.

![90 s: One 90-second run would have saved four days, beside a screenshot: a Mosaic leak test: every surface a site reads, checked from inside the profile page](https://mosaicbrowser.com/covers/the-control-is-googles-build.webp)

Chrome for Testing and Google Chrome are built from the same source, but they do not have the same fingerprint, and that difference decides what each one can prove. Chrome for Testing is Google's unbranded build: the right control for "is this caused by our patches?" and the wrong one for "does this look like Chrome?". We spent four days on a detector signal before running the first question, and the answer took ninety seconds.

## Four days on the wrong assumption

IPHey scored every Mosaic profile Unreliable, 90 out of 100, with one signal on its browser card: an inconsistent browser fingerprint. A branded Google Chrome on the same Mac scored Trustworthy. So we assumed something in our patch series caused it, and went looking.

The search was thorough. We compared the JavaScript surface, then property descriptors, then enumeration order. We captured the TLS ClientHello with a raw listener and compared it field by field. We compared the HTTP/2 SETTINGS frame and header order. We tried claiming the real stable build number instead of ours. Every layer came back identical to branded Chrome, and the verdict did not move.

What would have ended it on day one was Google's own unpatched Chrome for Testing 153.0.8010.36, pointed at the same page. It earns the identical verdict. None of our patches are in it, so none of them can be the cause. One run rules out the whole series, and it should have been the first run rather than the last.

Mosaic is a desktop app

Email yourself the link and open it on your computer.

[How it works: Its own Chromium](https://mosaicbrowser.com/features/engine)

## What Chrome for Testing answers, and what it cannot

A control answers one question, and it is worth writing down which before trusting it.

Chrome for Testing shares the source and the branding flag with our engine and has none of our changes. So it isolates the patches. If it gets the verdict too, the cause is either in stock unbranded Chromium or in the environment, and bisecting our series would have been days of rebuilds searching for something no patch was responsible for.

It cannot answer whether a browser looks like Chrome, for two reasons we measured.

First, it contradicts itself. Its brand list read `Chromium/153, Not_A Brand/8` while its User-Agent read `Chrome/153.0.0.0`. A browser whose client hints disagree with its own User-Agent raises an inconsistency signal on its own account. So "the untouched Google build fails too" was true and circular at the same time, and we used that argument twice before noticing.

Second, its version and its branding were tangled. An earlier control had been taken while the machine's Google Chrome was still on 152, so the only 153 to compare against was unbranded. Version and branding were one column, and the wrong one got the credit: we wrote that the detector had not learned the new major yet. When Chrome updated to 153, two binaries of the same major got opposite verdicts, and the real variable showed itself.

## What a branded control found

With the right control in place, branded Chrome on the same machine and page, the difference was one call. `speechSynthesis.getVoices()` returns 199 voices on branded Chrome and 180 on any unbranded build of the same version. The missing 19 are Google's network voices, `Google US English`, `Google Deutsch` and the rest, supplied by a component that ships only when Chromium is compiled as Chrome.

Our comparison script had read the voice list, got 0 from both browsers because it read before the list loaded, and carried an exemption saying the field races the probe. Patch `0145-branded-tts-voices` now restores the 19 voices in our engine, where the component's own would arrive.

## The same rule, at smaller scale

The rule held on a much smaller question too. A check reported our engine's `AudioContext.outputLatency` as 0 against a claimed 0.0053, which looked like a broken patch. Branded Chrome 154, same page, same click, also answered 0 until real audio had played, and 0.024 after 1.2 seconds of it. The engine was reproducing Chrome exactly; the check was reading before the value existed. One launch of the control settled it in minutes.

So our order of questions is now fixed. First, does unpatched Chromium of the same major do it? That rules our patches in or out. Then, does the Google Chrome people run do it? That says whether the result is about looking like Chrome at all. A single third-party verdict is not evidence either way, so both get several rounds.

The first difference that branded control found, twenty APIs switched on by a test config, is written up in [twenty APIs Chrome doesn't have](https://mosaicbrowser.com/blog/twenty-apis-chrome-lacks). The same kind of control showed a detector flagging an untouched Chrome in [Pixelscan calls stock Chrome masked](https://mosaicbrowser.com/blog/pixelscan-masks-stock-chrome), and the case for owning the engine at all is in [why we built our own Chromium](https://mosaicbrowser.com/blog/why-we-built-our-own-chromium).

## Questions

### Does Chrome for Testing have the same fingerprint as Chrome?

No. It is an unbranded build, so it lacks things that ship only in Google Chrome, such as 19 Google network voices: 180 voices against branded Chrome's 199 on our Mac. Its brand list also said Chromium while its User-Agent said Chrome.

### When is Chrome for Testing the right control?

When the question is whether a patch of yours causes a result. If Google's own unpatched build gets the same verdict, your patches are ruled out in one run.

### When is it the wrong control?

When the question is whether a browser looks like Chrome. For that the control has to be the Google Chrome real people run, the same major, on the same machine and network.

### How long does a control run take?

About 90 seconds on our machine for one IPHey run. Because a single third-party verdict is not evidence, we repeat it for several rounds, which is still minutes rather than days.

## Related

[Twenty APIs Chrome doesn't have: Chromium's field trials](https://mosaicbrowser.com/blog/twenty-apis-chrome-lacks): Unbranded Chromium runs its field-trial testing config at every launch. Against Chrome 153 that was 20 API differences, and one switch moved them all.

[Pixelscan calls a stock Chrome masked 3 times in 20](https://mosaicbrowser.com/blog/pixelscan-masks-stock-chrome): A Pixelscan false positive, measured: an untouched Google Chrome read 'Masking detected' on 3 of 20 runs. Our fresh profiles read it once in 74.

[Why we built our own Chromium instead of injecting JavaScript](https://mosaicbrowser.com/blog/why-we-built-our-own-chromium): Mosaic changes fingerprint values in C++ inside its own engine. Three measured differences between Chrome and plain Chromium explain why that matters.

[Runtime.enable flips a detector, so we don't call it](https://mosaicbrowser.com/blog/runtime-enable-detection): Runtime.enable detection, measured: one DevTools command turned a clean Mosaic profile into isBot=true on deviceandbrowserinfo. We removed all five calls.









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