# Playwright — Administrator & Developer Guide

This guide covers the architecture, internals, deployment, security, and operational concerns of **Playwright v1.60.0-next** — Microsoft's cross-browser end-to-end testing and automation framework. It is written for platform engineers, DevOps teams, CI/CD administrators, and developers who need to understand how Playwright works under the hood, scale it across infrastructure, and troubleshoot production issues.

For installation walkthroughs, everyday CLI usage, test authoring patterns, and feature guides, see the companion [User Guide](/microsoft/playwright/user-guide/).

---

## 1. Architecture Overview

### 1.1 Monorepo Structure

Playwright is organized as an npm workspaces monorepo under `packages/*`. The codebase spans 2,985 files and over 9 million characters of source. Each package has a sharply defined responsibility; understanding these boundaries is essential for anyone modifying or extending the framework.

**Core Packages**

| Package | Role |
|---------|------|
| `playwright` | Main package — test runner, fixtures, expect matchers, reporters, CLI commands (`test`, `show-report`, etc.) |
| `playwright-core` | Core automation library — browser launching, CDP/protocol transport, server components, CLI commands (`install`, `codegen`, `open`, etc.) |
| `playwright-test` | Thin re-export wrapper providing the `@playwright/test` npm package name |
| `playwright-client` | Client-only package (no bundled browser binaries) |

**Browser-Specific Packages**

| Package | Role |
|---------|------|
| `playwright-chromium` | Chromium-only automation package |
| `playwright-firefox` | Firefox-only automation package |
| `playwright-webkit` | WebKit-only automation package |
| `playwright-browser-chromium` | Browser download metadata for Chromium |
| `playwright-browser-firefox` | Browser download metadata for Firefox |
| `playwright-browser-webkit` | Browser download metadata for WebKit |

**Component Testing**

| Package | Role |
|---------|------|
| `playwright-ct-core` | Component testing core — mount fixture, router |
| `playwright-ct-react` | Component testing adapter for React |
| `playwright-ct-react17` | Component testing adapter for React 17 |
| `playwright-ct-vue` | Component testing adapter for Vue |

**UI & Tooling Packages**

| Package | Role |
|---------|------|
| `html-reporter` | HTML report viewer (React SPA) |
| `trace-viewer` | Trace viewer (React SPA) |
| `recorder` | Codegen recorder UI |
| `dashboard` | Dashboard UI |
| `playwright-cli-stub` | CLI stub entry point |

**Internal Shared Packages**

| Package | Role |
|---------|------|
| `protocol` | Protocol type definitions (~259K chars) — the wire protocol spec between client and server |
| `injected` | Scripts injected into browser pages: selectors, clock, highlights, storage, WebSocket mock |
| `isomorphic` | Shared utilities: CSS parser, selector parser, locator generators, image utils, ARIA snapshots |
| `utils` | Node.js utilities: comparators, crypto, debug, env, file utils, host platform detection, profiler, process launcher, zones |
| `trace` | Trace format handling |
| `web` | Shared web UI components |

> [!NOTE]
> The `protocol` package is the single source of truth for the wire format between client and server. All dispatchers and channel interfaces are generated or hand-aligned to match these type definitions. Any protocol change must start here.

### 1.2 Layered Data Flow

Every Playwright operation — whether launched from a test file, the CLI, or a remote connection — follows this layered path:

```
User Code (test files / scripts)
  |
  v
playwright (test runner: fixtures, workers, reporters)
  |
  v
playwright-core (client layer — Browser, Page, Frame API objects)
  |
  v
Protocol (JSON-RPC messages over pipe or WebSocket)
  |
  v
Server (browser management, dispatcher hierarchy)
  |
  v
Chromium / Firefox / WebKit (browser processes)
  |
  v
Injected Scripts (selectors, clock, highlights, storage, WebSocket mock)
```

The client layer constructs protocol messages. The server layer dispatches them to browser processes. The injected scripts run inside the browser's JavaScript context to evaluate selectors, manipulate the clock, and perform DOM operations. This separation means the Node.js process never directly touches the browser DOM — all interaction is mediated by the protocol.

### 1.3 Server Components

**PlaywrightServer** — A WebSocket server that exposes browser automation over the network. Used for remote browser access, grid setups, and the Playwright service. Configured via `run-server` CLI command with `--port`, `--host`, `--path`, `--max-clients`, `--mode`, and `--artifacts-dir` options.

**DispatcherConnection + Dispatcher Hierarchy** — The server-side object graph mirrors the client-side API. Each client-side object (Browser, BrowserContext, Page, Frame, etc.) has a corresponding dispatcher on the server that handles protocol messages and maintains state.

```
RootDispatcher
  └── PlaywrightDispatcher
        ├── BrowserTypeDispatcher
        │     └── BrowserDispatcher
        │           └── BrowserContextDispatcher
        │                 ├── PageDispatcher
        │                 │     └── FrameDispatcher
        │                 │           └── ElementHandleDispatcher
        │                 └── CDPSessionDispatcher
        └── ... (25+ dispatcher classes total)
```

**ServerRegistry** — Manages browser installations. Extends EventEmitter to notify listeners of installation events. Handles download, verification, and path resolution for all three browser engines.

