Browser Fingerprinting and Stealth Mode
Learn how websites detect automated browsers through fingerprinting and how to use stealth plugins to avoid detection while scraping.
Websites use browser fingerprinting to distinguish automated scrapers from real users. They check dozens of signals including the navigator object, WebGL rendering, canvas fingerprints, installed plugins, and more. A default Selenium or Playwright instance leaks many signals that reveal it as automated.
How Websites Detect Automation
Common detection signals include:
navigator.webdriveristruein automated browsers- Missing or inconsistent browser plugins
- WebGL vendor and renderer strings
- Canvas fingerprint anomalies
- Consistent viewport sizes and screen resolutions
- Missing or robotic mouse movements
- CDP (Chrome DevTools Protocol) detection
Playwright Stealth with playwright-stealth
The playwright-stealth package patches common detection leaks:
pip install playwright-stealth
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Apply stealth patches
stealth_sync(page)
page.goto("https://bot.sannysoft.com")
page.wait_for_load_state("networkidle")
# Take a screenshot to verify stealth is working
page.screenshot(path="stealth_test.png", full_page=True)
browser.close()
Selenium with undetected-chromedriver
For Selenium, undetected-chromedriver patches ChromeDriver to avoid detection:
pip install undetected-chromedriver
import undetected_chromedriver as uc
driver = uc.Chrome(headless=True)
driver.get("https://bot.sannysoft.com")
# Check if detection tests pass
print(driver.title)
driver.save_screenshot("selenium_stealth.png")
driver.quit()
Manual Stealth Techniques
You can also apply patches manually for more control:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
headless=True,
args=[
"--disable-blink-features=AutomationControlled",
]
)
context = browser.new_context(
user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
viewport={"width": 1366, "height": 768},
locale="en-US",
timezone_id="America/New_York",
)
page = context.new_page()
# Override navigator.webdriver
page.add_init_script("""
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined
});
""")
page.goto("https://example.com")
browser.close()
Human-Like Behavior
Add realistic delays and mouse movements to avoid behavioral detection:
import random
import time
# Random delay between actions
time.sleep(random.uniform(1, 3))
# Type like a human (with random delays between keystrokes)
for char in "search query":
page.type("#search", char, delay=random.randint(50, 150))
The Easier Path
Maintaining stealth configurations is a constant cat-and-mouse game. Anti-bot services update their detection methods regularly. ScrapingAnt and ScraperAPI maintain stealth browser profiles on their end, so you get clean data without managing fingerprint evasion yourself.
Next Steps
- Set up proxies with Playwright and Selenium
- Learn anti-detection techniques in depth
- Compare browser automation tools