Canvas fingerprinting draws a hidden image in your browser and turns tiny rendering differences into a stable device ID. How it works and what really stops it.
Canvas fingerprinting works by asking your browser to draw text and shapes onto an invisible HTML5 canvas, then reading back the resulting pixels and hashing them into a short, stable identifier. Because every device renders those same drawing instructions slightly differently — depending on its GPU, graphics driver, operating system, and font engine — the hash becomes a quiet signature that follows you across sites without any cookie. This article goes well beyond the basics: how the pixels actually diverge, how much uniqueness canvas adds, how to tell when a site is fingerprinting you, and why some popular defenses can backfire.
How Canvas Fingerprinting Actually Works
The technique relies on the <canvas> element, which is meant for drawing graphics with JavaScript. A tracking script never needs to show that canvas on screen — it lives entirely in memory.
The flow is consistent across nearly every implementation:
- Create an off-screen canvas. A small canvas (often 200–300 px wide) is created but never attached visibly to the page.
- Draw a fixed scene. The script renders a predetermined string of text — frequently mixing fonts, colors, an emoji or two, and overlapping rectangles. Emoji and unusual Unicode are popular because they force the OS font stack to make rendering decisions.
- Read the pixels back. The script calls
toDataURL()to export the canvas as a Base64 PNG, orgetImageData()to read the raw RGBA byte array directly. These are the only two readback paths that matter for fingerprinting — every canvas fingerprinting script, regardless of library, ends in a call to one of them. - Hash the result. Those bytes are run through a hash function (commonly something like FNV or MurmurHash) to produce a compact fingerprint such as
e3b0c44298fc1c14.
The clever part is that the instructions are identical for everyone, but the output is not. Two visitors running the exact same script can produce different hashes, and the same visitor produces the same hash on every return visit — which is precisely what a tracker wants.
The canvas is never displayed. You will not see a flicker, a box, or any visual cue. This invisibility is exactly why canvas fingerprinting became so widespread for silent tracking.
Why the Pixels Differ Across Devices
If drawing "Hello" should be deterministic, why do the bytes change at all? Several layers of your system each introduce tiny, reproducible variations.
GPU and graphics driver
Anti-aliasing, sub-pixel rendering, and how curves are filled are all partly delegated to the GPU. An Intel integrated chip, an Apple Silicon GPU, and an NVIDIA discrete card will each round edge pixels differently. Even two machines with the same GPU model can diverge if their driver versions differ.
Font rasterization
The single biggest contributor is text rendering. The OS font engine — DirectWrite on Windows, Core Text on macOS, FreeType on Linux — decides how to turn glyph outlines into pixels. Hinting, gamma correction, and the exact anti-aliasing algorithm vary by platform and version, so the gray pixels along the edge of a letter "g" carry surprising amounts of distinguishing information.
Operating system and installed fonts
Whether a requested font exists determines whether the browser substitutes a fallback. An emoji might render as a flat outline on one system and a full-color glyph on another. The OS color-emoji set (Apple, Noto, Segoe) leaves an especially strong mark.
Browser engine and version
Chromium, Firefox, and WebKit each have their own canvas implementation. Color management and how toDataURL() encodes PNG data can shift between browser versions, which is why a browser update sometimes changes your canvas hash.
How Much Uniqueness Does Canvas Add?
Canvas is valuable to trackers not because it identifies you alone, but because it contributes a meaningful chunk of entropy — the measure of how much a signal narrows down who you are. In studies of fingerprinting in the wild, canvas has repeatedly ranked among the highest-entropy individual signals a passive site can read, on par with the full list of installed fonts. The best-known public test of that uniqueness is EFF's Cover Your Tracks — though its score is easier to misread than it looks, which we unpack in Cover Your Tracks: What Your Uniqueness Score Doesn't Prove.
That said, canvas rarely identifies a person by itself. Many people share common configurations — a stock Windows laptop on Chrome with default fonts will collide with millions of others. Its real power appears in combination: canvas plus WebGL, screen metrics, timezone, and language together push toward a near-unique fingerprint. For the actual math behind "how many bits until you're unique" and what your resulting anonymity set looks like, see Browser Fingerprint Entropy and Anonymity Sets Explained.
Why a Canvas Hash Is Stable — Until It Isn't
Canvas fingerprints have an unusual lifecycle that trips up a lot of explanations: the hash is stable across sessions but not stable across hardware or software changes. Both halves matter, and conflating them is the most common mistake in how this technique gets described.
Within a single machine, the hash barely moves. The same GPU, the same driver build, the same OS font rasterizer, and the same browser version will draw the exact same pixels every time — so a tracker sees an identical value on your first visit and your five-hundredth, with no cookie required. That persistence is what makes canvas useful as a long-term identifier in the first place.
But the hash is not permanent. It shifts whenever any layer in the rendering chain changes:
- A GPU driver update can change anti-aliasing or curve-fill rounding by a few sub-pixels, which is enough to flip the hash.
- An OS upgrade often ships a new font rasterizer (a new DirectWrite, Core Text, or FreeType build), silently changing how every glyph is drawn.
- A browser update can change how
toDataURL()encodes PNG data or how the canvas 2D context anti-aliases, independent of the OS. - Swapping hardware (a new laptop, a different GPU) produces an entirely different value, with no continuity from the old one.
In practice this means a canvas hash decays as an identifier over months, not days — useful for tracking a session or a return visit within a stable setup, but not a permanent fingerprint the way a hardware serial number would be. Trackers compensate by combining canvas with more stable signals rather than relying on it alone, which is exactly why entropy-stacking (see the anonymity-set link above) matters more than any single signal.
| Property | Canvas Fingerprinting |
|---|---|
| Storage required | None (no cookie, no localStorage) |
| Survives cache/cookie clearing | Yes |
| Survives incognito/private mode | Usually yes |
| Visible to the user | No |
| Typical entropy contribution | High among single passive signals |
| Defeated by clearing data | No |
| Defeated by IP change | No |
How Websites Use Canvas Fingerprints
Canvas fingerprinting is dual-use. The same mechanism serves both invasive and protective purposes:
- Cross-site tracking. Ad and analytics networks embedded on many sites read the canvas hash to recognize a returning visitor even after cookies are cleared, building a behavioral profile.
- Anti-fraud and account security. Banks and payment processors flag logins where the canvas fingerprint suddenly differs from a known device, helping catch account takeover.
- Bot and abuse detection. Headless browsers and automation frameworks often produce canvas outputs that are either too uniform or render in tell-tale ways, so fingerprinting helps separate real users from scripted traffic — see Bot Detection Techniques for how this works in practice.
- Rate limiting and abuse prevention. Services use the fingerprint as a stable key to throttle accounts evading limits with fresh cookies.
How to Detect Whether You're Being Canvas-Fingerprinted
You can't see the canvas, but you can watch for the behaviors that accompany it.
Watch the API calls
In a fingerprinting attempt, JavaScript calls getContext('2d'), then fillText(), then toDataURL() or getImageData() on a canvas that is never added to the visible page. Browser developer tools and certain privacy extensions can surface these calls.
A minimal detection hook
You can instrument the canvas API yourself to log suspicious reads:
// Detect scripts that read canvas pixels without displaying anything
(function watchCanvasReads() {
const origToDataURL = HTMLCanvasElement.prototype.toDataURL;
const origGetImageData = CanvasRenderingContext2D.prototype.getImageData;
HTMLCanvasElement.prototype.toDataURL = function (...args) {
if (!document.body.contains(this)) {
console.warn('[canvas-fp] toDataURL() on an off-screen canvas', this);
}
return origToDataURL.apply(this, args);
};
CanvasRenderingContext2D.prototype.getImageData = function (...args) {
if (!document.body.contains(this.canvas)) {
console.warn('[canvas-fp] getImageData() on an off-screen canvas', this.canvas);
}
return origGetImageData.apply(this, args);
};
})();
Run it before the page's own scripts (a document_start userscript, or pasted into the console on reload) and watch for warnings on a page that has no visible drawing on it. Expect false positives: image-editing widgets, chart libraries, and cropping tools legitimately read pixels back. The signal to look for is a readback on a canvas that is never attached to the document, on a page with no graphics feature at all.
If you would rather see your own fingerprint than read code, the simplest route is to run BrowserInsight's fingerprint detection tool. It computes your live canvas hash, shows the WebGL and audio signals alongside it, and estimates how unique your overall fingerprint is — the same readback path a tracker would use, run in your own browser and never sent to a server.
Defenses and Their Tradeoffs
There is no single perfect defense, and — importantly — some popular options can make you more identifiable. No two engines treat canvas readback the same way either, and a blanket claim like "browsers may add noise" glosses over the differences that actually matter when you are choosing one. Here is what each vendor ships today.
Uniformity (Firefox's resistFingerprinting and the Tor Browser)
Firefox's built-in privacy.resistFingerprinting preference — the same protection mode documented by Mozilla and shipped by default in the Tor Browser, which is built on Firefox — takes the uniformity approach: a canvas readback (toDataURL() or getImageData()) returns a blank white image unless you explicitly approve a permission prompt, and other high-entropy signals — the WebGL vendor and renderer strings, screen metrics, timezone — are reported as fixed, generic values that every protected user shares. A script therefore gets either a useless result or one that is identical across the whole protected population. Blending into a large, uniform crowd is the most robust defense — but it comes at the cost of a heavily standardized, sometimes restrictive browsing experience, and Mozilla ships it as an opt-in preference rather than the Firefox default precisely because of that tradeoff.
Randomization (Brave's farbling)
Brave takes a different path called farbling: as Brave documents, it adds small, deterministic, per-session-and-per-eTLD+1 noise to canvas readback — the same site sees a consistent fake value within a session, but a different one on the next session or on a different site, so cross-site linking breaks. The subtle risk is that being randomized is itself detectable — and randomization that is implemented naively can paradoxically add entropy, since "a browser whose canvas is noisy" is a distinguishing trait. Well-designed farbling keeps the noise small, deterministic, and plausible to avoid this trap. For a deeper dive into how noise seeding determines whether randomization helps or backfires, see Canvas Noise vs Real Hash: Why Randomization Backfires.
WebKit/Safari's tracking-prevention posture
Safari doesn't rely on canvas-specific noise at all. WebKit's Tracking Prevention documentation describes a broader strategy built on Intelligent Tracking Prevention: partitioning storage per top-level site, capping script access to cross-site data, and treating persistent cross-site identification generally as an abuse pattern to be blocked rather than something to be papered over per-API. Canvas reads still function in Safari, but the surrounding cross-site linking that makes a fingerprint valuable to a tracker is what ITP targets.
Chrome and stock Chromium (no canvas defense)
This one is worth stating plainly, because it covers most readers: Chrome ships no canvas-specific defense. toDataURL() and getImageData() hand back the real pixels your GPU and font stack produced, in normal and Incognito windows alike, and the same is true of Chromium-based browsers that don't patch the engine themselves — Brave, above, being the notable exception. Google's privacy work in this area has targeted the cross-site plumbing (third-party cookie policy, the Privacy Sandbox APIs) rather than making the canvas itself unreadable. If you use Chrome unmodified, treat your canvas hash as fully exposed.
Blocking extensions (CanvasBlocker)
Extensions like CanvasBlocker can block readback, return a fake value, or randomize per-domain. They give you fine control, but the same caveat applies: an unusual or overly aggressive spoof can stand out, and a poorly configured blocker may be a stronger signal than the canvas it hides.
Disabling JavaScript
Turning off JavaScript (via NoScript or similar) defeats canvas fingerprinting entirely, because the API can't run. The tradeoff is steep — most modern sites break without it — so this suits only the most security-sensitive workflows.
| Defense | How it works | Main tradeoff |
|---|---|---|
| Firefox resistFingerprinting / Tor Browser | Uniform value or blocked readback | Restricted, standardized experience |
| Brave farbling | Per-session, per-site noise breaks linking | Randomization can itself be detectable |
| Safari (WebKit ITP) | Blocks cross-site linking, not the API itself | Canvas read still succeeds; scope is narrower |
| Chrome / stock Chromium | No canvas defense — real pixels are returned | No protection to configure |
| CanvasBlocker | Block/spoof/randomize readback | Misconfiguration can backfire |
| Disable JavaScript | API never runs | Breaks most websites |
Frequently Asked Questions
Does clearing cookies remove my canvas fingerprint?
No. Canvas fingerprinting stores nothing on your device — it derives the identifier from how your hardware and software render graphics. Clearing cookies, cache, or site data has no effect on it.
Does private or incognito mode stop canvas fingerprinting?
Usually not. Private windows isolate cookies and history, but your GPU, drivers, and fonts are unchanged, so the canvas hash is typically the same as in a normal window. Private mode helps with storage-based tracking, not fingerprinting.
Can a website see that I'm using a canvas blocker?
Sometimes, yes. If your canvas returns an obviously fake, blank, or noisy value, a sophisticated script can infer that a protection is active. That's why uniformity (looking like everyone else) is often more robust than randomization (looking deliberately different).
Is canvas fingerprinting the same as WebGL fingerprinting?
They're related but distinct. Canvas reads 2D rendering of text and shapes; WebGL probes your GPU through 3D rendering and exposes vendor and renderer strings directly. They complement each other in a combined fingerprint — our WebGL fingerprinting deep dive covers the 3D side in detail.


