🎯 A customizable, anti-detection cloud browser powered by self-developed Chromium designed for web crawlers and AI Agents.👉Try Now
Back to Blog

Avoid Bot Detection With Playwright Stealth: 9 Solutions for 2026

Michael Lee
Michael Lee

Expert Network Defense Engineer

30-Jun-2026

TL;DR:

  • Playwright leaks fingerprints. Default headless Chromium instances broadcast automation signals like navigator.webdriver, missing plugins, and predictable viewport sizes.
  • Python and Node.js ecosystems differ. Use playwright-stealth in Python (with the v2.x context manager) and playwright-extra in Node.js to patch these leaks.
  • Stealth requires multiple layers. Bypassing modern detection requires patching the JavaScript layer, randomizing headers, rotating proxies, and managing session cookies simultaneously.
  • Cloud browsers handle the rest. When local stealth plugins fail against advanced WAFs, offloading the browser execution to managed infrastructure is the only reliable upgrade path.
  • Free to start. New Scrapeless accounts include free Scraping Browser runtime — sign up at app.scrapeless.com.

Introduction: the limits of default automation

Playwright is a powerful browser automation tool, but out of the box, it announces itself as a bot. When you launch a headless Chromium instance, it carries specific markers—like the navigator.webdriver flag set to true, a lack of standard browser plugins, and distinct WebGL signatures. Modern anti-bot systems from Cloudflare, DataDome, and Akamai read these signals and block the request before your script can even parse the DOM.

To scrape protected sites, you need Playwright stealth. However, "stealth mode" is not a built-in toggle you can flip in the Playwright library. It requires implementing specific techniques to patch browser fingerprint leaks, manage network characteristics, and emulate human behavior.

This guide breaks down 9 practical solutions to avoid bot detection with Playwright in 2025, providing detailed code examples to help you navigate the complexities of modern web scraping.


What You Can Do With It

  • Bypass basic bot detection. Access websites that block default headless browsers by patching navigator.webdriver and User-Agent leaks.
  • Standardize browser fingerprints. Inject realistic hardware concurrency, memory, and plugin data into your headless Chromium instance.
  • Maintain session persistence. Combine stealth patches with proper cookie and context management to keep sessions alive longer.
  • Scale data extraction. Run parallel, stealth-patched browser contexts for high-volume scraping tasks.

Why Scrapeless Scraping Browser

Scrapeless Scraping Browser is a customizable, anti-detection cloud browser designed for web crawlers and AI agents. When local stealth plugins hit their limits against advanced WAFs, it brings:

  • Built-in anti-detection. Native fingerprint spoofing that goes beyond JavaScript patches, including TLS and TCP fingerprint management.
  • Automatic proxy rotation. Integrated residential proxies in 195+ countries to solve the IP reputation problem.
  • Managed challenge solving. Automatic resolution of Cloudflare Turnstile, reCAPTCHA, and hCaptcha.
  • Playwright compatibility. Connect your existing Playwright scripts to the cloud browser via CDP with a single line of code.

Get your API key on the free plan at app.scrapeless.com.


Prerequisites

  • Node.js 18+ or Python 3.10+
  • A Scrapeless account and API key — sign up at app.scrapeless.com
  • Basic familiarity with Playwright automation

9 Solutions to Avoid Bot Detection with Playwright Stealth

One of the most common indicators of automation is the navigator.webdriver property, which is set to true in automated browser environments. The W3C WebDriver standard defines this flag specifically to allow servers to identify automated traffic. Websites can easily check this flag to identify bots. Disabling it is a fundamental stealth technique.

Code Operation Steps:

Use page.add_init_script() to inject JavaScript that modifies the navigator.webdriver property before any site scripts run:

python Copy
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context()
    
    # Inject JavaScript to disable the webdriver flag
    context.add_init_script("""
        Object.defineProperty(navigator, 'webdriver', {
          get: () => undefined
        })
    """)
    
    page = context.new_page()
    page.goto("https://bot.sannysoft.com/")
    page.screenshot(path="webdriver_disabled.png")
    browser.close()

