Debug Flaky UI Tests with Playwright Trace Viewer
Learn how Playwright's Trace Viewer captures full test sessions — DOM snapshots, network logs, and console output — so you can replay flaky UI failures, pinpoint root causes, and add tracing safely to CI.
30 May 2026, 13:58 UTC

The problem: flaky UI tests that leave no clues
When a Playwright test fails intermittently, the usual console output often shows only a generic timeout or selector error. Without a record of what the browser actually did, you end up re‑running the test locally, adding console.log statements, or guessing which network request stalled. Playwright’s Trace Viewer solves this by capturing a full, replayable session — DOM snapshots, network traffic, console logs, and source‑code pointers — for every test step.
How Trace Viewer works
Trace Viewer is a Chromium‑based UI that opens a .zip trace file. Inside the archive you’ll find:
- DOM snapshots after each action (click, navigation, fill, etc.)
- Network requests with headers, payloads, and timings
- Console output including errors and custom logs
- Source‑code mapping that links each step back to the test file line
You can pause at any step, inspect the element’s computed selector, modify the page state, and even replay the test from that point — a true time‑travel debugging experience.
Enabling tracing in your project
Tracing is controlled in playwright.config.ts. The three most common modes are:
| Mode | When a trace is written |
|---|---|
trace: 'on' | Every test run |
trace: 'retain-on-failure' | Only when a test fails (default for CI) |
trace: 'off' | Never |
Example configuration (Playwright v1.44+):
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'retain-on-failure', // adjust per environment
},
});
You can also override per‑test via test.use({ trace: 'on' }) when you need a trace for a specific flaky case.
Worked example: capturing a flaky button click
- Create a minimal test (save as
tests/flaky-click.spec.ts):import { test, expect } from '@playwright/test'; test('click the submit button', async ({ page }) => { await page.goto('https://example.com'); await page.click('button[type="submit"]'); // may be flaky await expect(page).toHaveURL(/success/); }); - Run the test with tracing enabled from the repository root (requires Node ≥ 18 and Playwright installed):
npx playwright test tests/flaky-click.spec.ts --trace onExpected result: a
test-results/flaky-click-/trace.zipfile appears. - Open the trace:
npx playwright show-trace test-results/flaky-click-/trace.zipThe viewer launches in your default browser. You should see a timeline with three entries —
goto,click,expect— each expandable to reveal the DOM snapshot, network waterfall, and console logs for that step. - Diagnose: if the click step shows a missing selector in the snapshot, you have a concrete clue (e.g., the button is rendered after an async fetch). You can now add a wait for the network request or a more robust selector without guessing.
Trade‑offs: storage, speed, and sensitivity
- Overhead: each trace can be 2–10 MB. A suite of 500 tests may add gigabytes to CI artifacts and increase run time by 10‑30 %.
- Sensitive data: traces contain cookies, localStorage, and request bodies. In regulated environments, either sanitize traces (remove
networkentries) or restrict tracing to non‑production runs. - Mitigation: use
retain-on-failurein CI, enabletrace: 'on'only for targeted debugging sessions, and configure artifact retention policies (e.g., keep traces for 7 days).
Actionable closing: make tracing a default safety net
Add trace: 'retain-on-failure' to your shared playwright.config.ts today. When a test flakes, the trace is already there — no extra run required. Pair this with a CI step that uploads the trace zip as a build artifact, so teammates can open it with npx playwright show-trace without pulling the repository. Periodically review trace size reports (CI logs show artifact bytes) and adjust retention or sampling if storage becomes a concern.
Verification checklist:
- Run a test with
--trace onand confirm atrace.zipappears. - Open it with
show-traceand verify the timeline matches your test steps. - Switch config to
trace: 'off', re‑run, and ensure no trace is produced and the run is faster.
With Trace Viewer in the loop, flaky UI tests stop being mysteries and become reproducible debugging sessions.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.