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.

ZERO UPLOAD · ALL LOCAL
  1. The scan runs automatically when you open this page — no input needed.
  2. Each section shows a group of signals your browser exposes. Rows marked TRACKABLE are the highest-entropy signals used to identify you.
  3. The entropy score at the top estimates how uniquely identifiable your browser is across the web.
  4. Use the Copy buttons next to any row to copy that value to your clipboard.
  5. The Installed Fonts section lists which fonts from a 30-font probe were detected on your system.

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
Scanning browser APIs…
~0 bits

Analysing fingerprint…

27+ bits VERY HIGH
19 – 26 bits HIGH
9 – 18 bits MODERATE
0 – 8 bits LOW

IDENTITY

USER AGENTTRACKABLE
APP VERSION
PLATFORM
VENDOR
WEBDRIVER

HARDWARE

CPU THREADS
DEVICE MEMORY
SCREEN RESOLUTIONTRACKABLE
AVAILABLE SCREEN
COLOUR DEPTH
PIXEL DEPTH
PIXEL RATIO
ORIENTATION
TOUCH POINTS
BATTERY LEVEL
BATTERY CHARGING

GRAPHICS

CANVAS HASHTRACKABLE
WEBGL VENDOR
WEBGL RENDERERTRACKABLE
WEBGL EXT COUNT
WEBGL EXTENSIONS
MAX TEXTURE SIZE
WEBGL 2
WEBGPU

AUDIO

AUDIO FINGERPRINTTRACKABLE
SAMPLE RATE
BASE LATENCY

NETWORK & PRIVACY

ONLINE
DO NOT TRACK
COOKIES ENABLED
CONNECTION TYPE
DOWNLINK
RTT
SAVE DATA

BROWSER ENVIRONMENT

LANGUAGE
LANGUAGESTRACKABLE
TIMEZONETRACKABLE
TIMEZONE OFFSET
PLUGIN COUNT
PLUGINS
LOCAL STORAGE
SESSION STORAGE
INDEXEDDB
WEBSQL
CODEC H.264
CODEC VP8
CODEC VP9
CODEC AV1
CODEC HEVC
SPEECH VOICES
VOICE NAMES

SYSTEM PREFERENCES

COLOUR SCHEME
REDUCED MOTION
CONTRAST
POINTER
HOVER
FORCED COLOURS

INSTALLED FONTS

INSTALLED FONTSTRACKABLE
Show detected fonts (30 probed)

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.

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