2. Randomize User-Agent Strings

The User-Agent header identifies the browser and operating system to the web server. Using a consistent or outdated User-Agent (especially one containing HeadlessChrome) is a strong indicator of a bot. Randomizing User-Agent strings helps in appearing as different legitimate users.

Code Operation Steps:

Maintain a list of common User-Agent strings and select one randomly for each session:

python Copy
from playwright.sync_api import sync_playwright
import random

user_agents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0"
]

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context(user_agent=random.choice(user_agents))
    page = context.new_page()
    page.goto("https://www.whatismybrowser.com/detect/what-is-my-user-agent")
    page.screenshot(path="random_user_agent.png")
    browser.close()

3. Use Proxies and Rotate IP Addresses

Repeated requests from the same IP address are a primary indicator of bot activity. Using a pool of proxies and rotating IP addresses for each request or session distributes your traffic and avoids IP-based blocks.

Code Operation Steps:

Configure Playwright to use a proxy:

python Copy
from playwright.sync_api import sync_playwright
import random

proxies = [
    "http://user1:pass1@proxy1.example.com:8080",
    "http://user2:pass2@proxy2.example.com:8080"
]

with sync_playwright() as p:
    # Launch browser with a randomly selected proxy
    browser = p.chromium.launch(headless=True, proxy={
        "server": random.choice(proxies)
    })
    page = browser.new_page()
    page.goto("https://www.whatismyip.com/")
    browser.close()

For large-scale operations, consider using a managed proxy service like Scrapeless Proxies that handles rotation automatically.

4. Simulate Realistic Mouse Movements and Keyboard Inputs

Bots often interact with web elements directly and instantaneously, which is unnatural. Anti-bot systems track behavioral biometrics like cursor velocity and keystroke cadence. Simulating human-like mouse movements, clicks, and keyboard inputs reduces the chances of detection.

Code Operation Steps:

Use page.mouse and page.keyboard methods to introduce delays and realistic paths:

python Copy
from playwright.sync_api import sync_playwright
import time
import random

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://www.example.com")

    # Simulate human-like typing
    search_input = page.locator("#search-box")
    search_input.click()
    text_to_type = "Playwright Stealth"
    for char in text_to_type:
        page.keyboard.type(char)
        time.sleep(random.uniform(0.05, 0.2)) # Random delay between key presses
    page.keyboard.press("Enter")
    
    browser.close()

5. Manage Cookies and Session Data

Websites use cookies to track user sessions. Bots that drop cookies between requests are easily identified as automated traffic. Maintaining a consistent session by accepting and sending cookies is vital for stealth.

Code Operation Steps:

Use context.storage_state() to save cookies and local storage, then load them into new sessions:

python Copy
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    
    # Scenario 1: Save current session cookies for future use
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://www.example.com/login")
    # Perform login...
    
    # Save state
    context.storage_state(path="state.json")
    browser.close()

    # Scenario 2: Load cookies from a previous session
    browser2 = p.chromium.launch(headless=True)
    context2 = browser2.new_context(storage_state="state.json")
    page2 = context2.new_page()
    page2.goto("https://www.example.com/dashboard")
    browser2.close()

6. Adjust Viewport Size and Device Emulation

Websites check the viewport size and screen resolution to detect anomalies. Using a default 800x600 viewport is a common red flag. Emulating common device configurations helps in blending in with real user traffic.

Code Operation Steps:

Set viewport and user_agent when creating a new context:

python Copy
from playwright.sync_api import sync_playwright
import random

viewports = [
    {"width": 1920, "height": 1080}, # Desktop
    {"width": 1366, "height": 768},  # Laptop
]

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    
    selected_viewport = random.choice(viewports)
    context = browser.new_context(
        viewport=selected_viewport
    )
    page = context.new_page()
    page.goto("https://www.deviceinfo.me/")
    browser.close()

