Anti-Bot

What Is Canvas Fingerprinting?

What Is Canvas Fingerprinting? — conceptual illustration
On this page

Canvas fingerprinting is a browser-identification technique that asks the browser to draw an invisible image and hashes the resulting pixel data. The same drawing instructions produce slightly different output on different GPUs, drivers, and operating systems — enough variation to identify a device, and enough consistency to spot a headless browser or a software renderer instantly.

Quick facts

Introduced2012 academic paper, mainstream by 2016
How it variesGPU model, driver version, sub-pixel rendering, OS font stack
Used byAkamai, DataDome, PerimeterX, Cloudflare Turnstile
Tells onHeadless Chrome, SwiftShader, Mesa llvmpipe (known hashes)
Bypassed byReal GPU, Camoufox, CloakBrowser (C++ patches)

How canvas fingerprinting works

The script creates an invisible <canvas> element, draws shapes, gradients, and text on it using canvas.getContext("2d"), then calls canvas.toDataURL() to read the pixel data back. The pixel output depends on: the GPU manufacturer and model, the driver version, OS-level font rendering (Windows ClearType vs macOS CoreText), and canvas DPI scaling. Hashing the result produces a short identifier that is stable for the same device across sessions and different for almost every other device.

WebGL fingerprinting works the same way but for 3D rendering, and additionally exposes the GPU name via gl.getParameter(gl.RENDERER) — real Chrome returns something like ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0), while headless Chrome with no GPU returns a generic software string or crashes the WebGL context entirely.

Why scrapers get caught

Headless browsers do not have a GPU. They fall back to software rendering — either Chrome's built-in SwiftShader or Mesa llvmpipe on Linux. Both produce canvas hashes from a deterministic, known set. Anti-bots maintain a catalogue of these hashes and flag any session that produces one. Even worse: if the script asks for the WebGL renderer string and gets SwiftShader Device 0x0000C0DE, that is on a blocklist directly.

Patching toDataURL() in JavaScript does not help. Function.prototype.toString.call(canvas.toDataURL) reveals the patched source instead of [native code], so the patch itself becomes the bot signal.

How real bypasses work

Real fixes happen at the C++ level. CloakBrowser patches Chromium's rendering layer to inject slight per-profile noise into pixel values before toDataURL() returns — different hash every profile, identical visually. Camoufox does the same for Firefox via build-time patches. Real browsers running on consumer hardware are the gold standard: a real laptop with an Intel iGPU produces a real canvas hash that nothing in the blocklist matches.

A 2026 development complicates things further: services like Bablosoft PerfectCanvas now sell real harvested canvas hashes from real consumer GPUs that can be replayed into headless sessions. In response, anti-bots are pairing canvas probes with harder-to-replay signals (WASM SIMD timing, behavioural Bezier curve physics) so a "passing" canvas hash alone is no longer proof of a real browser.

PerfectCanvas — replaying a real machine's output

Naive canvas spoofing adds noise to the pixel output. This fails because anti-bot vendors expect stable output per-machine — randomising the canvas hash on every load looks more like a scraper than a fixed-but-wrong hash. The current state-of-the-art bypass is canvas replay, popularised by the PerfectCanvas project bundled into multilogin and several commercial anti-detect browsers.

The approach is: (1) on a real machine, generate canvas output for a wide set of known render operations and save the resulting hashes, (2) when the headless browser is asked to render any of those operations, return the pre-recorded pixels rather than the SwiftShader-degraded output. The result is byte-identical to the real machine for any test the anti-bot vendor knows to ask, and the consistent-per-session property is preserved.

The catch is novel render operations. Anti-bot vendors that suspect canvas replay can issue a render the database hasn't seen — the headless browser falls back to its real (broken) output, mismatch detected. The arms race here is whether the replay database has wider coverage than the vendor's test set.

Code example

javascript
// What every anti-bot script runs to fingerprint your browser
function canvasFingerprint() {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  ctx.textBaseline = 'top';
  ctx.font = '14px Arial';
  ctx.fillStyle = '#f60';
  ctx.fillRect(125, 1, 62, 20);
  ctx.fillStyle = '#069';
  ctx.fillText('Cwm fjordbank glyphs vext quiz', 2, 15);
  return canvas.toDataURL();   // hashed and sent to the server
}

Related terms

What Is Browser Fingerprinting?
Browser fingerprinting is a technique that identifies and tracks a visitor by combining dozens of small, observable characteristics of their…
What Is Anti-Bot Detection?
Anti-bot detection is the set of techniques websites use to distinguish automated traffic from human users — and to block, challenge, or thr…
What Is TLS Fingerprinting (JA3/JA4)?
TLS fingerprinting is a technique that identifies an HTTP client from its TLS handshake — before the server reads a single request byte. The…
What Is Camoufox?
Camoufox is a stealth-focused fork of Firefox with anti-fingerprinting patches applied at the C++ build level. Unlike playwright-stealth, wh…
What Is WebGL Fingerprinting?
WebGL fingerprinting reads identifying information directly from the GPU. The browser exposes the graphics card vendor and renderer string (…
What Is AudioContext Fingerprinting?
AudioContext fingerprinting plays a silent waveform through the Web Audio API, then reads back the resulting floating-point samples and hash…
What Is Function.toString() Inspection?
Function.prototype.toString() inspection is the technique anti-bot scripts use to detect runtime JavaScript patches. Every JS function expos…
What Is WASM Fingerprinting?
WebAssembly fingerprinting is a 2026 detection layer that probes the actual CPU through WASM SIMD instructions and uses WebAssembly.Memory({…
What Is Timing & Cache Side-Channel Fingerprinting?
Timing-based fingerprinting uses high-resolution clocks to measure how long operations take, turning microarchitectural and rendering behavi…
What Is Fingerprint Clustering?
Fingerprint clustering is the practice of grouping fingerprints from millions of real visitors by similarity, then rejecting any new visitor…

Concept map

How Canvas Fingerprinting connects

The terms most directly tied to this one. Hover a node to see its neighbours, click to preview, drag to rearrange.

0 terms · 0 connections
You are here · Anti-Bot
Building map…

Frequently asked questions

Can I disable canvas fingerprinting?

Real users cannot easily disable it without breaking pages. Privacy extensions like CanvasBlocker randomise the output, which itself is detectable as "this canvas hash is too random to be real hardware". For scraping you do not want to disable — you want to look like a real device.

Do all browsers have the same canvas hash?

No, even the same browser version on the same OS can produce different hashes on different machines because the GPU and driver matter. That is what makes the technique useful for fingerprinting.

Is canvas fingerprinting legal under GDPR?

Canvas fingerprinting is generally treated as personal data under GDPR because it identifies devices. Sites need a lawful basis (usually consent) to use it for tracking. Using it strictly for anti-fraud or bot defense is more commonly accepted under the "legitimate interest" basis.

What is the difference between canvas and WebGL fingerprinting?

Canvas uses 2D rendering and is faster; WebGL uses 3D rendering and additionally exposes the GPU name string. Anti-bots typically combine both — a contradiction between them (e.g. WebGL says "Intel UHD 620" but canvas hash matches a software renderer) is itself a strong bot signal.

Why is canvas noise injection a worse strategy than fixed spoofing?

Real machines produce stable canvas hashes per session — same render always gives same pixels. A scraper that randomises the canvas hash on every page load looks anomalous compared to the global distribution of real users. A scraper with a fixed-but-wrong hash at least looks like one machine.

Last updated: 2026-05-27