ScreenshotNeo

BlogHow-to

How to Reveal Test Output in Playwright

Learn how to see Playwright output in the terminal, HTML reports, Trace Viewer, and browser DevTools, with CI-ready commands and fixes.

By the ScreenshotNeo team1 October 20267 min read

Use the output surface that matches the problem you are investigating: the terminal reporter for immediate pass/fail results, the HTML report for a run-level view, Trace Viewer for correlated actions, logs, errors, and network requests, and PWDEBUG=console with page.pause() for live browser inspection.

Playwright’s official documentation covers these workflows in its command-line guide, Trace Viewer guide, and debugging guide.

Choose the right Playwright output surface

Need Use When it helps
Immediate result while a command runs Terminal reporter See test names, pass/fail state, retries, and errors without opening another tool.
Summary of a complete run HTML report Browse projects, files, tests, errors, steps, attachments, and trace links.
Why an action failed Trace Viewer Correlate snapshots, source, call logs, console messages, network requests, and metadata.
Inspect a live browser PWDEBUG=console and page.pause() Use browser DevTools to inspect the DOM, console, and network activity during a paused test.

1. Reveal output in the terminal

Run your suite normally. Playwright Test prints the selected reporter’s output to the terminal.

npx playwright test

Run one file, one test, or a project while investigating a smaller problem:

npx playwright test tests/login.spec.ts
npx playwright test -g "rejects an invalid password"
npx playwright test --project=chromium

Select a reporter for one run

The CLI accepts built-in reporters including list, line, dot, html, json, junit, github, blob, and null.

npx playwright test --reporter=list
npx playwright test --reporter=line
npx playwright test --reporter=dot
npx playwright test --reporter=html
npx playwright test --reporter=json
npx playwright test --reporter=junit

Use list when you want each test and its steps displayed, dot for compact local feedback, and machine-readable reporters when another process will consume the result.

Node.js test-file logs are written to the process running Playwright. Browser-page logs are separate; capture them explicitly when needed:

import { test, expect } from '@playwright/test';

test('logs useful state', async ({ page }) => {
  page.on('console', message => {
    console.log(`[browser:${message.type()}] ${message.text()}`);
  });

  await page.goto('https://example.com');
  console.log('title:', await page.title());
  await expect(page).toHaveTitle(/Example/);
});

2. Reveal output in the HTML report

Generate an HTML report, then serve it locally:

npx playwright test --reporter=html
npx playwright show-report

If the report was written to a custom directory, pass that directory:

npx playwright show-report playwright-report

Open a test entry to inspect its error, steps, attachments, and (when available) trace. The report is useful for understanding the complete run rather than following one action in real time.

Configure HTML reporting

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [['html', { outputFolder: 'playwright-report', open: 'never' }]],
});

Set open: 'never' in CI so a failed run does not try to launch a browser. After the job uploads the report artifact, download it and run npx playwright show-report locally.

3. Reveal detailed output with Trace Viewer

Trace Viewer is the richest post-run surface. It shows action snapshots, source location, the Playwright call log, errors, console messages, network requests, and metadata. The Console tab includes browser and test-file logs; selecting an action filters related messages.

Capture a trace locally

npx playwright test --trace on

Open the resulting archive:

npx playwright show-trace path/to/trace.zip

If the trace is attached to an HTML report, open the test in the report and select its trace link instead.

Capture traces on the first CI retry

Tracing every passing test can create unnecessary artifacts. A common CI configuration records a trace only when a retry is needed:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  retries: 1,
  use: {
    trace: 'on-first-retry',
  },
});

This preserves a failure artifact while keeping normal runs lighter. The resulting trace can be opened with:

npx playwright show-trace path/to/trace.zip

Read a trace efficiently

  1. Start with the failed action in the Actions list.
  2. Inspect the snapshot immediately before the action to verify the page state.
  3. Open the Call log for locator resolution, waits, and timeout details.
  4. Use the Console tab to check browser errors and test logs.
  5. Use the Network tab to find failed requests, redirects, or unexpectedly slow responses.
  6. Check metadata for browser, operating system, project, and timing information.

4. Reveal output with browser DevTools

Set PWDEBUG=console when launching a test. Playwright’s debugging workflow makes a playwright object available in browser developer tools so you can inspect console logs, network activity, and the DOM while the test is paused.