7. Avoid Headless Mode Detection

While headless mode is efficient, some anti-bot systems can detect it by checking for missing graphics rendering capabilities. Running Playwright in headful mode (with a visible browser UI) can sometimes bypass detection, especially for more aggressive systems.

Code Operation Steps:

Set headless=False when launching the browser:

python Copy
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False) # Launch in headful mode
    page = browser.new_page()
    page.goto("https://www.example.com")
    browser.close()

8. Use playwright-stealth and playwright-extra

Instead of writing manual JavaScript injections, use dedicated stealth packages. The Python ecosystem uses playwright-stealth, while Node.js uses playwright-extra combined with puppeteer-extra-plugin-stealth. These libraries automatically apply a suite of evasions to patch the browser fingerprint.

Code Operation Steps (Python):

Install the package (pip install playwright-stealth) and use the v2.x context manager API:

python Copy
import asyncio
from playwright_stealth import Stealth
from playwright.async_api import async_playwright

async def main():
    # The context manager applies stealth patches automatically
    async with Stealth().use_async(async_playwright()) as playwright:
        browser = await playwright.chromium.launch(headless=True)
        context = await browser.new_context()
        page = await context.new_page()
        
        await page.goto("https://bot.sannysoft.com/")
        await browser.close()

asyncio.run(main())

9. Implement Delays and Randomization in Actions

Bots often execute actions with perfect timing and speed. Introducing random delays between actions and varying the speed of interactions makes the script appear more human.

Code Operation Steps:

Use time.sleep() with random intervals:

python Copy
from playwright.sync_api import sync_playwright
import time
import random

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://www.example.com")

    # Simulate browsing with random delays
    time.sleep(random.uniform(2, 5)) # Initial page load delay
    page.click("a[href='/products']")
    
    page.locator("input[name='q']").fill("search item")
    time.sleep(random.uniform(0.5, 1.5)) # Delay after typing
    page.keyboard.press("Enter")
    
    browser.close()

Get your API key on the free plan: app.scrapeless.com


Conclusion: beyond basic stealth

Playwright stealth plugins and behavioral adjustments are essential for basic web scraping, but they have hard limits. They operate at the JavaScript layer, meaning they cannot spoof TLS fingerprints, TCP window sizes, or solve complex behavioral challenges like Cloudflare Turnstile.

When your stealth-patched local browser starts receiving 403 errors or CAPTCHA loops, the solution is not to write more JavaScript evasions. The solution is to offload the browser execution to a managed infrastructure like the Scrapeless Scraping Browser, which handles IP rotation, TLS fingerprinting, and challenge solving automatically while letting you keep your Playwright code.


Ready to Build Your AI-Powered Data Pipeline?

Join the community of developers building robust data extraction systems.


FAQ

Q: Is Playwright stealth built into the library?
No. Playwright does not have a native stealth mode. You must use third-party packages: playwright-stealth for Python, or playwright-extra with the stealth plugin for Node.js.

Q: Do stealth plugins bypass Cloudflare?
Stealth plugins patch basic browser fingerprint leaks, which helps against simple checks. However, they do not solve advanced Cloudflare challenges (like Turnstile) or fix IP reputation issues.

Q: Does Playwright stealth work with Firefox or WebKit?
No. The evasion modules in both the Python and Node.js stealth packages are specifically designed to patch Chromium APIs. They do not support Firefox or WebKit.

Q: Do I still need proxies if I use stealth?
Yes. Stealth plugins only mask the browser's identity (the fingerprint). They do not hide your IP address. You still need residential proxies to avoid rate limits and IP-based blocks.

Q: Is scraping with Playwright legal?
Scraping publicly visible data is generally permissible, though jurisdictions vary. Review the target site's Terms of Service and consult legal counsel regarding your specific use case.

Q: Can this run without an AI agent?
Yes, the Playwright code works end-to-end as standard automation scripts. No AI agent is required to implement browser stealth.

At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.

Most Popular Articles

Catalogue