# How to Browser Fingerprint: Methods

> How to browser fingerprint a visitor: the signals collected, canvas/WebGL/audio/TLS methods, code to build one, and how to avoid browser fingerprinting.

[Home](https://quanticdata.io/)/[Blog](https://quanticdata.io/blog/)/How to Browser Fingerprint: Methods

# How to browser fingerprint: signals, code and countermeasures

Anti-botJul 29, 2026·9 min read·QuanticData Team

On this page [What a browser fingerprint actually is](/blog/how-to-browser-fingerprint/#what-a-browser-fingerprint-actually-is) [How to browser fingerprint, step by step](/blog/how-to-browser-fingerprint/#how-to-browser-fingerprint-step-by-step) [Fingerprinting methods compared](/blog/how-to-browser-fingerprint/#fingerprinting-methods-compared) [Why automation gets caught](/blog/how-to-browser-fingerprint/#why-automation-gets-caught) [How to avoid browser fingerprinting](/blog/how-to-browser-fingerprint/#how-to-avoid-browser-fingerprinting) [Legality and ethics](/blog/how-to-browser-fingerprint/#legality-and-ethics) [A short checklist](/blog/how-to-browser-fingerprint/#a-short-checklist)

To browser fingerprint a visitor you collect dozens of low-entropy signals in one page load — headers, client hints, screen and timezone, canvas and WebGL render output, audio stack, font metrics, plus the TLS ClientHello — normalise them, hash them into one identifier, and store that hash server-side to recognise the same environment on later visits without any cookie.

## What a browser fingerprint actually is

A device fingerprint is information collected about the software and hardware of a remote machine for the purpose of identification, assimilated into a short identifier by a fingerprinting algorithm; a browser fingerprint is the subset gathered specifically through the browser ([Wikipedia, Device fingerprint](https://en.wikipedia.org/wiki/Device_fingerprint)). The important property is that nothing is written to the client. Clear cookies, open incognito, switch to a VPN — the same hardware and software configuration regenerates approximately the same hash.

Two properties decide whether a fingerprint is useful: **diversity** (does it separate you from millions of others?) and **stability** (does it survive a browser update?). They trade off. Adding another setting to the hash raises entropy but breaks the identifier the moment a user changes that setting. The EFF's Panopticlick study measured at least 18.1 bits of entropy from browser fingerprinting alone, with canvas claiming roughly 5.7 more; later work found 83.6% to 89.4% of desktop fingerprints unique, while the 2018 "Hiding in the Crowd" dataset put uniqueness at 33.6% overall and only 18.5% on mobile (figures collected in the same Wikipedia article). Mobile devices are simply less varied.

That gap explains why production systems do not hash-and-compare naively. They weight each signal by uniqueness and durability, then link partially-different fingerprints with rule-based or machine-learned matching — for example treating two fingerprints identical except for a monotonically increasing browser version as the same device.

## How to browser fingerprint, step by step

1. **Read the transport layer first.** Before any JavaScript runs, the TLS ClientHello exposes version list, cipher-suite ordering, supported groups and extensions. JA3 (MD5 over those fields) and the newer JA4 (stable under extension shuffling, with HTTP and QUIC context) turn that into a string. A plain Python `requests` handshake is identifiable here no matter how perfectly you spoof headers.

2. **Capture headers and client hints.** User-Agent, `Accept-Language`, `Accept-Encoding` order, HTTP/2 pseudo-header order and settings frames, and the `Sec-CH-UA-*` hint family. Cross-check them: a UA claiming macOS with `Sec-CH-UA-Platform: "Windows"` is a hard fail.

3. **Query the JS environment.** `navigator.platform`, `hardwareConcurrency`, `deviceMemory`, `maxTouchPoints`, `languages`, `screen.width/height/colorDepth`, `Intl.DateTimeFormat().resolvedOptions().timeZone`, permission states, media-device counts.

4. **Force rendering work.** Draw text and shapes to an offscreen HTML5 canvas and hash the pixel buffer; read `WEBGL_debug_renderer_info` for the GPU and driver string; run an OfflineAudioContext oscillator and hash the output buffer. These reveal GPU, drivers and CPU-level float behaviour.

5. **Measure fonts by side channel.** Render a string in a candidate font and compare its measured width against a fallback. Font lists are highly identifying — one cited study found 34% of a population identifiable from 43 characters of font data.

6. **Normalise, weight, hash.** Sort keys, round noisy floats, drop signals you know to be unstable, then hash. Store the hash plus the raw component vector so you can re-link when one component drifts.

7. **Score, do not just match.** Combine the fingerprint with IP reputation, ASN, and behavioural timing into a risk number. Fingerprint alone answers "same environment?", not "human?".

### A minimal browser fingerprint generator

```
// Runs client-side; post the result to your own endpoint.
async function fingerprint() {
  const c = document.createElement('canvas');
  const ctx = c.getContext('2d');
  ctx.textBaseline = 'alphabetic';
  ctx.font = '16px "Arial"';
  ctx.fillStyle = '#f60';
  ctx.fillRect(0, 0, 100, 30);
  ctx.fillStyle = '#069';
  ctx.fillText('Cwm fjord veg 12345', 2, 20);

  const gl = document.createElement('canvas').getContext('webgl');
  const dbg = gl && gl.getExtension('WEBGL_debug_renderer_info');

  const signals = {
    ua: navigator.userAgent,
    langs: navigator.languages.join(','),
    tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
    screen: [screen.width, screen.height, screen.colorDepth].join('x'),
    cores: navigator.hardwareConcurrency || 0,
    mem: navigator.deviceMemory || 0,
    touch: navigator.maxTouchPoints,
    canvas: c.toDataURL(),
    gpu: dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) : 'none',
    webdriver: navigator.webdriver === true
  };

  const bytes = new TextEncoder().encode(JSON.stringify(signals));
  const digest = await crypto.subtle.digest('SHA-256', bytes);
  return [...new Uint8Array(digest)]
    .map(b => b.toString(16).padStart(2, '0')).join('').slice(0, 32);
}
```

That is a working fingerprint in forty lines, and it is also why open-source projects on GitHub are the usual starting point for people searching "browser fingerprinting github" — the collection logic is not secret. The hard part is the server side: entropy weighting, drift handling and linkage.

## Fingerprinting methods compared

| Method | What it reveals | Entropy | Stability | Defeated by |
| --- | --- | --- | --- | --- |
| Headers + client hints | Browser, OS, locale | Low | High | Trivial spoofing (but easy to cross-check) |
| Canvas | GPU, drivers, font rasterisation | High | High | Per-session noise injection |
| WebGL | Renderer and vendor strings, capabilities | High | High | Extension blocking, software rendering |
| Audio (Web Audio API) | CPU/DSP float behaviour | Medium | High | Value randomisation |
| Font enumeration | Installed font set | High | Medium | Default OS font list only |
| Media devices | Cameras, mics, speakers attached | Medium | Medium | Permission denial |
| TLS (JA3/JA4) | The HTTP client itself | Medium | Very high | Only a real browser stack |
| Behavioural | Mouse jitter, scroll and click timing | Medium | Low per session | Realistic input synthesis |

## Why automation gets caught

Fingerprinting was built for fraud teams — detecting account takeover from an unrecognised device, linking accounts controlled by one operator, spotting emulator farms — and it works equally well against scrapers. A default headless Chromium leaks in predictable ways: `navigator.webdriver === true`, a `HeadlessChrome` token, an empty plugin array, a SwiftShader WebGL renderer where the UA claims an NVIDIA desktop, a screen size that matches no shipping display, and a permissions object that answers differently from real Chrome.

Detection rarely relies on a single tell. It relies on *contradiction*. A residential IP in Lisbon paired with an `America/New_York` timezone, French language headers and a JA4 hash that belongs to a Go HTTP client is not one problem — it is four mutually inconsistent claims, and inconsistency is the cheapest bot signal there is. The corollary for anyone building automation: internal coherence matters more than any individual value you patch.

## How to avoid browser fingerprinting

There are two distinct goals here and they need different answers.

### As a privacy-minded user

Reduce entropy rather than fake it. Firefox's fingerprinting protection (part of Enhanced Tracking Protection, on by default for all browsing since Firefox 69) blocks known fingerprinting scripts and, in resist-fingerprinting mode, normalises values so you look like everyone else running the same build. Tor Browser takes that furthest. Keep default settings, avoid exotic font and extension combinations — research cited by Wikipedia found 56.86% of users have a unique extension set — and remember that a browser fingerprint protector extension can backfire: an environment that reports impossible values is *more* distinctive than a boring one, and vendors treat anti-fingerprinting plugins as a risk flag in their own right.

### As an engineer running automation

Patching individual leaks is a treadmill. The stack you need looks like this, and each layer has to agree with the others:

- **Transport:** a real browser TLS/HTTP2 stack, or a client that reproduces one faithfully. No amount of header work fixes a wrong JA4.

- **Network:** exit IPs whose type, geography and ASN match the story your headers tell. [Residential proxies](https://quanticdata.io/residential-proxies/) from $0.80/GB with per-request country targeting keep IP geo and locale aligned; [ISP proxies](https://quanticdata.io/isp-proxies/) give you static addresses when a session needs to look like the same returning household.

- **Browser environment:** coherent canvas, WebGL, audio and font profiles that belong to a device that actually exists.

- **Behaviour:** variable dwell time and non-linear input, because behavioural signals feed the same risk score.

### Or move the problem to an API

Most teams do not want to maintain a fingerprint farm; they want the page content. A [web scraping API](https://quanticdata.io/web-scraping-api/) keeps the fingerprint surface — TLS profile, browser environment, proxy selection, retries — behind one HTTP call and returns Markdown, HTML or structured JSON. On QuanticData that starts at $0.0002 per page, or $0.001 with JS rendering, and pay-per-success means a blocked attempt costs nothing:

```
curl https://api.quanticdata.io/v1/scrape \
  -H "Authorization: Bearer $QD_API_KEY" \
  -d '{ "url": "https://example.com/pricing", "render": true }'

{ "success": true,
  "data": { "markdown": "# Pricing\n…" },
  "usage": { "cost_usd": 0.001 },
  "retries": [ { "attempt": 1, "outcome": "blocked" },
               { "attempt": 2, "outcome": "ok" } ] }
```

### Honest cost maths

Compare that to building it. One engineer maintaining fingerprint profiles, TLS emulation and block triage is not a part-time job; call it a conservative fraction of a salary plus browser compute and proxy bandwidth. At $0.001 per rendered page you can fetch a million pages for $1,000 — and you only pay for the ones that came back. Self-hosting wins when you need custom in-page interaction or you are already running browser infrastructure; the API wins for read-heavy extraction, which is most scraping.

For agent workflows the same logic applies through [MCP](https://quanticdata.io/mcp-server/): a model calls `search`, `scrape`, `map` or `crawl` as tools and never sees a fingerprint problem, because the tool boundary is where that complexity lives. The [web data API for AI](https://quanticdata.io/web-data-api-for-ai/) returns the same envelope to every tool call, so a failed fetch is a typed error your agent can retry rather than an HTML challenge page it tries to summarise. For whole-site jobs, [crawl and map](https://quanticdata.io/crawl-map/) handle pagination and URL discovery at $0.0003 per page with unfetched pages refunded.

## Legality and ethics

Fingerprinting for security purposes is generally treated as lawful. Vendors and privacy regulators broadly agree that using it to detect fraud, protect accounts and block bots can rest on legitimate interest under GDPR, while tracking and personalisation attract disclosure and consent duties; CCPA imposes its own notice and opt-out obligations. MDN documents fingerprinting as a tracking technique browsers actively work to frustrate, which is a useful signal about where platform policy is heading.

Evading fingerprinting sits in a different bucket. Testing your own systems, building reliable first-party automation and collecting public data within a site's terms and applicable law are ordinary engineering. Defeating fingerprinting to commit fraud, bypass authentication or scrape personal data is not. We cover the boundaries in more depth in [is browser fingerprinting legal](https://quanticdata.io/blog/is-browser-fingerprinting-legal/) and [is device fingerprinting legal](https://quanticdata.io/blog/is-device-fingerprinting-legal/). None of this is legal advice — check your jurisdiction and the terms of the sites you touch.

## A short checklist

1. Decide whether you need identification (fingerprint) or bot classification (risk score). They are not the same product.

2. Collect at the transport layer as well as in JavaScript, or you will miss the most stable signal you have.

3. Weight signals by entropy and durability; store components, not just the hash, so you can re-link after drift.

4. If you are on the automation side, test coherence, not individual values — one contradiction defeats a hundred patches.

5. Price the build against pay-per-success extraction before you commit an engineer to it.

### Sources & further reading

- [Device fingerprint — Wikipedia](https://en.wikipedia.org/wiki/Device_fingerprint)

- [Fingerprinting — MDN Web Docs Glossary](https://developer.mozilla.org/en-US/docs/Glossary/Fingerprinting)

- [Browser fingerprinting techniques: 6 top methods explained — Fingerprint](https://fingerprint.com/blog/browser-fingerprinting-techniques/)

- [What is browser fingerprinting? — Stytch](https://stytch.com/blog/what-is-browser-fingerprinting/)

## FAQ

Quick answers on how to browser fingerprint.

[Something else? Ask us →](mailto:hello@quanticdata.io)

### How do you create a browser fingerprint?

Collect signals in one page load — headers and client hints, screen and timezone, canvas and WebGL output, audio buffer, font metrics, hardware counts — normalise them, then hash the combined vector into a short identifier stored server-side. Add the TLS ClientHello fingerprint (JA3/JA4) from the connection itself for a signal JavaScript cannot fake.

### How do I avoid browser fingerprinting?

Reduce entropy instead of faking values: keep default settings, limit extensions and custom fonts, and use a browser with built-in protection such as Firefox's fingerprinting protection or Tor Browser. Aggressive spoofing via a browser fingerprint protector extension often makes you more distinctive and triggers CAPTCHAs, because impossible value combinations read as risk.

### Is browser fingerprinting legal?

Generally yes. Under GDPR, using it for security, fraud detection and bot prevention is typically justified as legitimate interest, while tracking and personalisation carry disclosure and consent obligations; CCPA adds notice and opt-out duties in California. Rules vary by jurisdiction and use case, so treat this as background, not legal advice.

### Can browser fingerprinting be cleared like cookies?

No. A fingerprint is stateless — nothing is written to your device, so the hash lives in a server-side database beyond your reach. Clearing cookies, using incognito or switching browsers does not reset it, because the same hardware and software configuration regenerates a very similar identifier on the next visit.

### What is the difference between browser and device fingerprinting?

Browser fingerprinting uses attributes exposed by one browser: headers, JS APIs, canvas, WebGL, fonts. Device fingerprinting aims at the machine itself — OS, CPU, GPU, network attributes and mobile SDK identifiers — so it can recognise the same device across different browsers and apps, and tends to stay stable for longer.

### Why does my scraper get blocked even with good proxies?

Because proxies only fix the IP. Anti-bot systems also read your TLS fingerprint, headless markers such as navigator.webdriver, WebGL renderer strings and behavioural timing. A residential IP paired with a Python TLS handshake and a headless browser profile is a contradiction, and contradictions are the cheapest bot signal available.

## Skip the fingerprint treadmill

QuanticData handles TLS profiles, browser environments and proxy selection behind one API call — any page as clean Markdown, HTML or JSON from $0.0002 ($0.001 rendered), pay per success so blocked attempts cost nothing. Start with $2 of free usage every month, no card required.

[Start free — $2/month included](https://app.quanticdata.io/register)[Explore Web Scraping API](https://quanticdata.io/web-scraping-api/)

## Related reading

[Anti-bot Is Browser Fingerprinting Legal? Browser fingerprinting is legal but regulated: consent rules for tracking, more room for fraud detection, and separate questions for anyone resisting it in automation. Read →](https://quanticdata.io/blog/is-browser-fingerprinting-legal/) [Anti-bot Is Device Fingerprinting Legal? Device fingerprinting is conditionally legal: ePrivacy consent and GDPR balancing in the EU, notice and opt-out in the US. A practical, layer-by-layer breakdown. Read →](https://quanticdata.io/blog/is-device-fingerprinting-legal/) [SEO data How to Perform an SEO Audit A practical six-step SEO audit process with a checklist, the crawler-vs-user diff most audits skip, and how to run the whole thing programmatically. Read →](https://quanticdata.io/blog/how-to-perform-an-seo-audit/)

---

Source: https://quanticdata.io/blog/how-to-browser-fingerprint/ · Site index for AI: https://quanticdata.io/llms.txt
