Flaky tests are the silent productivity killer of every QA team. You see a red CI pipeline, open the logs, stare at a cryptic timeout error, and spend the next hour sprinkling console.log statements across your test files. Sound familiar?
Playwright's Trace Viewer eliminates that entire cycle. It records a complete timeline of your test execution — every click, every network request, every DOM mutation — and lets you replay it in the browser like a flight recorder for your tests. No extra tools, no setup headaches. If you are still debugging with console.log in 2026, this guide will change your workflow permanently.
What Is Playwright Trace Viewer?
Playwright Trace Viewer is a time-travel debugger built directly into Playwright. When enabled, it records every action your test performs — navigations, clicks, form fills, assertions — along with the complete execution context at each step: DOM snapshots, network requests, console logs, and even the test source code.
After a test run, you open the trace file in your browser and get a visual timeline of the entire execution. You can click on any action and see:
- The DOM before and after the action — exactly what the page looked like when that click or fill happened
- Every network request that fired, with full headers, request body, and response
- Console output at that exact moment in the timeline
- Actionability checks — was the element visible? Was it enabled? Was it attached to the DOM?
- The test source code with the current line highlighted
Think of it as Chrome DevTools, but for your entire test execution — frozen in time and fully navigable. You do not need to install anything extra. Trace Viewer opens in your default browser and works with any Playwright test written in TypeScript, JavaScript, Python, Java, or C#.
Key insight: Trace Viewer is not just for failed tests. Recording traces for passing tests helps you understand why a test works, catch slow steps before they become timeouts, and document test behavior for new team members.
Why Trace Viewer Beats console.log Debugging
Most developers debug Playwright tests the same way they debug application code: console.log everywhere. This works for simple cases, but it falls apart when you are dealing with flaky tests, race conditions, or failures that only happen in CI. Here is how the common debugging approaches compare:
| Method | What You See | Limitations |
|---|---|---|
| console.log | Variable values at specific points | Blind to DOM state, noisy output, requires manual placement, no visual context |
| Screenshots | Single frame of the page | No context before/after, cannot inspect elements, one moment in time only |
| Video recording | Pixel-level screen capture | Slow to scrub, no DOM inspection, no network data, large file sizes |
| Trace Viewer | Full timeline with DOM snapshots, network, console, source code | Requires trace recording enabled (minimal overhead) |
The difference is stark. With console.log, you are guessing what happened. With Trace Viewer, you are seeing what happened — the full context at every step. For flaky tests that fail intermittently, this is the difference between a 5-minute fix and a 60-minute investigation.
How to Enable Traces in Your Tests
There are three ways to enable trace recording in Playwright. Each serves a different use case. The right choice depends on whether you want traces always, only on failures, or only on retries.
Method 1: On First Retry (Recommended Default)
This is the recommended default for most teams. Traces are only recorded when a test fails and Playwright retries it. Zero overhead for passing tests.
import { defineConfig } from '@playwright/test'; export default defineConfig({ retries: 2, use: { // Only record trace on first retry — zero overhead for passing tests trace: 'on-first-retry', }, });
Method 2: Always On (For CI)
Record traces for every test, every run. Use this in CI when you want full debugging context for every failure, including first-run failures that never retry.
import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { // Record trace for every test — useful in CI for full context trace: 'on', }, });
Method 3: Retain on Failure (Keep Only What Matters)
Record traces for all tests, but only save the trace file when a test fails. This gives you first-failure traces without the retry requirement, while keeping your disk usage manageable.
import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { // Record all traces, save only for failures trace: 'retain-on-failure', }, });
Which should you choose? Start with on-first-retry for local development. Switch to retain-on-failure or on in your CI config where you want traces for every failure without relying on retries.
Recording Your First Trace
Let's record and view a trace step by step. Even if you have never used Trace Viewer before, you will be up and running in under two minutes.
Step 1: Run your tests with tracing enabled
You can enable tracing from the command line without modifying your config file:
# Run all tests with trace recording npx playwright test --trace on # Run a specific test file with tracing npx playwright test tests/login.spec.ts --trace on
Step 2: Open the trace file
After the test run completes, Playwright saves trace files in the test-results/ directory. Open the trace with:
# Open a specific trace file npx playwright show-trace test-results/login-test/trace.zip # Or open the last test run's trace from the HTML report npx playwright show-report
The Trace Viewer opens in your default browser. No installation required — it is a web application bundled with Playwright.
Step 3: Explore the trace
You will see a timeline of every action your test performed. Click on any action to see the DOM snapshot, network activity, and console output at that exact moment. You can also drag the timeline scrubber to navigate through the execution frame by frame.
Quick shortcut: You can also drag and drop any .zip trace file onto trace.playwright.dev to view it instantly in the browser — no local Playwright installation needed.
Anatomy of a Trace: What You See
The Trace Viewer UI is organized into panels, each showing a different dimension of your test execution. Understanding these panels is the key to fast debugging.
Timeline Bar
The top of the Trace Viewer shows a visual timeline of all actions. Each action appears as a colored segment — green for passed steps, red for failures. You can see at a glance where the test spent the most time and where it broke.
Actions Panel
The left sidebar lists every step your test performed: page.goto(), locator.click(), locator.fill(), expect() assertions. Each action shows its duration in milliseconds. Click any action to jump to that point in the timeline.
DOM Snapshot
This is the most powerful panel. For every action, Trace Viewer captures the before and after state of the DOM. You can inspect elements, check visibility, verify text content, and even see CSS computed styles — exactly as the page appeared when the action executed. This is what makes Trace Viewer a true time-travel debugger.
Network Tab
Every HTTP request and response is captured with full details: URL, method, status code, headers, request body, and response body. You can filter by request type (XHR, Fetch, Document, etc.) and see the exact timing of each request relative to your test actions.
Console Tab
All console.log, console.warn, and console.error output from the page is captured and timestamped. You can see exactly which console messages appeared at each point in the test timeline — no more guessing which log corresponds to which action.
Source Tab
The Source tab shows your test source code with the current line highlighted. As you click through actions in the timeline, the source highlight moves to the corresponding line. This makes it trivial to correlate test code with execution behavior.
Metadata
The metadata section shows the browser engine (Chromium, Firefox, WebKit), viewport dimensions, test file path, and test name. This is particularly useful when debugging cross-browser failures — you can immediately see which browser was used for a failing trace.
Debugging Flaky Tests with Trace Viewer
Flaky tests — tests that pass locally but fail intermittently in CI — are the number one debugging challenge for QA teams. Trace Viewer transforms flaky test debugging from a guessing game into a forensic investigation.
Real-world example: The intermittent login failure
Consider this common scenario: your login test passes 100% of the time on your machine but fails ~20% of the time in CI with a timeout error on the dashboard assertion.
test('user can log in and see dashboard', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('user@example.com'); await page.getByLabel('Password').fill('password123'); await page.getByRole('button', { name: 'Sign In' }).click(); // This line times out ~20% of the time in CI await expect(page.getByText('Welcome back')).toBeVisible(); });
With console.log, you would add logging before and after each step, push to CI, wait for the next failure, read the logs, and repeat. This cycle takes hours.
With Trace Viewer, you open the failing trace and immediately see:
- Actions panel: The
click('Sign In')action completed successfully, but theexpect(toBeVisible)action timed out after 30 seconds - DOM snapshot (after click): The page shows a loading spinner instead of the dashboard — the API response has not arrived yet
- Network tab: The
POST /api/auth/loginrequest took 28 seconds to respond (vs 200ms locally). The CI server has higher latency to the API - Console tab: A warning message reads
"Slow network detected, retrying..."
The root cause is clear in 5 minutes: the CI environment has higher network latency, causing the API call to take longer than the default timeout. The fix is to increase the assertion timeout or add a waitForResponse before the assertion.
test('user can log in and see dashboard', async ({ page }) => { await page.goto('/login'); await page.getByLabel('Email').fill('user@example.com'); await page.getByLabel('Password').fill('password123'); // Wait for the API response before asserting await Promise.all([ page.waitForResponse(resp => resp.url().includes('/api/auth/login') && resp.status() === 200 ), page.getByRole('button', { name: 'Sign In' }).click(), ]); await expect(page.getByText('Welcome back')).toBeVisible(); });
Debugging stat: Teams using Trace Viewer report reducing flaky test debugging time from 30–60 minutes to 5–10 minutes per test. The DOM snapshots alone eliminate the most common blind spot: not knowing what the page actually looked like when the assertion ran.
Debugging Network Issues
The Network tab in Trace Viewer is essential for debugging API-dependent tests. Whether you are mocking API responses, intercepting network calls, or diagnosing CORS errors, the network panel gives you complete visibility.
Common network debugging scenarios
- API mocking failures — Your route handler is not intercepting the right URL. The Network tab shows both the mocked requests and the ones that slipped through to the real server.
- CORS issues — The request was blocked by CORS policy. You can see the preflight OPTIONS request and the missing headers in the response.
- Slow responses — A request that usually takes 100ms took 5 seconds. The timing column shows exactly which requests are slow, so you can add targeted
waitForResponsecalls. - Failed requests — A 500 error from the API caused the page to show an error state instead of the expected content. The response body in the Network tab shows the exact server error message.
Filtering and inspecting requests
In the Network tab, you can filter requests by type (XHR, Fetch, Document, Stylesheet, Image), search by URL, and click any request to see the full details: headers, query parameters, request body, response body, and response time. This is the same information you would get from Chrome DevTools — but captured at the exact moment your test action executed.
test('displays user list from API', async ({ page }) => { // Set up API mock await page.route('**/api/users', route => { route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify([ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, ]), }); }); await page.goto('/users'); // If this fails, check the Network tab in the trace: // - Did the route intercept the request? // - Was the URL pattern correct? // - Did the page make the request at all? await expect(page.getByText('Alice')).toBeVisible(); });
Advanced: Trace Viewer in CI/CD
Traces are most valuable in CI/CD where you cannot manually run tests with DevTools open. The key is to automatically save traces as build artifacts and make them easily accessible to the team.
GitHub Actions: Attach traces as artifacts
This workflow runs your Playwright tests and uploads trace files as GitHub Actions artifacts whenever tests fail. Any team member can download the traces directly from the PR.
name: Playwright Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Install Playwright browsers run: npx playwright install --with-deps - name: Run Playwright tests run: npx playwright test env: CI: true - name: Upload trace artifacts # Upload traces only when tests fail if: failure() uses: actions/upload-artifact@v4 with: name: playwright-traces path: test-results/ retention-days: 30
When a test fails in CI, the traces appear as downloadable artifacts in the GitHub Actions run. Click the artifact, download the zip, and open it with npx playwright show-trace — or drag it onto trace.playwright.dev.
Sharing traces with teammates
Trace files are self-contained .zip archives. You can share them via:
- Slack/Teams — drop the zip file in a channel; teammates open it with
npx playwright show-trace - trace.playwright.dev — drag-and-drop for instant browser-based viewing
- Cloud storage — upload to S3/GCS and share a link; traces are small (typically 1–5MB)
- PR comments — use a GitHub Action to automatically post trace links as PR comments on failure
Trace Viewer + Claude AI: AI-Powered Debugging
The future of test debugging is combining Trace Viewer's execution context with Claude AI's reasoning. Instead of manually interpreting traces, you can feed trace data to Claude and get instant analysis.
How it works
Export the trace's key data — the action list, network requests, console errors, and DOM snapshots — and provide it to Claude. Claude can read trace data via the Playwright MCP Server and suggest targeted fixes based on the full execution context.
Practical workflow:
- Run failing tests with tracing enabled —
npx playwright test --trace on - Extract key data from the trace — action timeline, network failures, DOM diffs, console errors
- Provide context to Claude — paste the trace summary and ask Claude to diagnose the failure
- Get an AI-generated fix — Claude analyzes the race condition, missing wait, or wrong selector and produces a corrected test
This is not theoretical. Teams using Claude AI with Playwright trace data report fixing flaky tests 3–5x faster than manual analysis alone. The AI excels at spotting patterns across multiple trace files — identifying common failure modes that a human might miss when reviewing traces one at a time.
Learn this workflow: The complete course covers how to integrate Claude AI with Playwright debugging, including trace analysis, MCP Server connectivity, and AI-powered test healing.
Frequently Asked Questions
How do I open Playwright Trace Viewer?
Run npx playwright show-trace trace.zip in your terminal to open the Trace Viewer in your default browser. You can also open trace files directly at trace.playwright.dev by dragging and dropping the .zip file. No additional tools or installations are needed — Trace Viewer runs entirely in the browser.
Does Trace Viewer slow down my tests?
Trace recording adds approximately 5–10% overhead to test execution time. The recommended configuration is trace: 'on-first-retry', which only records traces when a test fails and retries — meaning zero overhead for passing tests. For CI pipelines, use retain-on-failure to keep traces only for failing tests without impacting overall suite speed.
Can I share traces with my team?
Yes. Trace files are portable .zip archives that anyone can open. Share them via Slack, email, or cloud storage. You can also upload traces to trace.playwright.dev for instant browser-based viewing — just share the URL. In CI/CD, attach traces as GitHub Actions artifacts so any team member can download and inspect them directly from the PR.
What's the difference between trace and video recording?
Video recording captures pixel-level screen recordings but offers no interactivity — you cannot inspect the DOM, view network requests, or check console logs. Trace Viewer captures the full execution context: DOM snapshots before and after every action, all network requests with headers and bodies, console output, and test source code mapping. Traces are significantly more useful for debugging than videos.
How do I enable traces only for failed tests?
Set trace: 'retain-on-failure' in your playwright.config.ts under the use section. This records traces for all tests but only saves the trace file when a test fails. Alternatively, use trace: 'on-first-retry' which only starts recording on the first retry attempt, meaning no trace overhead for tests that pass on the first run.
Asim Noaman
Senior QA Automation Engineer & AI Testing Specialist
With years of hands-on experience building test automation frameworks for production applications, Asim specializes in combining traditional QA methodologies with cutting-edge AI tools. He has helped teams adopt Playwright and AI-driven testing workflows to ship faster with fewer bugs.
Complete Course
Master Playwright Debugging — Trace Viewer & Beyond
Learn Trace Viewer, advanced debugging patterns, and AI-powered test analysis in the complete Udemy course. Go from zero to production-grade Playwright automation with real projects and hands-on labs.
- Trace Viewer deep-dive
- Flaky test debugging patterns
- CI/CD trace integration
- Claude AI-powered debugging