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.
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.
Mosaic is a desktop app
Email yourself the link and open it on your computer.
How it works: Machines that exist
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

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. Why values move inside the engine rather than in a page script is in C++, not JavaScript, and the hardware those values come from is described on real fingerprints.




