Most BrowserLeaks pages won't tell you if your result is good. You get a canvas signature or a WebGL renderer or a JA3 hash, a long table under it, and no opinion. So what do BrowserLeaks results mean? Not much until you open the same page in a browser you already trust, on the same machine, and read the two side by side. That's how Mosaic's detection tests use the site. Five of its pages we leave unscored, as reference rows, because we couldn't think of an honest score for them.
What BrowserLeaks results mean when there is no verdict
BrowserLeaks is really fourteen pages that test one thing each: Canvas, WebGL, WebGPU, Fonts, JavaScript, Client Hints, IP, DNS, WebRTC, Geolocation, Features, TLS, HTTP/2 and Proxy. Every page draws a table of what it measured. You won't find a red or green mark for the browser anywhere on them.
Take "Canvas signature 20282078e8ef". Is that fine? The page can't say. You can't either, not until you've seen what a real browser of the same kind prints on the same hardware. Or you catch the browser out: it tells the WebGL page about one GPU and the WebGPU page about another.
The rows we can score, and what we score them on
Nine of the pages give us something to compare against that we didn't have to make up. On each one, Mosaic's detection tests read the table and check a single thing:
- Canvas: draw the same image twice and compare the bytes. Chrome draws the same input the same way every time. If the signature changes between two reads, somebody is re-rolling noise. Sites spot that faster than whatever the noise was covering.
- WebGL: the unmasked renderer the page measured is the one the profile claims.
- WebGPU: the adapter's vendor is the one named inside the WebGL renderer string. If WebGPU says Apple and WebGL says NVIDIA, a site has caught one browser describing two graphics cards.
- Client Hints: the User-Agent header the server received matches the one the page reports.
- JavaScript:
navigator.userAgentmatches the session's value. - IP: the address is the profile's exit, and the country code matches what the session reported.
- DNS: with a proxy, whether the resolver is the exit; with no proxy, the row says the machine's own resolver is the correct answer and claims nothing.
- WebRTC: at most one public address on the page. This reader counts addresses; it does not yet compare the one it finds with the exit.
- Proxy: no request header names the relay.
In eight of those we already know the answer before the page loads, from the profile's own record or from the exit we measured. WebRTC we only count, so far.
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
Five rows that stay reference
That leaves Fonts, Features, Geolocation, TLS and HTTP/2. Our catalogue marks them verdict: 'reference': the page shows no verdict, and any reader we wrote would have to guess one.
- Fonts lists what the browser can render. A plausible list depends on the operating system, its version and whatever the owner installed (Office, Adobe, a game), so any cutoff we wrote would flag real people and pass fake ones.
- Features lists which web APIs exist. That list comes close to naming the exact Chromium build, and we can only read it next to a real Chrome of the same version.
- Geolocation shows the permission state, and nothing more until somebody clicks a browser prompt that no script can press. We check a profile's coordinates somewhere else, against the switch that sets them.
- TLS renders a JA3 and JA4 hash. Seeing a hash proves there was a handshake. It doesn't prove the handshake looks like Chrome's, so we do that comparison in a separate echo test that knows what to expect.
- HTTP/2 shows the SETTINGS frame and priorities. It has the same problem as TLS. You learn something only by putting it next to stock Chrome's.
For those five we keep the screenshot. We don't count a reference row as unfinished. A manual row is different: the page does show a verdict there, and we still owe the code that reads it.
How we got BrowserLeaks wrong first
Reading somebody else's page is a heuristic over their markup, and we got the heuristic wrong more than once before it held.
The first version read the page's innerText. Every BrowserLeaks page puts its answer in a table and its site menu in the body text, so a run recorded thirteen identical "results", all of them the navigation menu.
Then nine of the page ids sat in the branch written for the TLS page, which looks for rows labelled JA3, JA4 or TLS Version. The canvas, WebGL, fonts, IP, DNS, JavaScript, client hints and WebGPU pages, and an audio page BrowserLeaks has since dropped, each came back "No JA3/JA4 row in the results table". The reason sounded specific, which is why it took a while to notice it was a sentence about a table those pages never had.
The third was smaller. The JavaScript page puts a <style> element inside the first cell of its table, and reading that cell raw quoted # True<span class="false"> and a CSS rule as if they were a measurement. The reader now drops style and script children before taking a cell's text.
And one we had already paid for elsewhere: BrowserLeaks prints a country as "Austria (AT)", and matching a substring of the name makes "LATVIA".includes("AT") true. That mistake cost us two days in two other extractors, so the IP reader takes the code in brackets.
How to read your own BrowserLeaks results
The method that works without any of our tooling is the one we use:
- Open the BrowserLeaks page in the browser you are testing.
- Open the same page in a known browser on the same computer, of the same version. For a Chromium profile that means your own Google Chrome, not some other build, because an unbranded Chromium differs from Chrome in ways a page can see.
- If the profile uses a proxy, put the comparison browser on the same exit, or the IP, DNS and WebRTC pages will differ for reasons that have nothing to do with the browser.
- Change one thing, reload, and compare row by row.
Where the two browsers differ, look closer. Where they agree on something scary, relax: that's just what Chrome does on your computer. We once skipped step 2 and lost four days to it, written up in the control is Google's own build: a stock Chromium already showed the signal we had spent days blaming on our own patches.
For particular pages: what a canvas signature can and cannot identify is in what a canvas hash reveals, how to compare a TLS hash with Chrome's without being fooled by GREASE values and extension order is in comparing TLS fingerprints as sets, and how the font list is measured in the first place is in how sites detect installed fonts.





