Browser Fingerprinting: What It Is and How to Prevent It
Browser fingerprinting is the process of collecting technical details about a user’s browser and device to create a unique identifier — a “fingerprint.” Anti-bot systems use fingerprinting to distinguish real users from automated scrapers, even when scrapers use different IPs, clear cookies, or switch user agents.
Understanding how fingerprinting works is essential for anyone building web scraping infrastructure. This guide covers every fingerprinting technique used in 2026 and practical methods to defeat them.
How Browser Fingerprinting Works
Every browser exposes hundreds of data points through JavaScript APIs. Individually, each data point isn’t unique. But combined, they create a fingerprint that’s unique to your specific browser, hardware, and configuration.
Research from the EFF’s Panopticlick project showed that the combination of just a few dozen attributes can uniquely identify over 94% of browsers. Anti-bot systems collect far more signals than Panopticlick.
What Makes a Fingerprint
// Example: collecting basic fingerprint data
const fingerprint = {
userAgent: navigator.userAgent,
platform: navigator.platform,
language: navigator.language,
languages: navigator.languages,
hardwareConcurrency: navigator.hardwareConcurrency,
deviceMemory: navigator.deviceMemory,
screenResolution: [screen.width, screen.height],
colorDepth: screen.colorDepth,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
plugins: Array.from(navigator.plugins).map(p => p.name),
doNotTrack: navigator.doNotTrack,
cookiesEnabled: navigator.cookieEnabled,
touchSupport: navigator.maxTouchPoints,
};Fingerprinting Techniques
1. Canvas Fingerprinting
Canvas fingerprinting renders text and shapes on an HTML5 canvas element, then reads the pixel data. Different GPUs, drivers, and OS rendering engines produce subtly different outputs — even for identical instructions.
// How canvas fingerprinting works
function getCanvasFingerprint() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 50;
ctx.textBaseline = 'top';
ctx.font = '14px Arial';
ctx.fillStyle = '#f60';
ctx.fillRect(0, 0, 200, 50);
ctx.fillStyle = '#069';
ctx.fillText('Browser Fingerprint', 2, 15);
ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
ctx.fillText('Browser Fingerprint', 4, 17);
return canvas.toDataURL(); // Unique per GPU/driver/OS combo
}Detection problem for scrapers: Headless browsers produce canvas outputs that differ from headed browsers. Some produce blank or uniform outputs entirely.
2. WebGL Fingerprinting
WebGL exposes detailed GPU information:
function getWebGLFingerprint() {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
if (!gl) return null;
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
return {
vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL),
renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL),
version: gl.getParameter(gl.VERSION),
shadingLanguage: gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
extensions: gl.getSupportedExtensions(),
};
}Headless Chrome reports "Google SwiftShader" as the WebGL renderer — an instant bot signal.
3. Audio Fingerprinting
The AudioContext API produces device-specific audio processing results:
function getAudioFingerprint() {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const analyser = audioCtx.createAnalyser();
const gain = audioCtx.createGain();
const processor = audioCtx.createScriptProcessor(4096, 1, 1);
oscillator.type = 'triangle';
oscillator.frequency.value = 10000;
gain.gain.value = 0;
oscillator.connect(analyser);
analyser.connect(processor);
processor.connect(gain);
gain.connect(audioCtx.destination);
// The resulting audio signal varies by hardware/OS
return new Promise(resolve => {
processor.onaudioprocess = (e) => {
const data = e.inputBuffer.getChannelData(0);
const hash = data.reduce((a, b) => a + Math.abs(b), 0);
resolve(hash);
processor.disconnect();
oscillator.disconnect();
};
oscillator.start(0);
});
}4. Font Fingerprinting
Different systems have different installed fonts. By measuring the rendered width of text in various fonts, sites can determine which fonts are installed:
function detectFonts() {
const baseFonts = ['monospace', 'sans-serif', 'serif'];
const testFonts = [
'Arial', 'Verdana', 'Helvetica', 'Times New Roman',
'Courier New', 'Georgia', 'Palatino', 'Garamond',
'Comic Sans MS', 'Impact', 'Trebuchet MS',
];
const span = document.createElement('span');
span.style.fontSize = '72px';
span.innerHTML = 'mmmmmmmmlli';
document.body.appendChild(span);
const installed = [];
for (const font of testFonts) {
for (const base of baseFonts) {
span.style.fontFamily = `'${font}', ${base}`;
const width = span.offsetWidth;
span.style.fontFamily = base;
if (width !== span.offsetWidth) {
installed.push(font);
break;
}
}
}
document.body.removeChild(span);
return installed;
}5. TLS/JA3 Fingerprinting
Before any JavaScript runs, the TLS handshake itself creates a fingerprint. The JA3 hash captures the client’s supported cipher suites, extensions, and other TLS parameters. Python’s requests library produces a completely different JA3 hash than Chrome.
See our detailed TLS/JA3 fingerprinting guide for more on this.
6. Navigator Property Fingerprinting
Anti-bot systems check for consistency across navigator properties:
// Inconsistencies that reveal bots:
// - platform says "Win32" but user agent says "Linux"
// - hardwareConcurrency is 0 (headless default)
// - deviceMemory is undefined (only bots)
// - languages array is empty
// - plugins array is empty (headless Chrome)How Anti-Bot Systems Use Fingerprints
Consistency Checking
The most powerful technique isn’t any single fingerprint — it’s checking that all signals are internally consistent. For example:
- User agent claims Chrome on Windows, but
navigator.platformsays “Linux” - Screen resolution is 1920×1080 but
window.outerWidthis 0 (headless) - Claims 8 CPU cores but WebGL reports a server GPU
- Font list matches Linux but user agent says macOS
Historical Fingerprint Tracking
Anti-bot systems maintain databases of fingerprints. If they see the same fingerprint across thousands of requests (all from different IPs), that’s a bot. Real users have unique fingerprints.
Anomaly Detection
Some fingerprint values are virtually impossible in real browsers:
- Zero plugins
navigator.webdriver === true- WebGL renderer containing “SwiftShader” or “llvmpipe”
- Canvas producing identical hashes across requests
Prevention Methods for Web Scrapers
Method 1: Stealth Browser Automation
Use browser automation libraries with anti-detection patches:
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
user_agent=(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/122.0.0.0 Safari/537.36"
),
)
page = context.new_page()
stealth_sync(page)
page.goto("https://target-site.com")
browser.close()See our Playwright Stealth and Undetected ChromeDriver guides for detailed setup.
Method 2: Fingerprint Spoofing
Override specific fingerprint values to match real browsers:
# Comprehensive fingerprint spoofing with Playwright
context.add_init_script("""
// Spoof canvas fingerprint by adding noise
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function(type) {
const context = this.getContext('2d');
if (context) {
const imageData = context.getImageData(0, 0, this.width, this.height);
for (let i = 0; i < imageData.data.length; i += 4) {
// Add subtle noise to RGB channels
imageData.data[i] ^= (Math.random() * 2) | 0;
imageData.data[i+1] ^= (Math.random() * 2) | 0;
imageData.data[i+2] ^= (Math.random() * 2) | 0;
}
context.putImageData(imageData, 0, 0);
}
return originalToDataURL.apply(this, arguments);
};
// Spoof WebGL renderer
const getParameterOriginal = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(param) {
// UNMASKED_VENDOR_WEBGL
if (param === 37445) return 'Google Inc. (NVIDIA)';
// UNMASKED_RENDERER_WEBGL
if (param === 37446) return 'ANGLE (NVIDIA, NVIDIA GeForce GTX 1060, OpenGL 4.5)';
return getParameterOriginal.apply(this, arguments);
};
// Spoof audio fingerprint
const originalCreateOscillator = AudioContext.prototype.createOscillator;
AudioContext.prototype.createOscillator = function() {
const oscillator = originalCreateOscillator.apply(this, arguments);
const originalConnect = oscillator.connect.bind(oscillator);
oscillator.connect = function(node) {
// Add slight random offset to audio processing
return originalConnect(node);
};
return oscillator;
};
""")Method 3: Fingerprint Rotation
For large-scale scraping, maintain a pool of consistent fingerprint profiles:
import random
FINGERPRINT_PROFILES = [
{
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"platform": "Win32",
"viewport": {"width": 1920, "height": 1080},
"timezone": "America/New_York",
"locale": "en-US",
"webgl_vendor": "Google Inc. (NVIDIA)",
"webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060)",
"hardware_concurrency": 12,
"device_memory": 16,
},
{
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"platform": "MacIntel",
"viewport": {"width": 1440, "height": 900},
"timezone": "America/Los_Angeles",
"locale": "en-US",
"webgl_vendor": "Google Inc. (Apple)",
"webgl_renderer": "ANGLE (Apple, Apple M1 Pro, OpenGL 4.1)",
"hardware_concurrency": 10,
"device_memory": 16,
},
{
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
"platform": "Linux x86_64",
"viewport": {"width": 1920, "height": 1080},
"timezone": "Europe/London",
"locale": "en-GB",
"webgl_vendor": "Google Inc. (AMD)",
"webgl_renderer": "ANGLE (AMD, AMD Radeon RX 580)",
"hardware_concurrency": 8,
"device_memory": 8,
},
]
def get_random_profile():
return random.choice(FINGERPRINT_PROFILES)
# Use a consistent profile per session
profile = get_random_profile()
context = browser.new_context(
viewport=profile["viewport"],
user_agent=profile["user_agent"],
locale=profile["locale"],
timezone_id=profile["timezone"],
)Method 4: Anti-Detect Browsers
For the highest level of fingerprint management, use commercial anti-detect browsers like Multilogin, GoLogin, or AdsPower. These tools create isolated browser profiles with unique, consistent fingerprints.
See our anti-detect browser guides for detailed tutorials.
Testing Your Fingerprint
Use these sites to check how unique and detectable your browser fingerprint is:
- bot.sannysoft.com — Comprehensive bot detection test
- browserleaks.com — Detailed fingerprint breakdown
- amiunique.org — Fingerprint uniqueness analysis
- fingerprintjs.com/demo — Commercial fingerprinting demo
- DataResearchTools Browser Fingerprint Tester — Our own testing tool
# Automated fingerprint testing
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
stealth_sync(page)
page.goto("https://bot.sannysoft.com")
import time
time.sleep(5)
# Screenshot the results
page.screenshot(path="fingerprint-test.png", full_page=True)
browser.close()FAQ
Can browser fingerprinting track me across different IPs?
Yes. That’s the entire point of fingerprinting — it works even when users change IPs, clear cookies, or use VPNs. If your browser fingerprint remains the same, the tracking persists. This is why fingerprint rotation (not just IP rotation) is essential for scraping.
Is canvas fingerprinting the most important technique?
Canvas fingerprinting is one of the most discussed techniques, but TLS/JA3 fingerprinting and navigator property consistency are actually more important for bot detection. Canvas fingerprinting primarily distinguishes between devices, while TLS fingerprinting distinguishes between real browsers and automation tools.
How do anti-detect browsers differ from stealth plugins?
Anti-detect browsers (Multilogin, GoLogin) create complete, consistent browser profiles at the binary level. Stealth plugins (playwright-stealth, puppeteer-stealth) override JavaScript APIs to fake specific values. Anti-detect browsers are more thorough but more expensive. Stealth plugins are free but can have inconsistencies that advanced detection catches.
Can I use a completely random fingerprint?
No. Fingerprints must be internally consistent and match real-world devices. A fingerprint claiming to be Chrome on Windows but with macOS-specific GPU info will be flagged immediately. Use real device profiles as templates.
Does fingerprinting work in incognito mode?
Yes. Incognito mode prevents cookie tracking but doesn’t change your browser fingerprint. Canvas rendering, WebGL info, installed fonts, and other hardware-level signals remain the same.
Conclusion
Browser fingerprinting is the most sophisticated layer of bot detection in 2026. Defeating it requires a combination of stealth browser automation, consistent fingerprint profiles, and quality residential proxies. No single technique is sufficient — you need to ensure every signal your browser emits matches what a real user’s browser would produce.
Useful Resources
- FingerprintJS GitHub
- EFF Cover Your Tracks
- TLS/JA3 Fingerprinting Guide
- How Websites Detect Bots
- User-Agent Rotation Guide
- 403 Forbidden in Web Scraping: How to Fix It
- Best CAPTCHA Solving Services in 2026: Complete Comparison
- Anti-Phishing with Proxies: How Security Teams Use Mobile IPs
- Brand Protection with Proxies: Detect Counterfeit Sellers & Trademark Violations
- How Cybersecurity Teams Use Proxies for Threat Intelligence
- Using Mobile Proxies for Dark Web Monitoring and Research
- 403 Forbidden in Web Scraping: How to Fix It
- Best CAPTCHA Solving Services in 2026: Complete Comparison
- Anti-Phishing with Proxies: How Security Teams Use Mobile IPs
- Brand Protection with Proxies: Detect Counterfeit Sellers & Trademark Violations
- How Cybersecurity Teams Use Proxies for Threat Intelligence
- Using Mobile Proxies for Dark Web Monitoring and Research
- 403 Forbidden in Web Scraping: How to Fix It
- Best CAPTCHA Solving Services in 2026: Complete Comparison
- Anti-Phishing with Proxies: How Security Teams Use Mobile IPs
- Brand Protection with Proxies: Detect Counterfeit Sellers & Trademark Violations
- How Cybersecurity Teams Use Proxies for Threat Intelligence
- Using Mobile Proxies for Dark Web Monitoring and Research
- 403 Forbidden in Web Scraping: How to Fix It
- Best CAPTCHA Solving Services in 2026: Complete Comparison
- Anti-Phishing with Proxies: How Security Teams Use Mobile IPs
- Brand Protection with Proxies: Detect Counterfeit Sellers & Trademark Violations
- How Cybersecurity Teams Use Proxies for Threat Intelligence
- Using Mobile Proxies for Dark Web Monitoring and Research
Related Reading
- 403 Forbidden in Web Scraping: How to Fix It
- Best CAPTCHA Solving Services in 2026: Complete Comparison
- Anti-Phishing with Proxies: How Security Teams Use Mobile IPs
- Brand Protection with Proxies: Detect Counterfeit Sellers & Trademark Violations
- How Cybersecurity Teams Use Proxies for Threat Intelligence
- Using Mobile Proxies for Dark Web Monitoring and Research