All articles Fundamentals

How Canvas Fingerprinting Works, With Examples

Two computers can request the exact same drawing instructions and produce subtly different pixels. That is the entire premise of canvas fingerprinting. When a browser rasterizes text and shapes onto an HTML5 canvas, the result depends on the GPU, the graphics driver, the font rasterizer, anti-aliasing settings, and the operating system’s sub-pixel rendering. None of those are visible to the human eye, but they are perfectly measurable in the pixel buffer.

Canvas is one of the highest-entropy signals available to a client-side script, and it needs no permission prompt in most browsers. This article walks through the mechanism, shows what the code actually does, and explains where the technique is strong and where it quietly fails.

Why identical instructions produce different pixels

The <canvas> element exposes a 2D rendering context that browsers implement on top of platform graphics stacks. When you draw a string of text with a specific font and fill style, the browser hands that request down through a chain of components that each vary between machines:

  • GPU and driver. Hardware-accelerated compositing means the actual pixel math can run on the graphics card. Different GPUs round floating-point color and coverage values differently.
  • Font rasterizer. Windows uses DirectWrite, macOS uses Core Text, Linux commonly uses FreeType. Each hints and anti-aliases glyph edges in its own way.
  • Installed fonts. If your requested font is absent, the browser substitutes one, changing the output entirely. Font availability is itself a fingerprint, as covered in how font fingerprinting works.
  • Sub-pixel and anti-aliasing settings. ClearType, grayscale smoothing, and DPI scaling all shift edge pixels.

The differences are small, often a handful of bytes across thousands of pixels. But hashed, those bytes collapse into a stable identifier that survives across sessions because nothing about it is stored client-side.

A minimal canvas fingerprint

The classic approach draws text with an unusual font stack, layers a couple of colored shapes to exercise compositing, then exports the pixel data and hashes it.

function canvasFingerprint() {
  const canvas = document.createElement('canvas');
  canvas.width = 240;
  canvas.height = 60;
  const ctx = canvas.getContext('2d');

  ctx.textBaseline = 'top';
  ctx.font = '16px "Arial"';
  ctx.fillStyle = '#f60';
  ctx.fillRect(10, 10, 100, 30);

  ctx.fillStyle = '#069';
  ctx.fillText('Prynt \u{1F510} canvas', 12, 15);

  ctx.fillStyle = 'rgba(102, 200, 0, 0.5)';
  ctx.fillText('Prynt \u{1F510} canvas', 14, 17);

  // Base64 PNG of the rendered pixels
  const data = canvas.toDataURL();
  return hash(data); // any stable hash, e.g. SHA-256
}

Two design choices matter. The overlapping text with a translucent fill forces the compositor to blend, which amplifies rounding differences. The emoji triggers the platform emoji font, which varies significantly across operating systems and even OS versions. The output of toDataURL() is a PNG-encoded string; hashing it yields a compact signal you can compare server-side.

What the signal is actually worth

Canvas is valuable precisely because it correlates with hardware and OS rather than with browser configuration a user can trivially change. But it is not a unique identifier on its own. Many devices in a large population share the same GPU, driver version, and OS build, so they collide into the same canvas hash.

PropertyCanvas fingerprint
Entropy contributionHigh, but shared across identical hardware
Stability across sessionsVery stable until driver or OS update
Permission requiredUsually none
Resistant to clearing cookiesYes
Resistant to dedicated spoofingNo

Think of canvas as one column in a wider entropy budget. On its own it narrows a visitor to a hardware-and-OS class. Combined with WebGL fingerprinting, audio fingerprinting, and dozens of smaller attributes, it contributes to a stable visitor ID. The math behind combining independent signals is covered in browser fingerprinting entropy explained.

Where canvas fingerprinting breaks

The technique has well-known failure modes, and pretending otherwise leads to brittle detection.

  • Anti-fingerprinting noise. Some privacy browsers add randomized per-read noise to the canvas buffer, so every read produces a different hash. This is itself detectable: a signal that should be perfectly stable but changes on every call is a strong tell for a spoofing browser.
  • Permission prompts. Certain browsers ask the user before returning canvas data, which suppresses the read entirely.
  • Headless rendering quirks. Headless Chrome and server-side rasterization can produce sanitized or unusually clean outputs, which pairs well with the techniques in how to detect headless Chrome.
  • Farmed uniformity. A device farm running identical VM images will produce identical canvas hashes across thousands of accounts, which becomes a clustering signal rather than an identity signal.

The right posture is to treat instability and impossible uniformity as signals in their own right. A canvas hash that changes every read, or a canvas hash shared by ten thousand supposedly distinct users, both tell you something useful even when the raw value does not identify anyone.

Using canvas responsibly in production

Because canvas requires no prompt and is invisible to users, it carries privacy weight. Collect it as part of a documented device-intelligence pipeline, not as a covert tracker. A few practical guidelines:

  1. Hash the pixel output on the client or server, and store the hash, not the raw image.
  2. Never treat the canvas hash as a standalone identity. Feed it into a combined visitor ID with a confidence score.
  3. Log when the value is unstable so you can distinguish spoofing from genuine hardware change.
  4. Document the collection in your privacy policy, and respect the constraints in GDPR and device fingerprinting.

Prynt collects canvas as one of many client signals in its open-source agent and folds it into a sealed, server-verified result rather than exposing raw hashes to your application code. You can see the raw signals in the playground and read the collection details in the docs.

Frequently asked questions

Does canvas fingerprinting work in incognito mode?

Yes. Canvas rendering does not depend on cookies or storage, so private windows produce the same hash as a normal session on the same device and browser.

Can users block canvas fingerprinting?

Some browsers and extensions add per-session noise or prompt before exposing canvas data. This defeats a naive single-signal approach, which is why canvas should be one input among many.

Canvas fingerprinting is a durable, permissionless window into a device’s hardware and rendering stack, and it remains one of the most useful client signals available. Its limits are as important as its strengths: it clusters rather than uniquely identifies, and dedicated spoofing turns its stability into a detectable anomaly. Used as one input in a broader device fingerprinting system, it earns its place. Used alone, it will mislead you.

Run it yourself

Prynt is open-source, self-hostable device intelligence — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics you own end to end.

Keep reading