Playwright Stealth Test: How Detectable Is Your Playwright Browser?
Playwright is one of the most popular browser automation frameworks, but out of the box, it's detectable. Detection scripts can identify a Playwright-controlled browser by examining artifacts left by its control protocol and launch configuration.
Here's what leaks, what the stealth plugins fix, and how to verify your setup.
Why Playwright gets detected
Playwright controls browsers via the Chrome DevTools Protocol (CDP). This control mechanism and the browser's launch configuration leave detectable artifacts.
Automation flags
Like all automation tools that use CDP or WebDriver, Playwright-controlled browsers set navigator.webdriver to true per the WebDriver spec. The navigator.plugins list and permission states may also differ from a regular Chrome installation, particularly when launching Chromium instead of Chrome.
Launch configuration
Playwright launches Chrome with flags that affect the browser's fingerprint:
--no-first-runand--no-default-browser-checkskip dialogs that set browser state- Default viewports and screen dimensions may not match common real-world values
- Bundled Chromium lacks extensions and plugins present in a full Chrome install
Control protocol artifacts
Playwright injects JavaScript bindings to communicate with the browser. While cleaned up after use, these injections can leave traces (such as modified global property counts or timing artifacts) that detection scripts look for.
Stealth plugins compared
playwright-stealth
The playwright-stealth npm package applies evasion scripts ported from puppeteer-extra-plugin-stealth. It patches navigator.webdriver, navigator.plugins, navigator.languages, chrome.runtime, WebGL vendor/renderer strings, and Permissions API responses.
It covers the most commonly checked automation flags but does not cover newer detection techniques like worker scope checks, prototype chain validation, or iframe consistency.
Patchright
Patchright is a Playwright fork that patches the browser binary itself rather than injecting JavaScript. This is harder to detect because the modifications exist at the C++ level, so they survive iframe creation, Worker spawning, and Function.prototype.toString inspection.
Patchright focuses on removing automation artifacts. It doesn't address signal consistency: your timezone, locale, GPU, screen resolution, and feature set still need to match a plausible real browser profile.
How to test your Playwright setup
Visual test
The simplest approach is to open https://stealthcheck.io/test in your Playwright browser and review the results. The test runs automatically and shows a detailed breakdown. No account needed, but the free test is limited to 10 checks per day. For CI or frequent testing, use a monitoring profile instead (see below).
import { chromium } from 'playwright'
const browser = await chromium.launch({ headless: false })
const page = await browser.newPage()
await page.goto('https://https://stealthcheck.io/test')
// Review the score and issues in the browser window
Programmatic test
For automated testing, use a monitoring profile token. The lightweight check page at /check/{token} exposes results on window.__stealthcheck:
import { test, expect } from '@playwright/test'
test('stealth score meets threshold', async ({ page }) => {
await page.goto(
process.env.STEALTH_CHECK_URL,
)
// The check page adds a .done class when analysis is complete
await page.waitForSelector('.done', { timeout: 30000 })
const result = await page.evaluate(() => (window as any).__stealthcheck)
expect(result.score).toBeGreaterThanOrEqual(90)
})
This requires a monitoring profile (available on paid plans).
Practical tips
-
Use
channel: 'chrome'. Launch the system's Chrome binary instead of Playwright's bundled Chromium. Chrome has plugins and extensions that Chromium lacks. -
Set a consistent context. Locale, timezone, and viewport should all agree:
const context = await browser.newContext({
locale: 'en-US',
timezoneId: 'America/New_York',
viewport: { width: 1920, height: 1080 },
screen: { width: 1920, height: 1080 },
})
-
Use
launchPersistentContext. Launch with a real user data directory to get authentic browser state (cookies, extensions, preferences). -
Test in both headless and headed mode. Some detection differences only appear in headless.
-
Pin your Playwright version. Test before upgrading, since new versions can change how the browser is launched or controlled.
Further reading
- Run a free stealth test to see how your Playwright browser scores
- How detection systems catch fingerprint spoofing
- Is my Puppeteer bot detectable?
Test your browser stealth for free
Run a free fingerprint test and see exactly what detection systems see.