← All posts

Browser Fingerprinting Explained: Canvas, WebGL, Fonts, and Why It Flags Bots

Quick answer: Browser fingerprinting identifies a browser by combining dozens of small, JavaScript-readable traits (canvas rendering, WebGL, installed fonts, screen size, navigator properties, timezone) into a hash that is stable per device and nearly unique. Anti-bot systems use it to tell a real browser from an automated one, because headless and spoofed browsers leak tells that no genuine browser emits. It works at the JavaScript layer inside the page, which is what makes it different from TLS fingerprinting, and it puts a hard ceiling on how far spoofing can take you.

If you have read about TLS fingerprinting, you know a client can be flagged before it sends an HTTP request. Browser fingerprinting is the layer above that: it runs after the page loads, in JavaScript, and asks a different question. Not "what kind of client opened this connection" but "is this a real browser on a real device, and have I seen it before." This is a defensive, educational walkthrough of how it works and why it is so hard to fully spoof.

What a Fingerprint Actually Is

A browser fingerprint is not one thing. It is a hash of many independent signals, each weak on its own, collectively distinctive. The page runs JavaScript that reads:

  • Canvas. The page draws text and shapes to a hidden <canvas> and reads back the pixels. The exact pixels vary by GPU, driver, OS, and font rendering, so the same drawing produces a slightly different image on different devices. Hash it and you get a stable per-device value.
  • WebGL. Rendering a 3D scene and reading it back exposes the GPU vendor, renderer string, and subtle rasterization differences.
  • Fonts. The set of installed fonts differs between machines. A page measures text widths for many fonts to infer which are present.
  • Screen and window. Resolution, color depth, available width, device pixel ratio.
  • navigator. userAgent, platform, languages, hardwareConcurrency (CPU cores), deviceMemory, and plugins.
  • Timezone and locale. Intl and Date reveal the timezone, which should agree with the IP's geography.
  • Audio. Processing an audio signal through the Web Audio API produces device-specific floating-point output.

Concatenate and hash all of that and you get an identifier that is stable across visits (so it tracks you) and rare enough to single out one device among millions.

How It Differs From TLS and Network Fingerprinting

These get conflated constantly. They live at different layers and answer different questions, and a scraper can pass one while failing another.

Layer Fingerprint When it runs What it reads Needs JavaScript
Network / transport TLS (JA3, JA4), HTTP/2 During the handshake, before HTTP ClientHello, cipher order, HTTP/2 settings No
Application / browser Canvas, WebGL, fonts, navigator After the page loads Rendering and device APIs Yes

The key consequence: a well-tuned HTTP client like curl_cffi can match a browser's TLS fingerprint perfectly and still fail browser fingerprinting, because a bare HTTP client cannot run the JavaScript that reads canvas and WebGL at all. It never renders anything. When a site's defense depends on browser fingerprinting, no HTTP client passes it, whatever its TLS looks like. That is the dividing line between the two techniques, and the reason the escalation ladder from curl to a real browser exists.

How Anti-Bot Systems Use It

Fingerprinting gives a detector three things at once:

  1. Bot tells. Headless browsers leak. navigator.webdriver is true under automation. Old headless Chrome reported an empty plugins list and a telltale HeadlessChrome User-Agent. WebGL might report a software renderer (SwiftShader) instead of a real GPU, which no normal desktop does. Each is a flag.
  2. Consistency checks. A real device is internally coherent. If the User-Agent says iPhone but WebGL reports a desktop NVIDIA GPU, the timezone says Tokyo but the IP is in Ohio, and the language is set to Russian, that combination does not occur naturally. Mismatched signals are a stronger bot signal than any single value.
  3. Rate and reuse. The same fingerprint requesting 10,000 pages, or a thousand "different" visitors sharing one fingerprint, both stand out. The fingerprint links sessions that a rotating IP would otherwise separate.

You can spoof one signal. Keeping all of them mutually consistent, and consistent with your IP and TLS, is the actual challenge.

Inspecting Your Own Fingerprint

You do not need special tools to see the raw inputs. This is the kind of JavaScript a fingerprinting script runs, shown so you understand what is being read:

// A tiny slice of what fingerprinting scripts collect
const signals = {
  userAgent: navigator.userAgent,
  platform: navigator.platform,
  languages: navigator.languages,
  cores: navigator.hardwareConcurrency,
  memory: navigator.deviceMemory,
  screen: [screen.width, screen.height, screen.colorDepth],
  pixelRatio: window.devicePixelRatio,
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
  webdriver: navigator.webdriver,        // true under automation
};

// Canvas: draw text, read pixels back, hash them
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
ctx.textBaseline = "top";
ctx.font = "14px Arial";
ctx.fillText("fingerprint", 2, 2);
signals.canvas = c.toDataURL();          // varies by GPU/driver/OS

console.log(signals);

Run that in a normal browser console and a headless one and compare. The webdriver flag alone often gives an automated browser away.

The Limits of Spoofing

This is the honest part. You can patch individual signals (set navigator.webdriver to false, spoof a canvas value, fake a font list), and stealth browser configurations do exactly this. But there is a ceiling, and it is lower than people expect:

  • Consistency is combinatorial. Fix ten signals and the eleventh betrays you. Your spoofed GPU must match a plausible OS, which must match your fonts, which must match your screen size and pixel ratio, which must match your timezone, which must match your IP. Every value you fake is another value you must keep coherent.
  • Detectors watch for spoofing itself. A canvas value that is too clean, an audio fingerprint that is suspiciously default, a font list that is impossibly generic: these are tells that someone is spoofing, which is worse than an honest headless flag.
  • The arms race is asymmetric. Defenders add a new signal in a day; matching it convincingly across a fleet takes real work and breaks on the next browser release.

So the realistic goal is not a perfect fake. It is a real browser environment (a genuine rendering engine with a real GPU-backed canvas and WebGL) that behaves consistently, driven carefully. That is why serious scraping of fingerprint-defended sites uses actual browsers, not spoofed HTTP clients, and manages them as a pool.

The Defensive View

If you run a site, browser fingerprinting is a strong mid-tier signal: cheap to collect, hard to fake coherently, and excellent at catching lazy automation and linking abusive sessions. Combine it with TLS fingerprinting and behavioral analysis and you have layered defense that no single trick defeats.

If you are scraping, the ethical line is the same as everywhere else. Fingerprinting questions are only relevant for public data, and the right posture is to use a real browser environment, respect robots.txt and rate limits, and never route around authentication or a protection meant to keep you out of private content. Matching a browser environment to read public pages is reasonable; defeating a fingerprint gate to reach data behind a login is not. The technique is neutral; what you point it at is the ethics.

Where this nets out: browser fingerprinting is why "I set the User-Agent and I am still blocked" happens on JavaScript-heavy sites. It runs deeper than headers and higher than TLS, and it rewards a genuinely consistent real browser over a cleverly spoofed fake. A managed fetch layer like link.sc runs and coordinates that browser layer for you, so you request a URL and get clean content without maintaining a browser fleet or chasing the next fingerprint signal.


Skip the fingerprint arms race. Get a free link.sc key and fetch JavaScript-heavy pages through a managed real-browser layer.