### 1.4 Test Runner Architecture

The test runner (`playwright` package) has four major subsystems:

1. **Configuration** — `FullConfigInternal` parses and validates `playwright.config.ts`. `FullProjectInternal` handles per-project configuration including dependencies and teardown ordering.

2. **Worker Pool** — `WorkerMain` extends `ProcessRunner` to run tests in isolated worker processes. Workers communicate with the main process over IPC. The number of workers is controlled by the `workers` config option (default: `'50%'` of CPU cores).

3. **Fixture System** — `FixtureRunner` and `Fixture` classes implement a dependency-injection system. Fixtures declare dependencies on other fixtures, and the runner resolves the dependency graph, sets up fixtures in order, and tears them down in reverse order.

4. **Tracing** — `TestTracing` manages trace recording per test. Traces capture screenshots, network activity, DOM snapshots, and console output for post-mortem debugging.

### 1.5 Browser Patches

Playwright maintains custom patches for the browsers it drives:

| Directory | Purpose |
|-----------|---------|
| `browser_patches/firefox/` | Firefox Juggler protocol — a custom CDP-like protocol that enables Playwright to control Firefox internals not exposed by standard APIs |
| `browser_patches/webkit/` | WebKit embedder patches for Playwright's WebKit automation |
| `browser_patches/winldd/` | Windows DLL dependency checker utility |

These patches are applied to specific browser revisions that Playwright downloads and manages. This is why Playwright bundles its own browser binaries rather than using system-installed browsers.

### 1.6 Build System

The build toolchain uses a custom esbuild-based builder:

```bash
node utils/build/build.js
```

Key build dependencies:
- **TypeScript** ^5.9.2
- **esbuild** — fast bundling for packages
- **Vite** — UI packages (html-reporter, trace-viewer, recorder, dashboard)
- **React / React-DOM** — UI component rendering

---

## 2. System Requirements

### 2.1 Runtime Requirements

| Requirement | Minimum |
|-------------|---------|
| Node.js | 18 or later |
| npm | 8+ (ships with Node 18+) |
| Disk space | ~500 MB per browser engine (Chromium, Firefox, WebKit) |
| RAM | 2 GB minimum for single browser; 4+ GB recommended for parallel execution |

### 2.2 Supported Platforms

Playwright supports these host platforms for running tests:

| OS | Architectures |
|----|---------------|
| Ubuntu 20.04, 22.04, 24.04 (and Debian derivatives) | x64, arm64 |
| macOS 13 (Ventura), 14 (Sonoma), 15 (Sequoia) | x64, arm64 (Apple Silicon) |
| Windows 10, 11, Server 2019, Server 2022 | x64 |

