Tutorial
Browser Fingerprint Injection with Playwright
Learn how to inject custom browser fingerprints in Playwright to avoid bot detection. Covers canvas, WebGL, audio, and navigator fingerprinting.
Anti-bot systems fingerprint your browser by collecting canvas renders, WebGL data, audio context, and navigator properties. Injecting consistent, realistic fingerprints helps avoid detection.
What Gets Fingerprinted
Anti-bot systems collect data from these browser APIs:
- Canvas, Draws hidden images and reads pixel data to generate a unique hash
- WebGL, Queries GPU renderer, vendor, and rendering output
- Audio Context, Processes audio signals that vary by hardware/OS
- Navigator, Platform, language, hardware concurrency, device memory
- Screen, Resolution, color depth, available dimensions
- Fonts, Enumerates installed fonts via rendering measurement
Injecting Navigator Properties
from playwright.sync_api import sync_playwright
FINGERPRINT = {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
"platform": "Win32",
"hardwareConcurrency": 8,
"deviceMemory": 8,
"languages": ["en-US", "en"]
}
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context(
user_agent=FINGERPRINT["userAgent"],
locale="en-US",
viewport={"width": 1920, "height": 1080},
screen={"width": 1920, "height": 1080}
)
context.add_init_script(f"""
Object.defineProperty(navigator, 'platform', {{get: () => '{FINGERPRINT["platform"]}'}});
Object.defineProperty(navigator, 'hardwareConcurrency', {{get: () => {FINGERPRINT["hardwareConcurrency"]}}});
Object.defineProperty(navigator, 'deviceMemory', {{get: () => {FINGERPRINT["deviceMemory"]}}});
Object.defineProperty(navigator, 'languages', {{get: () => {FINGERPRINT["languages"]}}});
""")
page = context.new_page()
page.goto("https://bot.sannysoft.com")
page.screenshot(path="fingerprint_test.png")
browser.close()
Canvas Fingerprint Injection
context.add_init_script("""
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function(type) {
if (this.width === 220 && this.height === 30) {
// Fingerprint canvas detected - add slight noise
const ctx = this.getContext('2d');
const imageData = ctx.getImageData(0, 0, this.width, this.height);
for (let i = 0; i < imageData.data.length; i += 4) {
imageData.data[i] += Math.floor(Math.random() * 2); // Tiny R change
}
ctx.putImageData(imageData, 0, 0);
}
return originalToDataURL.apply(this, arguments);
};
""")
WebGL Fingerprint Injection
context.add_init_script("""
const getParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function(param) {
if (param === 37445) return 'Google Inc. (NVIDIA)'; // UNMASKED_VENDOR
if (param === 37446) return 'ANGLE (NVIDIA, GeForce RTX 3060)'; // UNMASKED_RENDERER
return getParameter.call(this, param);
};
""")
Using fingerprint-generator Libraries
For realistic fingerprint sets, use the fingerprint-generator package from Apify.
npm install fingerprint-generator fingerprint-injector
Better Alternative: Managed APIs
Maintaining fingerprint injection code is tedious since browsers update fingerprint APIs regularly. ScraperAPI handles all fingerprinting automatically, generating consistent profiles per session. This is the recommended approach for production scrapers where reliability matters more than fine-grained control.