An Edge profile on our engine could have a correct User-Agent or a correct set of client hints, never both. Without one flag its User-Agent carried the full build number, which no Edge sends. With that flag, Sec-CH-UA-Bitness came back empty, which no browser sends. Each is a User-Agent and client hints mismatch a site can read in one request, so Mosaic profiles claim Chrome and asking for Edge is refused.
The report that started it
Pixelscan marked one Windows profile "Your Browser Fingerprint is inconsistent", with its browser card red and reading Edge 153.0.8010.37 on Windows. A second run of the same report read Edge 153.0.0.0. One profile, two runs, two browsers: the shape of every bug report that arrives as "sometimes".
We launched the same Edge profile twice and read the headers off a local server:
without --user-agent UA Edg/153.0.8010.37 Sec-CH-UA-Bitness "64"
with --user-agent UA Edg/153.0.0.0 Sec-CH-UA-Bitness ""
Neither row is a real browser. Chromium browsers now reduce the User-Agent to the major version followed by zeros, so an Edge User-Agent never carries the build number 8010.37. And an empty bitness beside a filled-in Sec-CH-UA-Arch is what Chromium sends when it has been handed a User-Agent string it did not build itself and refuses to vouch for the high-entropy hints. So the two choices were a wrong User-Agent or a wrong bitness.
Why it changed between runs
Mosaic passed --user-agent only when a profile's string differed from the engine's own, and it learned the engine's own string from an in-memory cache that is empty every time the app starts. The first profile launched in a session went out without the flag. Every later launch had it. One profile, three launches after a restart:
launch 1 Edg/153.0.8010.37
launch 2 Edg/153.0.0.0
launch 3 Edg/153.0.0.0
A profile that presents two identities is worse than either one, because a site that has seen it twice holds both. The cache half of this story, and how it affected Chrome profiles too, is told in one profile wore two identities.
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
One switch meaning two things
The root cause sat in our engine patch. --fingerprint-brand-version is the only place the engine gets the version for the client-hint lists, and those need the full build, 153.0.8010.37. Sending the full build is what let FingerprintJS name the browser correctly. But the same value was also pasted, unchanged, onto the end of the User-Agent as the Edge suffix, and that part needs 153.0.0.0.
The patch already knew the reduced form. It carried kEdgeUAVersion = "153.0.0.0" beside kEdgeDefaultVersion = "153.0.8010.37", and used the reduced one only when the switch was absent. We have to send the switch for the hints, so we always took the other path.
Chrome profiles never showed any of this, because Chrome has no suffix. The engine builds a Chrome profile's User-Agent byte for byte from the platform it claims, with no --user-agent at all. Three cold launches of a fresh Windows Chrome profile: the User-Agent matched the stored string every time, and Sec-CH-UA-Bitness read "64" every time.
What we changed
Edge is refused. Before this, 14% of Windows profiles were drawn as Edge. Now none are, and a request that names Edge gets a 400 that quotes both measurements, not a terse list of allowed values. The same refusal sits under the app, the REST API and MCP, because a rule enforced at one door is enforced nowhere. A build check, check:brand, holds it from three sides: the generator draws only browsers the engine can be, the shared entry point refuses anything else by name, and the patch that would let Edge back must carry the reduction.
The patch is fixed for a later engine. A function now cuts a build number down to major.0.0.0 before it reaches the suffix, so one switch can feed both shapes. Edge comes back only when an engine built from that patch has been measured sending both right.
A 500 became a 400. The first version of the refusal threw a plain error from the fingerprint generator, and the API reported it as an internal error. A sentence written for the caller is a 400, so both error classes now come from one small module that imports nothing.

What a claimed browser has to survive
The general rule is the reason we built our own Chromium in the first place: every value a page reads has to agree with every other value, from every place it can be read. A brand is a claim in at least four places: the User-Agent, the low-entropy client hints, the full version list and the bitness. Our engine can make all four agree for Chrome. For Edge it could make three, which is a contradiction, and a contradiction is worse than a common answer.
So every profile is drawn as a Chrome, from hardware records of real machines, at the version the engine really is. What a site can read from a browser, and why it adds up to a browser fingerprint, is the background to all of this.




