How to Use Playwright Trace Viewer to Debug Tests
Record a Playwright trace, open trace.zip, and use Actions, DOM snapshots, console output, and Network data to find why a test failed.
Playwright Trace Viewer helps you reconstruct what happened during a test: which action failed, what the page looked like before and after it, and what the browser logged or requested. For a local run, record a trace with npx playwright test --trace on, then open it with npx playwright show-trace path/to/trace.zip. In CI, the recommended starting point is trace: 'on-first-retry' with retries enabled.
1. Record a trace
A trace is an archive of a test run that you can inspect after the run finishes. For local investigation, use the Playwright Test CLI:
npx playwright test --trace on
Playwright saves trace data for the run. You can open the HTML report and select the test trace, or open an archive directly:
npx playwright show-report
npx playwright show-trace path/to/trace.zip
Use the direct command when you already know the archive path. The HTML report is useful when you want to browse test results and choose a particular test’s trace.
Capture traces on CI retries
Recording every test is performance heavy. For intermittent CI failures, enable retries and capture a trace on the first retry:
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: 1,
use: {
trace: 'on-first-retry',
},
});
Run your normal test command in CI, then open the generated HTML report or the attached trace.zip. A retry trace preserves evidence from the attempt that is being retried, which is often the useful run for diagnosing a flaky failure.
Choose a trace mode
| Mode | Use |
|---|---|
on |
Record every test. Convenient for a focused local debugging run, but Playwright says it is performance heavy and does not recommend it for routine runs. |
on-first-retry |
Record the first retry after a test failure. A practical CI default when retries are enabled. |
on-all-retries |
Record retry attempts. Check the documentation matching your installed Playwright version for exact behavior. |
retain-on-failure |
Retain a trace for failed tests when you are not using retries. |
off |
Do not record traces. |
The CLI reference also lists retain-on-first-failure and retain-on-failure-and-retries. Trace modes can vary with Playwright version, so consult the version-matched documentation before relying on a less common mode.
2. Open the trace
Use the CLI to open a local archive:
npx playwright show-trace test-results/example-test/trace.zip
You can also open the HTML report with npx playwright show-report and select the failed test’s trace. The hosted Trace Viewer at trace.playwright.dev loads a trace entirely in your browser rather than transmitting it to the service. To open a remotely hosted trace, its URL must be accessible to the browser; cross-origin resource sharing (CORS) rules may prevent loading it.
3. Find the failing action
- Open the Actions tab and locate the failed or suspicious step in the action list and timeline. Use the red error marker or the Errors tab to find the failure quickly.
- Select the action and note its source location, locator, call details, and duration. Follow the highlighted source location back to the test line.
- Compare the Before, Action, and After DOM snapshots. Ask what was present before the interaction, where the action applied, and what changed afterward.
- Read the action log and call details. They can show Playwright scrolling and waiting for visibility, enabled state, or stability before performing the action. Check locator strictness and other call details when the action targeted an unexpected element.
- Use the screenshot film strip and timeline to check the visible page around the action. When you select a time range, related actions, console entries, and network requests can be filtered to that period.
- Inspect console messages and Network requests around the same time. Look for failed responses, unexpected redirects, missing data, or browser errors that could explain the page state.
- Form a specific hypothesis, then verify it in the test or application before changing a locator or behavior.
What each panel helps answer
| Trace evidence | Question to ask |
|---|---|
| Actions, source, and call details | Which test line ran, which locator was used, and what did Playwright do before the action? |
| DOM snapshots | Was the expected element in the DOM before the action, and what did the action target? |
| Screenshot film strip and timeline | What did the page look like at the time of the action or failure? |
| Errors | What error did the test report, and where does the timeline mark it? |
| Console | Did the page or test log a relevant error or message? |
| Network | Did a request fail, return an unexpected response, or take a suspicious amount of time? |
| Metadata and attachments | Which browser, viewport, and run context apply? Are visual-regression expected, actual, or diff images attached? |
In Network, narrow requests by status, method, type, content type, duration, or size. Selecting a request can reveal request and response headers and bodies. Correlate this evidence with the selected action rather than treating a failed request elsewhere in the run as the cause automatically.
4. Debug locally with UI Mode
For interactive local investigation, run:
npx playwright test --ui
UI Mode lets you step through a test and inspect what happened before, during, and after each step. It is a useful alternative when you want to reproduce and explore a failure while editing the test. A saved trace is better when you need to inspect a completed run, share its artifact with a teammate, or investigate a CI-only failure.
5. Use the right tracing API
For Playwright Test, prefer the test-runner trace configuration when assertion context matters. Playwright’s lower-level browserContext.tracing API records browser operations and network activity, but does not record test assertions such as expect calls. Playwright Test’s trace integration provides more complete context for test failures.
If you are using the lower-level API outside the test runner, start tracing before the browser actions and stop tracing to export the archive. A minimal pattern is:
const context = await browser.newContext();
await context.tracing.start({ screenshots: true, snapshots: true });
const page = await context.newPage();
await page.goto('https://example.com');
await context.tracing.stop({ path: 'trace.zip' });
This creates browser-operation trace data; it does not add Playwright Test assertion records. Use the tracing API documentation for the exact options supported by your installed version.
6. Troubleshoot common problems
| Symptom | Likely cause | Fix |
|---|---|---|
| No trace archive appears | Tracing was off, the test did not run under the expected configuration, or you are looking in the wrong output directory. | Run a focused local test with --trace on, check the test results directory and reporter output, and verify the project’s effective use.trace setting. |
| The HTML report has no trace link | The selected run did not record or retain a trace. | Enable a trace mode that applies to the run, rerun the test, and inspect the resulting report. |
show-trace cannot open the file |
The path is wrong, the archive was not downloaded, or the file is incomplete. | Confirm the path and artifact download, then open the actual trace.zip file. |
| A hosted trace will not load | The remote URL is inaccessible or the host blocks cross-origin requests through CORS. | Make the trace URL accessible to the browser and configure the host to allow the viewer’s request, or download the archive and open it locally. |
| The trace has browser activity but no assertion context | It was captured with the lower-level context tracing API. | Use Playwright Test’s trace configuration for test failures involving assertions. |
| The failure is absent from a retry trace | The retry passed, or the relevant failure happened on a different attempt than the one retained. | Review retry results and configure the trace mode to retain the attempt you need; use a focused local run with --trace on to capture every attempt during investigation. |
| The run becomes slower with tracing enabled | Tracing adds recording work, especially when enabled for every test. | Limit on to focused debugging. For CI, use retry-based or failure-retention modes appropriate to your workflow. |
7. Performance, reliability, and cost
Playwright documents tracing with on as performance heavy, so do not make it the routine default for every test. Retry-based recording captures diagnostic evidence for failures while avoiding trace capture on every passing test. If retries are disabled, consider retain-on-failure.
Trace Viewer is an investigation aid, not proof that a failure has one particular cause. A trace records one run and its environment. Compare the action timeline, snapshots, browser messages, requests, and test source; then reproduce or validate the proposed fix. Preserve the trace artifact from CI if the failure is intermittent, since a later rerun may not reproduce it.
Playwright’s cited guidance gives no numeric overhead or trace-size benchmark. The practical costs are added recording work and artifacts to retain or transfer. Choose a mode that captures enough failed-run evidence for your team without recording every test unnecessarily.
8. Or skip the browser setup
If you need a clean screenshot of a page while documenting or investigating a failure, ScreenshotNeo is a website screenshot API and MCP server. It does not replace Trace Viewer’s action history, DOM snapshots, or test assertions; it provides a direct way to capture the page as an image or PDF.
Make one GET request with your API key and target URL. See the ScreenshotNeo API documentation for the available parameters.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
Python
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)
Node.js
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(async fs => {
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
});
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 screenshots. Sign up for 1,000 free screenshots a month, no card required.
9. Frequently asked questions
Does Trace Viewer upload a local trace?
The official guide says the hosted viewer loads a trace entirely in the browser and does not transmit it externally. For a remote trace, the URL still needs to be accessible to your browser, and CORS may apply.
Can I inspect a trace without opening the browser UI?
The trace is intended for interactive inspection in Trace Viewer. You can launch it from the CLI with npx playwright show-trace or find it through the HTML report.
Should I trace every test in CI?
Usually no. Playwright warns that recording every test with on is performance heavy. Use on-first-retry with retries, or a failure-retention mode when retries are off.
Can Trace Viewer show why an assertion failed?
Playwright Test tracing includes test-runner context. The lower-level browser context tracing API does not record assertions such as expect.


