Playwright and Puppeteer Browser Fingerprinting

Playwright and Puppeteer expose navigator.webdriver=true, empty plugins, and SwiftShader WebGL in headless mode. How anti-bot systems detect automation and how to test more realistically.

Playwright and Puppeteer Browser Fingerprinting: Headless Detection

For QA teams using browser automation, Playwright and Puppeteer expose detectable fingerprints in headless mode. Both automation frameworks control Chromium through the Chrome DevTools Protocol (CDP), and the resulting browser environment differs from a real user's browser in ways that fingerprinting scripts can measure.

navigator.webdriver is set to true in headless Chromium, advertising the automation context directly.1 navigator.plugins is empty, which no real desktop Chrome installation reports. The headless User-Agent string contains "HeadlessChrome" rather than "Chrome".2 Consequently, sites that run fingerprinting checks can detect automation without any behavioral heuristics; the passive signal profile alone distinguishes a headless browser from a real user.

Building on this, Playwright's real-browser mode using an installed Chrome binary rather than the bundled Chromium reduces some of these differences, but the CDP connection itself introduces artifacts that persistent fingerprinting scripts can detect. Understanding which signals change between real and headless mode is essential for testing automation against sites with bot detection.

Four passive signals that expose headless Chromium

  • navigator.webdriver returns true, required by the WebDriver specification
  • navigator.plugins empty PluginArray, length 0
  • User-Agent string contains the substring HeadlessChrome
  • WebGL renderer may return Google SwiftShader instead of a real GPU model

Opens the Browser Fingerprint Inspector with this page's checklist shown at the top of the tool.

Open in the tool →

What headless Chrome signals fingerprinting scripts detect

Headless Chromium produces several passive signals that distinguish it from a real user's browser, and any one of these signals is sufficient for a fingerprinting script to flag the session as automated. navigator.webdriver returns true, which the WebDriver specification explicitly defines as a boolean that must be set to true during any automation session controlled through the Chrome DevTools Protocol.1 navigator.plugins returns an empty PluginArray with length 0, while real desktop Chrome installations always include at least the PDF Viewer plugin and typically several others.2 The User-Agent string from headless Chromium includes "HeadlessChrome" in the comment section, a substring that is completely absent from real Chrome installations on any platform.

Why automation leaves a recognizable profile

WebGL rendering in some headless configurations uses a software renderer (SwiftShader) rather than GPU hardware acceleration, causing the WEBGL_debug_renderer_info UNMASKED_RENDERER_WEBGL string to return "Google SwiftShader" rather than a real GPU model.3 Consequently, a fingerprinting script that checks any of these four signals can identify the Playwright or Puppeteer context.

Building on this, the canvas hash in SwiftShader mode differs from all hardware-rendered canvases, making it a reliable automation detector independent of the webdriver flag. You can confirm the effect by comparing the hash your headless run produces against the hash from a normal Chrome window on the same machine. Because SwiftShader is a shared software renderer, every headless instance generates the same canvas output, so a fingerprinting script does not need behavioral analysis to reach a confident verdict about the session.

How anti-bot systems identify automation

Anti-bot systems combine the passive fingerprint profile with behavioral and timing signals to classify visitors. On the fingerprint side, the combination of webdriver=true, empty plugins, and a SwiftShader WebGL renderer is an unambiguous automation signal. On the behavioral side, mouse movement trajectories in automation differ from human movements; they often follow straight lines or programmatic curves, lack the micro-jitter of real hand movement, and arrive at click targets with unrealistic precision.

How to keep testing honest

Yet even without behavioral analysis, the fingerprint profile alone is sufficient for basic detection. Building on this, the absence of GPU hardware acceleration means the canvas hash computed in headless mode is deterministic and matches the SwiftShader hash that all headless Chrome instances produce, making it a shared signature across all automation runs regardless of the test machine. Furthermore, the CDP WebSocket connection metadata is available to server-side code, and some advanced bot detection services fingerprint the CDP protocol characteristics in addition to the browser environment.

Reducing detection in automation testing

For automation used to test sites that have bot detection as a side effect of fingerprinting, several modifications reduce the detection surface. Setting navigator.webdriver to false via CDP Page.addScriptToEvaluateOnNewDocument prevents the most obvious detection signal by removing the automation flag before any page script executes.4 Passing a realistic User-Agent string through the browser launch options removes the "HeadlessChrome" substring that immediately identifies the headless context.

Using Playwright's launched-browser mode with the system-installed Chrome binary rather than the bundled Chromium enables full hardware GPU acceleration, which replaces the SwiftShader software renderer with a real GPU renderer and produces a canvas hash that matches what a real user's Chrome browser generates on that specific machine, while also populating the navigator.plugins array with the actual plugin list from the system Chrome installation rather than returning an empty array.5

What still needs manual verification