# macOS and Linux
PWDEBUG=console npx playwright test tests/login.spec.ts

# Windows PowerShell
$env:PWDEBUG="console"; npx playwright test tests/login.spec.ts

Pause at the point that needs inspection:

import { test } from '@playwright/test';

test('inspect the page', async ({ page }) => {
  await page.goto('https://example.com');
  await page.pause();
});

Continue or step through the test after checking the live page. Interactive debugging is primarily a local workflow; use reports and traces for CI.

5. See browser console output reliably

A console.log executed inside the page is browser output. It may not appear where you expect unless you subscribe to the page’s console event.

import { test } from '@playwright/test';

test('captures browser console output', async ({ page }) => {
  page.on('console', msg => {
    console.log(`${msg.type()}: ${msg.text()}`);
  });
  page.on('pageerror', error => {
    console.error('page error:', error.message);
  });

  await page.goto('https://example.com');
  await page.evaluate(() => console.log('message from the page'));
});

For a historical record, enable tracing as well. The trace stores console messages alongside the action that produced them.

6. Python and Node.js examples

Python Playwright

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.on("console", lambda msg: print(f"browser:{msg.type}: {msg.text}"))
    page.goto("https://example.com")
    print("title:", page.title())
    page.pause()
    browser.close()

Run it after installing the package and browser binaries:

pip install playwright
playwright install
python debug_page.py

Node.js command-line debugging

PWDEBUG=console npx playwright test
npx playwright test --trace on
npx playwright show-report
npx playwright show-trace trace.zip

7. Troubleshooting common output problems

Symptom Cause Fix
No test output appears A quiet or null reporter is configured, or output is being redirected. Run with --reporter=list and inspect the active reporter configuration.
console.log from the page is missing Browser console events are not automatically copied to the test process. Register page.on('console', ...) before navigation.
show-report cannot find a report The report directory is different or the test has not run with the HTML reporter. Run npx playwright test --reporter=html, then pass the correct directory to show-report.
No trace exists Tracing was not enabled, or the test passed while using on-first-retry. Use --trace on for the run, or reproduce the failure so the configured retry creates an archive.
show-trace rejects the file The path is wrong or the archive was not fully copied. Confirm the artifact path and download the complete trace.zip.
PWDEBUG=console has no effect The environment variable syntax is wrong for your shell, or the test never pauses. Use the shell-specific command above and add await page.pause().
CI logs are too large Verbose reporters or traces are enabled for every test. Use a compact reporter, retain HTML artifacts, and set trace: 'on-first-retry'.
Output differs between local and CI Different browser, project, environment variables, or parallel workers. Compare trace metadata, run the same project locally, and preserve the CI report and trace artifacts.

8. Performance, reliability, and cost considerations

  • Terminal reporters: lowest overhead and best for fast feedback.
  • HTML reports: add report-generation work and disk usage, but make run-level investigation repeatable.
  • Traces: capture screenshots, snapshots, logs, and network data, so retain them for retries or selected debugging runs instead of every passing test when storage matters.
  • Interactive debugging: depends on a local headed browser and is less suitable for unattended CI.
  • Parallelism: correlate output with the test name, project, worker, and trace metadata when several tests run concurrently.
  • Reproducibility: record the exact command, project, browser, and retry settings with CI artifacts.

Or skip the browser setup

If your goal is a clean screenshot of a page rather than interactive Playwright diagnostics, ScreenshotNeo provides a single request to its screenshot API. Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. ScreenshotNeo also includes an MCP server so Claude, Cursor, and other MCP clients can call take_screenshot, get_page_info, and capture_pdf.

See the complete option list in the ScreenshotNeo documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

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

FAQ

Where are Playwright traces stored?

The archive location depends on your reporter and output configuration. Use the path printed by the test run or the trace attachment in the HTML report, then open it with npx playwright show-trace path/to/trace.zip.

Which reporter should I use in CI?

Choose a machine-readable reporter such as JSON or JUnit when another system consumes results, and retain an HTML report or trace artifact for human investigation.

Can I inspect network requests after a test finishes?

Yes. Capture a trace and open its Network tab; it correlates requests with the actions and timing that produced them.

Why does the HTML report open but contain no trace?

An HTML report and a trace are separate outputs. Enable tracing with --trace on or configure trace: 'on-first-retry' before rerunning the test.