# Chromium field trial config as a fingerprint

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

Source: https://mosaicbrowser.com/blog/twenty-apis-chrome-lacks

## Twenty APIs Chrome doesn't have: Chromium's field trials

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.

![20: Twenty APIs a page could find on us and not on Chrome, beside a screenshot: mosaic settings showing the installed Tesseract Chrome engine and its version](https://mosaicbrowser.com/covers/twenty-apis-chrome-lacks.webp)

An unbranded Chromium build compiles a file called `fieldtrial_testing_config.json` into the binary and applies it at every launch. Google Chrome does not run that file. So a Chromium with the field trial config on carries experiments no Chrome user has, and a page can find them by listing properties. Against the Google Chrome 153 on our build Mac, that was twenty differences, and `--disable-field-trial-config` moved all of them.

## How we found twenty differences after weeks of none

We keep a check, `check:stock`, that launches our engine and a stock browser of the same major and compares what a page can read. It had been clean for weeks. Its baseline was Chrome for Testing 153, Google's unbranded build for automation, which a real person does not browse with.

Pointed at the machine's own Google Chrome 153, the browser people actually run, it reported twenty unexplained differences in one run:

```
missing here   navigator.runAdAuction, joinAdInterestGroup,
               protectedAudience, adAuctionComponents and nine more
               Document.browsingTopics
               window.XSLTProcessor
added here     window.ModelContext
               window.WebMCPEvent

```

The navigator entries are Chrome's Protected Audience API. The two added ones are worse. A missing API is ambiguous, because an old build or an enterprise policy could explain it. An API a page finds on you and not on Chrome is a positive identification, and a browser claiming Chrome 153 that carries `window.WebMCPEvent` has answered the question before any canvas is drawn.

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)

## Two theories that were wrong first

The obvious theory was the variations seed, the experiment list Chrome downloads from Google. We launched a branded Chrome on a fresh profile with no cached seed and the variations server unreachable. It still had the full set. Not the seed.

The second theory was branding: that these APIs come with being Google Chrome and an unbranded build cannot have them. Chrome for Testing settled that. It is unbranded, the same major, with the same config compiled in, and it matched our engine on all twenty. With `--disable-field-trial-config` added, it matched branded Chrome on all twenty. Not branding either.

That is the useful part of the result. The difference was one switch away the whole time, on Google's own unbranded build as much as on ours.

## Two probe mistakes on the way

Both runs that went wrong went wrong the same way: the probe changed the answer.

The first asked `'runAdAuction' in Navigator.prototype` on `about:blank`, and every browser said no. The Protected Audience members are marked `[SecureContext]`, and a top-level `about:blank` has an opaque origin, so none of them exist there in any browser. Reading a secure-context API on a page that is not one, and reporting the absence, is a mistake we have now made twice.

The second tested `--enable-field-trial-config` on Chrome for Testing, which already had the config on. A switch that changes nothing because it was already the state is not a negative result.

## Order is a fingerprint too

Later we stopped sorting. Every name list we compared had been `Object.getOwnPropertyNames(...).sort()`, and a sorted diff cannot see enumeration order, which a page can read. Compared unsorted, with the trial config left on, the order differences were the same twenty entries: `ModelContext` sitting between `ServiceWorkerContainer` and `NotRestoredReasonDetails` on `window`, and `modelContext` where `browsingTopics` should be on `Document.prototype`.

With the switch on, our engine listed its properties in exactly the order as branded Chrome across `window`, `Navigator`, `Screen`, `Document`, `Element`, `Performance`, `CanvasRenderingContext2D`, `WebGL2RenderingContext`, `MediaDevices` and `window.chrome`.

## What the switch did not fix

At the time, IPHey scored our profiles Unreliable with a browser signal, and the field trials were the obvious suspect. We tried the switch on Chrome for Testing with the config off. It moved neither IPHey's verdict nor FingerprintJS's. Ruling out the best hypothesis was worth having, and that signal turned out to be something else.

## Turning off the field trial config, on every launch

![Mosaic's Settings › Engine panel showing the installed Tesseract Chrome](https://mosaicbrowser.com/shots/engine.png)
*Tesseract Chrome, launched with the trial config off*

Tesseract Chrome, Mosaic's engine, gets `--disable-field-trial-config` on every launch, and `check:preferences` fails our build if the switch ever stops being sent. We also changed what `check:stock` compares against: the machine's own Google Chrome, not a build nobody runs. A check is only as good as its baseline, and ours had stayed green for weeks against the wrong one.

Field trials are one of three differences between plain Chromium and Chrome that we have measured. The other two, the speech voice list and Widevine, are in [why we built our own Chromium](https://mosaicbrowser.com/blog/why-we-built-our-own-chromium). Why values move inside the engine rather than in a page script is in [C++, not JavaScript](https://mosaicbrowser.com/blog/cpp-not-javascript), and the hardware those values come from is described on [real fingerprints](https://mosaicbrowser.com/features/real-fingerprints).

## Questions

### What is fieldtrial_testing_config.json?

A file of experiment settings in the Chromium source. An unbranded Chromium build compiles it in and applies it at every launch, so it switches on trials and features that Google Chrome, which does not run that file, leaves off.

### How do I turn off the field trial testing config?

Launch Chromium with --disable-field-trial-config. On our build it moved all twenty API differences we had measured against Google Chrome 153 in one step.

### Can a website see field trials?

Not the trial names, but it can see what they switch on. A page that lists properties on window, Navigator or Document finds APIs that exist or are missing, and the order they are listed in, which is enough to tell a trial-config Chromium from Chrome.

### Does Mosaic send --disable-field-trial-config?

Yes, on every launch of its own engine, Tesseract Chrome. A check in our build fails if the switch ever goes missing.

## Related

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

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

[Machines that exist: fingerprints drawn from real hardware](https://mosaicbrowser.com/features/real-fingerprints): Mosaic draws each profile's GPU, screen, CPU, memory and fonts from one real device, so the parts of a fingerprint agree with each other and with the host.

[What is an anti-detect browser?](https://mosaicbrowser.com/guides/what-is-an-anti-detect-browser): An anti-detect browser gives each profile its own fingerprint, proxy and cookies, so sites see separate visitors. What it changes, how, and its limits.









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