2026-05-23 · Avery Chen · 925 words
Canvas fingerprinting on a real Windows box
Canvas output is a stable tell on real Windows ClearType. This page explains the surface and seeded noise, not a walkthrough to a green lab badge.

Canvas fingerprinting is not a screenshot of your desktop. It is a hash of how this Windows box paints text and shapes into a 2D context. ClearType, the GPU, installed faces, and the exact raster path all land in the pixels. Two towers that look identical on a spec sheet can still disagree.
I am writing the surface, not a pass-the-lab script. How we read BrowserLeaks is the place to look at a panel. This page stays on why the hash exists and why noise has to be stable.
What the page actually calls
A script creates a canvas, draws a pangram, maybe a gradient or an emoji, then calls toDataURL or toBlob. The result is a compressed image. The site hashes that image. The hash is the fingerprint.
The draw is sensitive because Windows does not paint like a textbook. DirectWrite, ClearType tuning, hinting, and the GPU path change coverage on the edges of glyphs. Subpixel antialiasing is enough. You do not need a unique wallpaper.
This is still a browser surface. It is not device fingerprinting. No disk serial is in the PNG.
| Method | What the site hashes | Why wrapping one is not enough |
|---|---|---|
toDataURL | A compressed data URL | Common demo path |
toBlob | The blob bytes | Same paint, different exit |
getImageData | Raw pixels, no compression | A third witness if left on the host |
Our inject covers toDataURL and toBlob. That is the product fact. I will not claim every read path in Chromium is wrapped. If a probe uses a path we did not name, treat it as unknown.
Why Windows makes a stable hash
The same profile on the same box should hash the same way tomorrow. Sites rely on that. If your hash jumps every reload while the user agent and GPU stay put, you look like a liar, not like a new PC.
That is why we do not reroll canvas for a prettier screenshot. The inject path wraps toDataURL and toBlob with OS-biased stable noise. The bias matters. A Windows raster that suddenly looks like a macOS raster is a coherence tell. Noise that stays put across launches is a seed. Noise that changes is a new person.

Canvas is not WebGL
Operators mash the two words because both touch the GPU. They are different APIs.
Canvas 2D is paint. WebGL is a GL context with vendor and renderer strings and a parameter table. WebGL vendor and renderer strings have to agree with the OS and the user agent. WebGPU is a third door. A canvas hash that matches a machine family can still sit next to a renderer string from the wrong family. That disagreement is the tell.
Keep the notes separate. A combo page hides the mismatch.
Fonts leak into the paint
You cannot talk about canvas on Windows without fonts. The faces you enumerate and the faces you draw are related. Font enumeration is the list. Canvas is the raster of a string you chose to draw.
An allowlist that hides a face in document.fonts.check but still draws it in canvas is another contradiction. DirectWrite raster is only partly in our hands, and only when the custom Chromium core is present with a font list. The inject path can constrain probes. It does not rewrite every glyph the GPU already knows.
Emoji and mixed scripts make the hash louder because they pull extra faces. A Latin pangram is the common demo. A string that forces Segoe UI Emoji is closer to what a real page can do.
ClearType is why two Windows boxes disagree
ClearType tuning, gamma, and the GPU path change coverage on glyph edges. A laptop on a 125 percent scale is not the same raster as a tower at 100 percent. The CSS pixel size can match and the PNG will not. That is why a copied hash from another operator's screenshot is a bad gift. You did not copy their GPU.
OS-biased noise exists so the result still looks like a Windows raster after the offset. A hash that suddenly looks like a macOS capture next to a Windows UA is the coherence failure I care about more than rarity. Uniqueness is overrated. Many Windows boxes share a family.
This is not tracking prevention. Blocking canvas is a reduce-signal move. We present a coherent Windows paint. It is also not a WebRTC problem. A WebRTC leak is an IP candidate. We have no published lab scores.
How I use the surface
When I open a profile I ask three canvas questions. Does this hash stay put after I quit. Does the paint still look like Windows. Does it agree with fonts and GPU strings in the same profile.
If you need the wider definition, start at what browser fingerprinting actually measures. The Browser fingerprinting notes take the neighboring APIs one at a time. Canvas is the one operators screenshot. It is not the only one that has to stay still.
FAQ
Is canvas the same as WebGL? No. Canvas is 2D paint. WebGL is vendor and renderer strings plus a parameter table. They can disagree even when both touch the GPU.
Should I randomize the hash every launch? No. A hash that moves while UA and GPU stay put looks broken. Seeded, OS-biased noise is the policy.
Does wrapping toDataURL cover everything? No. We also wrap toBlob. Treat unnamed paths such as getImageData as unknown.
Can I copy someone else's canvas hash? No. The number is this GPU, these fonts, and this seed.
Related notes
- WebGL vendor and renderer stringsBrowser fingerprinting
- Font enumeration leaks on WindowsBrowser fingerprinting
- How we read BrowserLeaksBrowser fingerprinting
- What device fingerprinting includes beyond the browserBrowser fingerprinting
- WebGPU as a new fingerprint surfaceBrowser fingerprinting
- What browser fingerprinting actually measuresBrowser fingerprinting
- What a WebRTC leak actually isBrowser fingerprinting
- Fingerprint spoofing versus tracking preventionBrowser fingerprinting