Consequently, the passive fingerprint of an automation session using a real Chrome binary matches a real user on that machine far more closely than headless Chromium with default settings, because the GPU-rendered canvas hash, the real WebGL renderer string, and the authentic plugin list all align with what a legitimate Chrome installation produces on that specific hardware. Building on this, injecting realistic plugins via the navigator.plugins override prevents the empty plugins anomaly that would otherwise signal automation. These techniques are documented here for quality assurance and compatibility testing purposes, not for bypassing access controls on third-party services. CapyToolkit can compare the adjusted automation fingerprint with a real-browser baseline so you can verify which signals remain unrealistic.

When to use this

Use this guide when building browser automation that needs to behave like a real user for QA testing on sites where bot detection interferes with test execution, or when diagnosing which headless signals an automated test exposes to fingerprint-based blocks.

Examples

Checking `navigator.webdriver` in a Playwright session

Before
Default Playwright headless launch: `navigator.webdriver` === true (set by the WebDriver spec; detectable by any fingerprinting script)
After
Using Page.addScriptToEvaluateOnNewDocument to delete `navigator.webdriver` before page scripts run: `navigator.webdriver` === undefined (no longer exposes the automation flag)

This removes one detection signal but does not address empty plugins, SwiftShader WebGL, or the HeadlessChrome UA substring.

Canvas hash: headless Chromium vs real Chrome binary

Before
Playwright with bundled Chromium (SwiftShader): canvas hash = [SwiftShader deterministic hash, same on every machine]
After
Playwright with system Chrome binary and GPU enabled: canvas hash = [real GPU-rendered hash, matches the machine's Chrome browser]
Sources
  1. 1.

    W3C, "WebDriver," w3c.github.io, accessed July 2026. https://w3c.github.io/webdriver/

  2. 2.

    A. Vastel, "Detecting Chrome Headless," antoinevastel.com, 2023. https://arh.antoinevastel.com/bot%20detection/2023/02/19/new-headless-chrome.html

  3. 3.

    Chromium, "SwiftShader," chromium.googlesource.com, accessed July 2026. https://chromium.googlesource.com/chromium/src/+/main/docs/gpu/swiftshader.md

  4. 4.

    Playwright, "Page.addScriptToEvaluateOnNewDocument," playwright.dev, accessed July 2026. https://playwright.dev/docs/api/class-page#page-add-script-to-evaluate-on-new-document

  5. 5.

    Playwright, "Browsers," playwright.dev, accessed July 2026. https://playwright.dev/docs/browsers

FAQ

The WebDriver specification requires that browsers under WebDriver control set navigator.webdriver to true. This is the intended behavior for automation and cannot be changed through browser settings. It can only be overridden by injecting a script that deletes or redefines the property before page scripts run.

Four passive signals distinguish headless Chromium: navigator.webdriver returns true, navigator.plugins is an empty array, the User-Agent contains "HeadlessChrome", and the WebGL renderer may return "Google SwiftShader" instead of a real GPU model. Any one of these is sufficient for basic bot detection.

Yes, significantly. A real Chrome binary enables GPU hardware acceleration, replacing the SwiftShader renderer with a real GPU renderer and producing a realistic canvas hash. The User-Agent no longer contains "HeadlessChrome". You still need to handle navigator.webdriver and plugins separately.

No. Removing navigator.webdriver eliminates the most obvious signal but does not address empty plugins, SwiftShader WebGL, timing anomalies, or behavioral signals like unrealistic mouse movement. Advanced bot detection systems use many signals in combination, not a single flag.

For internal QA and compatibility testing on your own systems, yes; reproducing realistic browser behavior is a legitimate testing goal. CapyToolkit can help you compare the adjusted fingerprint against a real browser baseline. Using these techniques to bypass rate limits, circumvent access controls, or automate actions on third-party sites without authorization is outside the scope of acceptable use.

Additional resources

Guides

How to Reduce Your Browser Fingerprint Practical steps to reduce your browser fingerprint including Firefox resistFingerprinting, Tor Browser, Brave, and canvas-blocking extensions. Lower your uniqueness score. How Browser Fingerprinting Techniques Work How canvas, font, WebGL, AudioContext and Client Hints fingerprinting work, what each one reveals about your device and how browsers block or change each signal. Is Browser Fingerprinting Legal Under GDPR Browser fingerprinting may constitute personal data processing under GDPR and ePrivacy Directive. Consent requirements, legitimate interest, and regulatory enforcement approaches. Safari Fingerprinting on iPhone and Mac What Safari exposes to fingerprinting on iPhone and Mac, what Advanced Fingerprinting Protection in iOS 26 changes, and which signals it leaves untouched. Playwright and Puppeteer Browser Fingerprinting Playwright and Puppeteer expose navigator.webdriver=true, empty plugins, and SwiftShader WebGL in headless mode. How anti-bot systems detect automation and how to test more realistically. Android Chrome Browser Fingerprint Android Chrome exposes navigator.deviceMemory, hardwareConcurrency, and full WebGL renderer strings that iOS Safari restricts. How Android fingerprints differ from iOS, and Brave for Android protection. Windows 11 Browser Fingerprint Windows 11 creates distinctive fingerprints through its exclusive font set, ANGLE WebGL rendering strings, and non-integer DPI scaling options. Which signals are most identifying and how to reduce them.