Canvas fingerprinting is a technique in which a web page draws text and shapes on a hidden <canvas> element, reads the pixels back and turns them into a short hash. The picture is the same on every visit to that page, but the pixels come out slightly differently on different computers, so the hash helps a site tell one browser from another without storing anything on your device.
This guide shows what happens step by step, why two computers that look identical draw different pixels, the three ways browsers and tools respond (blocking, random noise and stable per-profile rendering), how detection services spot the first two, and how to check your own browser in a couple of minutes.
How a canvas hash is made
The HTML canvas is a drawing surface that pages use for charts, games, image editors and photo filters. A fingerprinting script uses the same interface, but nothing is ever shown on screen:
- The script creates a canvas in memory, typically a few hundred pixels wide.
- It draws a fixed test pattern: a sentence in a common font, an emoji, a few overlapping shapes in semi-transparent colours, sometimes a gradient.
- It reads the result back with [
toDataURL()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) orgetImageData(). - It hashes those bytes into a short identifier and sends it to the server with the other signals it collected.
The test pattern is chosen to exercise as many parts of the rendering pipeline as possible in one small image. Text tests the font engine, the emoji tests the colour emoji font the operating system ships, and the transparent shapes test how colours are blended.
Why the pixels differ between computers
Drawing the same sentence sounds deterministic, but several layers each make small choices of their own:
- Font rendering. Each operating system smooths the edges of letters differently. Hinting, sub-pixel positioning and anti-aliasing move a few grey pixels around every glyph.
- Installed fonts. If the requested font is missing, a fallback is used, and the whole line changes width.
- Emoji. Each operating system draws emoji in its own style, and versions change with updates.
- Graphics hardware and drivers. When drawing is accelerated, the GPU and its driver do part of the blending and rounding.
- Browser version. The graphics library inside the browser changes between releases.
None of these differences is visible to the eye, but a hash changes completely when a single pixel does. The result is a value that is stable on one computer, shared by computers with the same hardware and software, and different elsewhere. On its own it is not unique; next to the user agent, screen and fonts it narrows things down quickly. The cornerstone guide on what browser fingerprinting is shows where canvas sits among the other signals.
Three ways to respond, and how detectors see each
Anyone who wants a browser to present a different canvas has three broad options. They are not equally convincing.
| Approach | What a page reads | What a detector notices |
|---|---|---|
| Block the canvas | An empty image, an error, or an identical blank result for everyone | Real browsers almost never block canvas, so the block itself is rare and identifying |
| Add random noise | Pixels nudged by a small random amount, often different on every read | Two reads of the same drawing disagree, and a flat fill is no longer flat |
| Stable per-profile rendering | A clean image that differs between profiles but repeats exactly within one | Nothing unusual: it behaves like a real device that happens to draw slightly differently |
Why random noise stands out
Noise is popular because it is easy: an injected script wraps toDataURL() and getImageData() and flips a few low bits before returning the pixels. Some privacy-focused browsers do something similar on purpose. The trouble is that real hardware never behaves this way, and detectors only have to ask the question twice:
- Read twice and compare. Draw the same pattern, read it twice on the same page, and compare. Real hardware returns identical bytes. Per-read noise returns two different answers.
- Draw a flat colour. Fill a rectangle with one exact colour and check every pixel. On a real device they all match. Noise produces values one or two steps away.
- Look at the function itself. A wrapped
toDataURL()written in JavaScript no longer prints[native code]when a page asks for its source. - Ask from somewhere else. An
OffscreenCanvasin a Web Worker, or a canvas in a fresh iframe, may not have been reached by the script at all, so it returns the original pixels.
Per-session noise, where the random offset is fixed for one session, passes the first test but still fails the others, and it gives the browser a new canvas every time it starts. A returning visitor whose canvas changes every day looks less like a person and more like a tool.
Why stable rendering is the consistent choice
A real device that differs from another one does so because its fonts and rendering differ, consistently, every time. The convincing way to give a profile its own canvas is the same: change how that profile renders, not what the readback function returns. The image stays clean, both reads agree, a worker and an iframe draw the same pixels as the page, and the function stays native because nothing was replaced.
How to check your own browser
You can see your canvas behaviour in two minutes.
- Open our free browser fingerprint test. It runs in your browser and sends nothing.
- In the Graphics section, note the Canvas hash and the Canvas stable on re-read row. The test draws text, an emoji and shapes twice; if the two differ, your browser adds noise.
- In the consistency checks, look at Stable readings (canvas and audio read twice) and Built-in functions untouched (whether drawing functions were replaced).
- Press Download JSON, reload the page and run it again. Paste the first file into Compare: the canvas hash should not change on a reload.
- If you use browser profiles, run the test in two of them. Separate profiles should show different canvas hashes, and each should keep its own hash after a restart.
If you prefer to see it in raw form, paste this into the developer console on any ordinary page. It draws the same pattern twice and tells you whether the readbacks agree:
function readCanvas() {
const c = document.createElement('canvas');
c.width = 240; c.height = 60;
const ctx = c.getContext('2d');
ctx.textBaseline = 'top';
ctx.font = '16px Arial';
ctx.fillStyle = 'rgba(255, 102, 0, 0.7)';
ctx.fillRect(100, 1, 62, 20);
ctx.fillStyle = '#069';
ctx.fillText('Cwm fjordbank glyphs vext quiz', 2, 15);
return c.toDataURL();
}
console.log(readCanvas() === readCanvas() ? 'stable' : 'noise added');A result of stable is what real hardware gives. noise added means something between the page and the pixels is changing them on every read.
How Browz handles canvas
Browz sets each profile's fingerprint in the browser engine, not with a script on top, and canvas follows the stable approach above:
- Text drawn its own way, without noise. Each profile gets its own small, stable change to how text is drawn. The images stay as clean as an ordinary computer's, but differ between profiles. New profiles use this by default, so two profiles on one Mac do not share their canvas text and font-rendering hashes; the fingerprint policies article explains the settings.
- Genuine pixels. Nothing is added to the image after it is drawn, so a flat fill stays flat and two reads return the same bytes.
- Native everywhere. Because the change lives in the engine,
toDataURL()stays native, and the page, its workers and its iframes draw the same pixels. - Your choice per profile. Canvas noise and canvas blocking are still there as options for a profile if you want them; the engines page lists every control.
We chose this after measuring the alternative. In our tests, noise made a commercial device-identification service's tampering score jump and a public consistency checker report "masking detected", as the FAQ on the anti-detect page records. With stable rendering, the same public checks reported the fingerprint as consistent.
The free test is the one we run against each release. On 13 November 2026, Browz 0.1.9 on macOS passed 15 of 15 consistency checks, including stable readings and untouched built-in functions, in a normal window and headless; see our own result. For the wider picture of why consistency matters more than any single value, read fingerprint consistency checks, and for the 3D side of the graphics stack, WebGL and WebGPU fingerprinting.
Frequently asked questions
What is canvas fingerprinting used for?
Mostly fraud prevention, bot detection and, on some sites, tracking. Payment and sign-in pages use it as one of many device signals to notice an unfamiliar device. Bot-detection services use it to check whether a browser's graphics agree with what it claims to be. Advertising scripts have used it to recognise browsers without cookies, which privacy regulators in several countries treat like any other tracking.
Can I block canvas fingerprinting?
You can, with some extensions and browser settings, but blocking is rare among real browsers, so a blocked canvas is itself a distinctive signal, and some sites draw charts or images with canvas and stop working properly. For keeping identities apart, a separate profile with its own stable canvas is usually the better choice than a canvas that returns nothing.
Is my canvas fingerprint unique?
Usually not on its own. Computers with the same operating system, browser version, fonts and graphics often produce the same hash. It becomes identifying in combination with the user agent, screen, fonts, timezone and the WebGL renderer, which is why a profile's canvas has to fit the rest of its fingerprint.
Why does my canvas hash change every time I reload?
Because your browser or an extension adds random noise to canvas reads, a privacy feature. Our fingerprint test shows it in the "Canvas stable on re-read" row. A hash also changes after a browser update, a new graphics driver or a change in installed fonts, but those changes happen once, not on every reload.