> [!IMPORTANT]
> Windows ARM64 support is not yet available (tracked in issue #40202). Ubuntu 26.04 support is tracked in issue #40117. The platform detection logic in `utils/` will throw "Unsupported platform: ..." for unrecognized host platforms.

### 2.3 System Dependencies (Linux)

On Linux, browsers require system shared libraries. Use the built-in dependency installer:

```bash
# Install system dependencies for all browsers
npx playwright install-deps

# Install dependencies for a specific browser
npx playwright install-deps chromium
```

For Docker environments, Playwright provides pre-built images (see Section 4.3).

### 2.4 Browser Installation Paths

Browser binaries are stored at platform-specific default locations unless overridden:

| Platform | Default Path |
|----------|-------------|
| Linux | `$XDG_CACHE_HOME/ms-playwright` (defaults to `~/.cache/ms-playwright`) |
| macOS | `~/Library/Caches/ms-playwright` |
| Windows | `%LOCALAPPDATA%\ms-playwright` |

Override with `PLAYWRIGHT_BROWSERS_PATH`:

```bash
# Store browsers in a shared directory
export PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers
npx playwright install
```

---

## 3. Configuration Reference

### 3.1 Config File Resolution

Playwright looks for configuration in this order:
1. `playwright.config.ts`
2. `playwright.config.js`
3. `playwright.config.mjs`
4. `playwright.config.cjs`

The config file location determines the default `testDir` (the directory containing the config file).

### 3.2 Top-Level Configuration Options

The `FullConfigInternal` constructor defines every valid top-level option. Below is the complete reference:

```typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  // --- Test Discovery ---
  testDir: './tests',                    // Test directory (default: config file directory)
  testMatch: '**/*.@(spec|test).?(c|m)[jt]s?(x)', // Test file pattern
  testIgnore: undefined,                 // Glob patterns to ignore

  // --- Execution Control ---
  fullyParallel: false,                  // Run ALL tests in parallel (not just across files)
  workers: '50%',                        // Number or percentage of CPU cores
  retries: 0,                            // Retry count for failed tests
  repeatEach: 1,                         // Repeat each test N times
  maxFailures: 0,                        // Stop after N failures (0 = unlimited)
  timeout: 30000,                        // Per-test timeout in ms
  globalTimeout: 0,                      // Global timeout (0 = unlimited)
  forbidOnly: false,                     // Fail CI if test.only is present
  failOnFlakyTests: false,               // Treat flaky tests as failures

  // --- Filtering ---
  grep: /.*/,                            // Filter tests by title regex
  grepInvert: undefined,                 // Exclude tests matching regex
  tag: undefined,                        // Global tags (must start with @)

  // --- Output ---
  outputDir: 'test-results',             // Test artifacts directory
  preserveOutput: 'always',             // 'always' | 'never' | 'failures-only'
  quiet: false,                          // Suppress stdio
  reporter: [['list']],                  // Reporter configuration
  reportSlowTests: { max: 5, threshold: 300000 }, // Slow test reporting

  // --- Snapshots ---
  updateSnapshots: 'missing',            // 'all' | 'none' | 'missing'
  updateSourceMethod: 'patch',           // 'patch' | 'overwrite'
  ignoreSnapshots: false,                // Skip snapshot assertions
  respectGitIgnore: true,               // Honor .gitignore for snapshots

  // --- Setup/Teardown ---
  globalSetup: undefined,                // Path(s) to global setup file
  globalTeardown: undefined,             // Path(s) to global teardown file

  // --- Sharding ---
  shard: undefined,                      // { current: N, total: M }

  // --- Projects ---
  projects: [],                          // Array of project configurations

  // --- Web Server ---
  webServer: undefined,                  // Auto-start server config (single or array)

  // --- Metadata ---
  metadata: {},                          // Custom metadata object
  captureGitInfo: false,                 // Capture git info in test metadata

  // --- TypeScript ---
  tsconfig: undefined,                   // Custom TypeScript config path
});
```

> [!IMPORTANT]
> The `workers` option accepts either a number (`4`) or a percentage string (`'50%'`). Passing an invalid value triggers the error: "Workers ... must be a number or percentage". In CI environments, percentage-based workers automatically scale to the available cores.

### 3.3 Project-Level Configuration

Projects allow running the same tests against different browsers or configurations:

```typescript
export default defineConfig({
  projects: [
    {
      name: 'chromium',
      testDir: './tests',
      testMatch: '**/*.spec.ts',
      testIgnore: '**/mobile/**',
      outputDir: 'test-results/chromium',
      snapshotDir: './snapshots',
      snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
      timeout: 30000,
      retries: 2,
      repeatEach: 1,
      grep: /.*/,
      grepInvert: undefined,
      metadata: {},
      fullyParallel: true,
      ignoreSnapshots: false,
      respectGitIgnore: true,
      use: {
        browserName: 'chromium',
        headless: true,
        viewport: { width: 1280, height: 720 },
      },
      dependencies: ['setup'],         // Run 'setup' project first
      teardown: 'cleanup',             // Run 'cleanup' project after
    },
    {
      name: 'setup',
      testMatch: /global\.setup\.ts/,
    },
    {
      name: 'cleanup',
      testMatch: /global\.teardown\.ts/,
    },
  ],
});
```

**Dependency rules enforced by the config validator:**
- A project listed in `dependencies` must exist by name — "Project ... depends on unknown project ..." is thrown otherwise.
- A teardown project must not itself declare dependencies — "Teardown project ... must not have dependencies" is the error for violations.

### 3.4 Reporter Configuration

Built-in reporters:

| Reporter | Output | Best For |
|----------|--------|----------|
| `list` | Detailed per-test output | Local development (default for terminal) |
| `line` | One-line-per-test updates | Compact terminal output |
| `dot` | Dots for pass/fail | CI environments (default when `CI` env var is set) |
| `json` | JSON to stdout | Programmatic consumption |
| `junit` | JUnit XML | CI/CD integration (Jenkins, GitLab, etc.) |
| `html` | Interactive HTML report | Post-run analysis and sharing |
| `blob` | Binary blob | Merge sharded results |
| `github` | GitHub Actions annotations | GitHub Actions workflows |
| `null` | No output | Suppressing output entirely |

Multiple reporters can be active simultaneously:

```typescript
reporter: [
  ['list'],
  ['junit', { outputFile: 'results.xml' }],
  ['html', { open: 'never' }],
],
```

### 3.5 Web Server Configuration

Auto-start a dev server before tests:

```typescript
webServer: {
  command: 'npm run dev',
  url: 'http://localhost:3000',
  reuseExistingServer: !process.env.CI,
  timeout: 120000,
  stdout: 'pipe',
  stderr: 'pipe',
},
```

Multiple servers are supported by passing an array.

---

## 4. Deployment & Scaling

### 4.1 CI/CD Integration

**Sharding across machines:**

```bash
# Machine 1
npx playwright test --shard=1/4

# Machine 2
npx playwright test --shard=2/4

# Machine 3
npx playwright test --shard=3/4

# Machine 4
npx playwright test --shard=4/4
```

Merge sharded results using the blob reporter:

```bash
# Each shard produces a blob
npx playwright test --shard=1/4 --reporter=blob

# Merge all blobs into a single HTML report
npx playwright merge-reports --reporter=html ./blob-reports
```

**Caching browser binaries in CI:**

```bash
# Cache key based on Playwright version
PLAYWRIGHT_VERSION=$(npx playwright --version)
# Cache directory: $PLAYWRIGHT_BROWSERS_PATH or default location

# GitHub Actions example
- uses: actions/cache@v4
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ hashFiles('package-lock.json') }}
```

> [!TIP]
> Set `PLAYWRIGHT_BROWSERS_PATH` to a directory within your CI cache path for reliable cache hits. The `install --dry-run` command shows what would be installed without downloading, useful for verifying cache coverage.

### 4.2 Remote Browser Execution

**Running a Playwright Server:**

```bash
# Start a remote browser server
npx playwright run-server \
  --port 3000 \
  --host 0.0.0.0 \
  --path /ws \
  --max-clients 10 \
  --mode default \
  --artifacts-dir /tmp/pw-artifacts
```

**Launching via config file:**

```bash
# launch-config.json
{
  "browser": "chromium",
  "headless": true,
  "port": 3000
}

npx playwright launch-server --config launch-config.json
```

**Connecting from tests:**

```typescript
// Connect to a remote browser server
const browser = await chromium.connect('ws://remote-host:3000/ws');
```

Or via environment variables:

```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://remote-host:3000/ws npx playwright test
PW_TEST_CONNECT_HEADERS='{"Authorization":"Bearer token"}' npx playwright test
PW_TEST_CONNECT_EXPOSE_NETWORK="*" npx playwright test
```

### 4.3 Docker Deployment

Playwright provides Docker tooling in `utils/docker/` for building images with pre-installed browsers and system dependencies.

**Using the official Docker images:**

```dockerfile
FROM mcr.microsoft.com/playwright:v1.60.0-focal

WORKDIR /app
COPY package*.json ./
RUN npm ci
RUN npx playwright install --with-deps
COPY . .

CMD ["npx", "playwright", "test"]
```

**Marking custom Docker images:**

```bash
# Mark a Docker image so Playwright skips browser compatibility checks
npx playwright mark-docker-image
```

> [!TIP]
> In Docker/CI environments, always use `--with-deps` during `npx playwright install` to ensure system libraries are present. Without it, browsers will fail to launch with missing shared library errors.

### 4.4 Worker Scaling

The `workers` configuration controls parallelism:

```typescript
// Fixed count
workers: 4,

// Percentage of available CPUs
workers: '50%',

// Single worker (serial execution)
workers: 1,
```

**Scaling considerations:**
- Each worker is a separate Node.js process running one or more browser instances
- Memory usage scales linearly with worker count — budget ~300-500 MB per worker with a single browser
- CPU-bound test suites benefit from worker counts up to the number of physical cores
- I/O-bound suites (network-heavy tests) can exceed core count effectively
- Set `fullyParallel: true` to parallelize tests within a single file across workers (default only parallelizes across files)

### 4.5 Browser Garbage Collection

Playwright automatically garbage-collects old browser versions. Control this behavior:

```bash
# Skip browser GC (useful in shared/cached environments)
export PLAYWRIGHT_SKIP_BROWSER_GC=1
npx playwright install
```

Use `npx playwright install --list` to see all installed browser versions across all Playwright installations on the system.

---

## 5. Operations

### 5.1 Browser Management

**Installation commands:**

```bash
# Install all browsers
npx playwright install

# Install specific browser
npx playwright install chromium
npx playwright install firefox
npx playwright install webkit

# Install with system dependencies (Linux)
npx playwright install --with-deps

# Dry run — show what would be installed
npx playwright install --dry-run

# List all installed browsers
npx playwright install --list

# Custom install path
PLAYWRIGHT_BROWSERS_PATH=/shared/browsers npx playwright install
```

**Custom registry:**

```bash
# Use a custom server for browser downloads (air-gapped environments)
export PLAYWRIGHT_SERVER_REGISTRY=https://internal-mirror.company.com/playwright
npx playwright install
```

> [!NOTE]
> The `PLAYWRIGHT_SERVER_REGISTRY` environment variable redirects all browser download requests to a custom URL. This is essential for air-gapped or restricted network environments. The registry must mirror the same directory structure as the default Playwright CDN.

### 5.2 Debugging Facilities

**Playwright Inspector:**

```bash
# Launch with Inspector attached
PWDEBUG=1 npx playwright test

# Pause at end of test
PWPAUSE=1 npx playwright test
```

**Debug logging:**

```bash
# Enable protocol-level debug output
DEBUG=pw:api npx playwright test

# Enable all Playwright debug output
DEBUG=pw:* npx playwright test

# Write debug output to a file
DEBUG=pw:* DEBUG_FILE=playwright-debug.log npx playwright test
```

**Runner-level debugging:**

```bash
# Enable test runner debug output
PW_RUNNER_DEBUG=1 npx playwright test
```

**Trace recording:**

```bash
# Enable tracing for all tests
PWTEST_TRACE=1 npx playwright test

# View a trace file
npx playwright show-trace trace.zip
```

### 5.3 Report Management

**HTML reports:**

```bash
# Generate and auto-open HTML report
npx playwright show-report

# Custom report title
PLAYWRIGHT_HTML_TITLE="Nightly Regression" npx playwright test --reporter=html

# Merge sharded reports
npx playwright merge-reports --reporter=html ./blob-reports
```

**JUnit for CI:**

```bash
npx playwright test --reporter=junit > results.xml
```

### 5.4 Codegen and Recording

```bash
# Record user actions and generate test code
npx playwright codegen https://example.com

# Open a specific browser for manual testing
npx playwright open --browser=firefox https://example.com
```

### 5.5 Driver Mode

For language bindings (Python, Java, C#, Go), Playwright provides a pipe-based driver:

```bash
# Start the driver (used by non-Node.js SDKs)
npx playwright run-driver

# Configure SDK language name
PW_LANG_NAME=python npx playwright run-driver
```

> [!NOTE]
> The `run-driver` command starts a JSON-RPC server over stdin/stdout pipes. The Python, Java, and C# Playwright SDKs use this to communicate with the Node.js server process. `PW_LANG_NAME` controls which SDK-specific behaviors are activated in the server.

---

## 6. Performance

### 6.1 Test Execution Optimization

**Parallelism tuning:**

| Scenario | Recommended `workers` | `fullyParallel` |
|----------|----------------------|-----------------|
| Local dev, fast feedback | `'50%'` (default) | `false` |
| CI with ample resources | Number of cores | `true` |
| CI with constrained RAM | `2`-`4` | `false` |
| Debugging a single test | `1` | `false` |
| Flake detection | `1` with `repeatEach: 10` | `false` |

**Slow test detection:**

The default `reportSlowTests` config flags tests exceeding 5 minutes (300,000 ms) and reports up to 5 of them. Adjust for your suite:

```typescript
reportSlowTests: {
  max: 10,          // Report up to 10 slow tests
  threshold: 60000, // Flag anything over 1 minute
},
```

### 6.2 Browser Context Reuse

For test suites where browser startup is a bottleneck:

```bash
# Reuse browser context across tests (experimental)
PW_TEST_REUSE_CONTEXT=1 npx playwright test
```

> [!CAUTION]
> Context reuse skips browser context teardown between tests. This speeds up execution but means tests share cookies, localStorage, and other state. Only use this when tests are designed for shared state, or in combination with explicit cleanup in `beforeEach` hooks.

### 6.3 Module Instrumentation

For diagnosing slow startup:

```bash
# Profile module loading times
PW_INSTRUMENT_MODULES=1 npx playwright test
```

This logs the time taken to load each module, helping identify slow `require()`/`import()` chains.

### 6.4 Snapshot Update Strategies

| Strategy | `updateSnapshots` | Use Case |
|----------|-------------------|----------|
| Add new only | `'missing'` (default) | Normal development |
| Regenerate all | `'all'` | After intentional visual changes |
| Strict match | `'none'` | CI — fail on any missing snapshot |

The `updateSourceMethod` option controls how test source files are modified when updating inline snapshots:
- `'patch'` (default) — applies minimal diffs
- `'overwrite'` — replaces the entire file

---

## 7. Security

### 7.1 Threat Model

Playwright executes arbitrary web content in browser processes. The security boundary is:

```
Node.js process (trusted) → Protocol → Browser (sandboxed) → Web content (untrusted)
```

Key security considerations:

1. **Browser sandbox** — Playwright browsers run with their standard sandboxing. Chromium's multi-process sandbox, Firefox's content process isolation, and WebKit's WebProcess isolation all apply.

2. **Injected scripts** — Scripts from the `injected` package run in the browser's main world. They have access to the page DOM and JavaScript context. These scripts are trusted code injected by Playwright, not by the web page.

3. **Remote server access** — `PlaywrightServer` exposes browser automation over WebSocket. Anyone with network access to the server can control browsers, navigate to arbitrary URLs, and execute JavaScript.

> [!WARNING]
> The `run-server` command with `--host 0.0.0.0` exposes browser automation to the network. There is no built-in authentication. Use network-level controls (firewalls, VPNs, private networks) to restrict access. In production grid setups, place the server behind an authenticating reverse proxy.

### 7.2 Sensitive Environment Variables

These variables carry credentials and should be treated as secrets in CI/CD:

| Variable | Contains |
|----------|----------|
| `PLAYWRIGHT_SERVICE_ACCESS_KEY` | Authentication key for Playwright hosted service |
| `PW_TEST_CONNECT_HEADERS` | Custom headers (may contain auth tokens) for remote connections |

> [!WARNING]
> Never log or echo `PLAYWRIGHT_SERVICE_ACCESS_KEY` or `PW_TEST_CONNECT_HEADERS` in CI output. Use masked/secret variable features of your CI platform.

### 7.3 Network Exposure

**`webServer` configuration** — The `webServer` option starts a local development server. Ensure it binds only to `localhost` in CI environments to prevent unintended network exposure.

**`PW_TEST_CONNECT_EXPOSE_NETWORK`** — When connecting to a remote browser server, this variable controls which network targets the remote browser can access. Setting it to `"*"` grants access to all networks reachable from the server.

### 7.4 File System Access

Playwright writes to several directories:

| Directory | Contents | Sensitivity |
|-----------|----------|-------------|
| `test-results/` (or `outputDir`) | Screenshots, videos, traces, downloads | May contain application data |
| Browser cache directory | Browser binaries and profiles | Contains cached web data |
| `playwright-report/` | HTML reports | May contain screenshots of application state |
| Trace files | Full DOM snapshots, network data, console logs | High — may contain PII or secrets visible in the application |

> [!CAUTION]
> Trace files and HTML reports can contain sensitive application data including screenshots, network request/response bodies, cookies, and console output. Treat these artifacts with the same sensitivity as the application under test. Do not publish them to public storage without review.

### 7.5 TypeScript and Code Execution

Playwright's config file (`playwright.config.ts`) is executed as code. The test runner uses Node.js options for TypeScript support:

```bash
# Disable TypeScript ESM loader if it causes issues
PW_DISABLE_TS_ESM=1 npx playwright test
```

The `NODE_OPTIONS` environment variable is used internally to register the TypeScript loader. Be aware that overriding `NODE_OPTIONS` in your environment may interfere with Playwright's TypeScript support.

---

## 8. Developer Internals

### 8.1 Protocol Layer

The `protocol` package defines the complete wire protocol (~259K characters of type definitions). Communication between client and server uses JSON-RPC:

- **Pipe transport** — Used for in-process communication (default when launching browsers locally). The Node.js process communicates with the browser server over stdin/stdout pipes.
- **WebSocket transport** — Used for remote connections. The `PlaywrightServer` hosts a WebSocket endpoint that accepts JSON-RPC messages.

### 8.2 Dispatcher System

The dispatcher hierarchy is the server-side counterpart to the client API. There are 25+ dispatcher classes:

**Core dispatchers:**
- `Dispatcher` — base class with serialization, event emission, and lifecycle management
- `RootDispatcher` — root of the dispatcher tree for a connection
- `DispatcherConnection` — manages the full dispatcher tree and protocol message routing
- `PlaywrightDispatcher` — top-level dispatcher exposing browser types and devices

**Browser lifecycle:**
- `BrowserTypeDispatcher` → `BrowserDispatcher` → `BrowserContextDispatcher` → `PageDispatcher` → `FrameDispatcher` → `ElementHandleDispatcher`

**Supporting dispatchers:**
- `CDPSessionDispatcher` — raw CDP protocol access (Chromium only)
- Plus dispatchers for Dialog, Download, Request, Response, Route, WebSocket, Worker, etc.

### 8.3 Injected Script System

The `injected` package contains scripts that run inside browser page contexts:

| Class | Purpose |
|-------|---------|
| `InjectedScript` | Main entry point — selector evaluation, element interaction, waiting |
| `SelectorEvaluatorImpl` | CSS and custom selector engine evaluation |
| `BindingsController` | Manages page bindings (exposing Node.js functions to the page) |
| `ClockController` | Fake timers and clock manipulation |
| `ConsoleAPI` | Console message interception |
| `Highlight` | Element highlighting for codegen and debugging |
| `StorageScript` | localStorage/sessionStorage manipulation |
| `UtilityScript` | Shared utilities for injected code |
| `WebSocketMock` | WebSocket interception and mocking |

These scripts are bundled at build time and injected via the protocol's `evaluateExpression` mechanism.

### 8.4 Selector Engine Architecture

The `isomorphic` package contains the selector parsing and evaluation infrastructure:

- **CSS Parser** — `CSSParserToken` with 20+ token subclasses, handles the full CSS selector syntax
- **Selector Parser** — Parses Playwright's extended selector syntax (`text=`, `css=`, `xpath=`, `role=`, chained selectors with `>>`)
- **Locator Generators** — Language-specific code generators that produce locator expressions:
  - `JavaScriptLocatorFactory`
  - `PythonLocatorFactory`
  - `JavaLocatorFactory`
  - `CSharpLocatorFactory`

These are used by the codegen recorder to produce test code in the target language.

### 8.5 Fixture System Internals

The `FixtureRunner` resolves a dependency graph of fixtures:

1. Each `Fixture` instance declares its dependencies (other fixtures it needs)
2. The runner topologically sorts the dependency graph
3. Setup runs in dependency order; teardown runs in reverse
4. Fixtures can be scoped to `test` (per-test) or `worker` (per-worker process)

**Error conditions:**
- "Cannot provide fixture value for the second time" — a fixture's `use()` callback was invoked more than once
- "use() was not called in fixture ..." — a fixture function completed without calling the provided `use()` function
- "Playwright detected inconsistent test.use() options" — conflicting `use()` declarations across test files sharing a worker

### 8.6 Shared Utilities

The `utils` package provides Node.js-level infrastructure:

| Module | Purpose |
|--------|---------|
| `comparators` | Image comparison (pixel diff, SSIM) |
| `crypto` | Hashing and random ID generation |
| `debug` | Debug logging (integrates with the `debug` npm package) |
| `env` | Environment variable reading and validation |
| `fileUtils` | File I/O helpers with atomic writes |
| `hostPlatform` | Host OS/architecture detection (overridable via `PLAYWRIGHT_HOST_PLATFORM_OVERRIDE`) |
| `profiler` | Performance measurement |
| `processLauncher` | Cross-platform process spawning with cleanup |
| `zones` | Async context tracking (Zone.js-like) |

The `isomorphic` package also provides:
- `LRUCache` — least-recently-used cache
- `ManualPromise` — externally resolvable Promise
- `Semaphore` — concurrency limiter
- `MultiMap` — map with multiple values per key
- `InvalidSelectorError` — typed error for selector parsing failures

### 8.7 ARIA Snapshot System

The `isomorphic` package includes ARIA snapshot generation — a tree-based representation of the accessibility structure of a page. This powers the `toMatchAriaSnapshot()` assertion in the test runner.

---

## 9. Integration Points

### 9.1 Playwright Service

Playwright can connect to Microsoft's hosted service or a self-hosted equivalent:

```bash
PLAYWRIGHT_SERVICE_URL=https://playwright-service.example.com
PLAYWRIGHT_SERVICE_ACCESS_KEY=your-key
PLAYWRIGHT_SERVICE_RUN_ID=unique-run-id
PLAYWRIGHT_SERVICE_OS=linux  # or windows
```

### 9.2 VS Code Extension

Playwright integrates with VS Code through the official extension. Known issue #40226 tracks cases where the extension fails to discover tests.

### 9.3 Component Testing

The component testing packages (`playwright-ct-*`) integrate with framework build tools:

```typescript
// playwright-ct.config.ts
import { defineConfig } from '@playwright/experimental-ct-react';

export default defineConfig({
  use: {
    ctPort: 3100,
    ctTemplateDir: './playwright',
  },
});
```

The `PLAYWRIGHT_TEST_BASE_URL` environment variable overrides the component test server URL.

### 9.4 Dashboard

The `dashboard` package provides a UI for viewing test results. Enable via:

```bash
PLAYWRIGHT_DASHBOARD=1 npx playwright test
```

### 9.5 Custom Sockets Directory

For environments with restrictions on the default socket path:

```bash
PLAYWRIGHT_SOCKETS_DIR=/custom/path/sockets npx playwright test
```

---

## 10. Troubleshooting

### 10.1 Browser Launch Failures

**Error**: `Unsupported browser ...`
- **Cause**: Passed a browser name other than `chromium`, `firefox`, or `webkit`
- **Solution**: Use one of the three supported browser names
- **Prevention**: Validate browser names in your config against the allowed set

**Error**: `Directory does not exist: ...`
- **Cause**: The configured `testDir`, `outputDir`, or other path does not exist on disk
- **Solution**: Create the directory or correct the path in `playwright.config.ts`
- **Prevention**: Use relative paths anchored to the config file location

**Error**: Browser fails to launch with missing shared library errors (Linux)
- **Cause**: System dependencies not installed
- **Solution**: Run `npx playwright install-deps` or use the `--with-deps` flag
- **Prevention**: Use Playwright Docker images or include `install-deps` in your CI setup

> [!TIP]
> The `npx playwright install --dry-run` command shows exactly which browsers would be downloaded and their expected paths, without performing any downloads. Use this to verify your CI cache is correctly configured.

### 10.2 Configuration Errors

**Error**: `Cannot use --browser option when configuration file defines projects`
- **Cause**: The `--browser` CLI flag conflicts with project-based configuration
- **Solution**: Remove `--browser` from the CLI and configure browsers in `projects` instead
- **Prevention**: Choose one approach — CLI flags for simple setups, projects for multi-browser

**Error**: `Tag must start with @ symbol`
- **Cause**: A tag in config or CLI does not begin with `@`
- **Solution**: Prefix all tags with `@` (e.g., `@smoke`, `@regression`)

**Error**: `Workers ... must be a number or percentage`
- **Cause**: Invalid `workers` value (e.g., a non-numeric string)
- **Solution**: Use a positive integer or a percentage string like `'50%'`

**Error**: `Project ... depends on unknown project ...`
- **Cause**: A `dependencies` entry references a project name that does not exist
- **Solution**: Verify project names match exactly (case-sensitive)

**Error**: `Teardown project ... must not have dependencies`
- **Cause**: A project designated as `teardown` also declares `dependencies`
- **Solution**: Remove `dependencies` from the teardown project — it runs unconditionally after its parent

> [!NOTE]
> The error "Playwright detected inconsistent test.use() options" occurs when tests in the same worker process declare different `use()` options. Either move conflicting tests to separate projects or ensure consistent `use()` declarations within each project.

### 10.3 Runtime Issues

**Error**: `Unexpected browserName ..., must be one of chromium, firefox or webkit`
- **Cause**: The `use.browserName` option in config or `test.use()` has a typo or invalid value
- **Solution**: Set `browserName` to exactly `'chromium'`, `'firefox'`, or `'webkit'`

**Issue**: Tests stuck at `about:blank` (GitHub #31050, 50+ comments)
- **Cause**: Navigation race conditions, especially with single-page apps
- **Solution**: Use `waitUntil: 'networkidle'` or explicit waiting for application-specific elements rather than relying on default navigation completion

**Issue**: Proxy authentication hangs (GitHub #40194)
- **Cause**: Browser-level proxy auth dialogs are not automatically handled
- **Solution**: Provide proxy credentials in the proxy configuration object rather than relying on interactive authentication

**Issue**: Dialog handler not working as expected (GitHub #11014, 37 comments)
- **Cause**: Dialog handlers must be registered before the action that triggers the dialog
- **Solution**: Always call `page.on('dialog', handler)` before the click or navigation that produces the dialog

> [!CAUTION]
> The `--only-changed` flag is not supported in UI mode. Attempting to use it produces: "--only-changed is not supported in UI mode". Use CLI mode for changed-file-only test execution.

### 10.4 Android Automation

**Error**: `No devices found`
- **Cause**: No Android device connected or ADB not configured
- **Solution**: Connect a device via USB with USB debugging enabled, or start an emulator

**Error**: `More than one device found. Please specify deviceSerialNumber`
- **Cause**: Multiple Android devices/emulators are connected
- **Solution**: Pass the `deviceSerialNumber` option to specify which device to use. List devices with `adb devices`.

### 10.5 WebKit-Specific Issues

- **Issue #40268**: WebKit WASM — WebAssembly-related failures in WebKit
- **Issue #40244**: WebKit `formData()` — FormData parsing issues in WebKit

These are browser-engine-level issues tracked upstream in the Playwright patched WebKit build.

### 10.6 TypeScript Issues

**Issue #38586**: TypeScript `declare` keyword handling
- Certain TypeScript declaration patterns may not be recognized by Playwright's TypeScript loader

**Disabling TypeScript ESM loader:**

```bash
PW_DISABLE_TS_ESM=1 npx playwright test
```

Use this when the experimental TypeScript ESM loader conflicts with your project's module setup.

---

## Appendix A: Complete Environment Variable Reference

| Variable | Purpose | Default |
|----------|---------|---------|
| `PLAYWRIGHT_BROWSERS_PATH` | Custom browser installation directory | Platform default (see Section 2.4) |
| `PLAYWRIGHT_SKIP_BROWSER_GC` | Skip browser garbage collection | Not set |
| `PLAYWRIGHT_SERVER_REGISTRY` | Custom browser download registry URL | Official CDN |
| `PLAYWRIGHT_HOST_PLATFORM_OVERRIDE` | Override host platform detection | Auto-detected |
| `PLAYWRIGHT_SOCKETS_DIR` | Custom sockets directory | OS default |
| `PLAYWRIGHT_NO_COPY_PROMPT` | Disable copy prompt in CLI tools | Not set |
| `PLAYWRIGHT_HTML_TITLE` | Custom HTML report title | "Playwright Test Report" |
| `PLAYWRIGHT_DASHBOARD` | Enable dashboard binding | Not set |
| `PLAYWRIGHT_TEST_BASE_URL` | Base URL for component tests | Not set |
| `PLAYWRIGHT_SERVICE_URL` | Playwright service URL | Not set |
| `PLAYWRIGHT_SERVICE_ACCESS_KEY` | Playwright service auth key | Not set |
| `PLAYWRIGHT_SERVICE_RUN_ID` | Playwright service run ID | Not set |
| `PLAYWRIGHT_SERVICE_OS` | Playwright service OS | Not set |
| `PWDEBUG` | Enable Playwright Inspector (set to `1`) | Not set |
| `PWPAUSE` | Pause at test end | Not set |
| `PWTEST_MODE` | Test mode override | Not set |
| `PWTEST_TRACE` | Enable tracing in tests | Not set |
| `PW_CLI_DISPLAY_VERSION` | Override displayed CLI version | Package version |
| `PW_EXTENSION_MODE` | Enable extension mode | Not set |
| `PW_LANG_NAME` | SDK language name for driver | Not set |
| `PW_INSTRUMENT_MODULES` | Enable module load instrumentation | Not set |
| `PW_RUNNER_DEBUG` | Enable runner debug output | Not set |
| `PW_TEST_REUSE_CONTEXT` | Reuse browser context | Not set |
| `PW_TEST_CONNECT_WS_ENDPOINT` | WebSocket endpoint for remote connection | Not set |
| `PW_TEST_CONNECT_HEADERS` | Custom headers for remote connection | Not set |
| `PW_TEST_CONNECT_EXPOSE_NETWORK` | Expose network for remote connection | Not set |
| `PW_DISABLE_TS_ESM` | Disable TypeScript ESM loader | Not set |
| `DEBUG` | Debug namespace (uses `debug` npm package) | Not set |
| `DEBUG_FILE` | Write debug output to file | Not set |
| `NODE_OPTIONS` | Node.js options (used for TS loader) | Not set |
| `XDG_CACHE_HOME` | XDG cache directory (Linux browser path) | `~/.cache` |
| `LOCALAPPDATA` | Local app data (Windows browser path) | System default |

## Appendix B: Key Source Locations

| Component | Path |
|-----------|------|
| Test runner entry | `packages/playwright/` |
| Core automation | `packages/playwright-core/` |
| Protocol definitions | `packages/protocol/` |
| Injected scripts | `packages/injected/` |
| Selector/locator utilities | `packages/isomorphic/` |
| Node.js utilities | `packages/utils/` |
| Dispatcher hierarchy | `packages/playwright-core/src/server/dispatchers/` |
| Browser patches | `browser_patches/` |
| Docker tooling | `utils/docker/` |
| Build system | `utils/build/build.js` |
| HTML reporter UI | `packages/html-reporter/` |
| Trace viewer UI | `packages/trace-viewer/` |
| Codegen recorder UI | `packages/recorder/` |

---

_Generated May 2026 from microsoft/playwright at 5790370. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
