ScreenshotNeo

BlogComparisons

Playwright Headless vs. Headed

Choose Playwright headless for CI and headed for visual debugging, with runnable code, CI display setup, Chromium details, and fixes.

By the ScreenshotNeo team1 October 20265 min read

Short answer: Playwright is headless by default. Use headless for unattended tests and CI; use headed when you need to watch a browser, inspect interactions, or debug with the Playwright Inspector. Switch with npx playwright test --headed or chromium.launch({ headless: false }).

The choice changes visibility, display requirements, and the Chromium build Playwright starts. It does not replace diagnostics: traces, screenshots, videos, logs, and UI Mode can make a headless failure understandable without opening a window.

Headless vs. headed at a glance

Question Headless Headed
Window visible? No; observe results through the runner and artifacts. Yes; watch the browser directly.
Best fit Automated local runs and CI. Interactive debugging, demos, and rendering diagnosis.
Configuration headless: true or omit it. headless: false or --headed.
Display needed? No visible display in the normal workflow. Yes locally; CI commonly uses Xvfb.
Chromium build Separate headless shell by default when no channel is specified. Regular Chromium build.

See Playwright’s debugging documentation and browser documentation.

When to use headless

  • Run unattended tests in CI and containers.
  • Avoid display-server dependencies.
  • Collect reports, traces, screenshots, videos, logs, or UI Mode artifacts.
npx playwright test

Playwright Test is headless by default.

When to use headed

  • Watch navigation, clicks, scrolling, and popups.
  • Use the Inspector to step through actions, pick locators, edit locators live, and inspect actionability logs.
  • Slow actions so a person can follow them.
npx playwright test --headed
npx playwright test --debug

--debug opens the Inspector and launches a headed browser.

Runnable JavaScript examples

Headless

const { chromium } = require('playwright');
(async () => {
  const browser = await chromium.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  console.log(await page.title());
  await page.screenshot({ path: 'headless.png', fullPage: true });
  await browser.close();
})();

chromium.launch() with no options is also headless because the default is true.

Headed with a visible window

const { chromium } = require('playwright');
(async () => {
  const browser = await chromium.launch({ headless: false, slowMo: 100 });
  const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
  await page.goto('https://example.com');
  await page.screenshot({ path: 'headed.png' });
  await browser.close();
})();

slowMo: 100 is an example observation delay, not a measured benchmark.

Playwright Test configuration

// playwright.config.js
const { defineConfig } = require('@playwright/test');
module.exports = defineConfig({
  use: { headless: process.env.HEADED !== '1' }
});
# Default headless run
npx playwright test
# One visible run
npx playwright test --headed
# Inspector and headed browser
npx playwright test --debug

Headed runs in CI

A headed browser needs a desktop display. On Linux CI, use Xvfb, a virtual display server:

xvfb-run npx playwright test --headed

Use a CI image containing Xvfb and the browser’s display dependencies. If visual inspection is unnecessary, keep CI headless and retain traces or screenshots on failure.

Chromium headless implementation and channel

Without a channel, Playwright uses a separate Chromium headless shell for headless mode and the regular Chromium build for headed mode. The chromium channel opts into the newer headless mode, which Playwright describes as closer to regular Chrome and more feature-complete.

const browser = await chromium.launch({ headless: true, channel: 'chromium' });

Pin browser versions, channels, viewports, and CI images when rendering consistency matters. Official Playwright documentation does not publish a universal speed or memory benchmark for headless versus headed, so measure your own workload.

Debugging without changing CI

  1. Reproduce locally with npx playwright test --debug.
  2. Use Inspector’s locator picker and actionability log.
  3. Collect traces, screenshots, videos, console output, and network logs from the normal headless job.
  4. Add Xvfb and --headed to CI only when a visible window answers a question artifacts cannot.

Reliability, performance, and cost

  • Reliability: Headless avoids display-server failures; headed adds a desktop or Xvfb dependency.
  • Performance: There is no official universal benchmark. Compare complete runs using your pages, browser version, workers, and CI limits.
  • Artifacts: Traces, screenshots, videos, logs, and UI Mode provide evidence for unattended runs.
  • Cost: CI or compute duration determines spend; Playwright publishes no fixed cost difference for the two modes.
  • Consistency: Pin versions and use the same channel and launch options when comparing results.

Common errors and fixes

Symptom Cause Fix
cannot open display Headed CI has no display. Use xvfb-run npx playwright test --headed or run headless.
No window appears The run is headless. Use --headed or headless: false.
Inspector does not open Debug mode was not enabled or the process is remote. Run npx playwright test --debug locally; inspect artifacts remotely.
Actions are too fast to follow Normal automation speed. Add slowMo or step in Inspector.
Different rendering between modes Different Chromium build, channel, viewport, or environment. Pin versions, set viewport, and compare with channel: 'chromium' when appropriate.
Headless failure lacks context No artifacts were retained. Enable traces, screenshots, videos, and logs, then reproduce with --debug.

Or skip the browser setup

If you need a clean website image rather than browser test debugging, ScreenshotNeo provides one screenshot request. It accepts cookie banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the result with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

See the ScreenshotNeo API documentation for options.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://example.com \
  -o shot.webp
import requests
r = requests.get('https://api.screenshotneo.com/v1/shot', params={'access_key': 'YOUR_API_KEY', 'url': 'https://example.com'}, timeout=90)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

There are 1,000 screenshots each month on the free plan with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Is headed more accurate?

Not universally. Build, channel, viewport, and environment affect rendering. The chromium channel provides a headless mode closer to regular Chrome.

Can I use headed mode on a laptop?

Yes. Use --headed or headless: false, with slowMo when needed.

Should every CI failure be rerun headed?

No. Inspect traces and other artifacts first, then reproduce headed when visual inspection helps.

Does headless remove the need for screenshots?

No. Screenshots and traces are the normal evidence for unattended runs.