DEV Community

Cover image for Playwright Trace Viewer: Debug Failed Tests Without Reproducing Them
Vanessa Sastre
Vanessa Sastre

Posted on

Playwright Trace Viewer: Debug Failed Tests Without Reproducing Them

Playwright Trace Viewer is a built-in GUI that records a full, replayable snapshot of a test run — every action, DOM state, network call, and console log — so you can debug a CI failure by opening a file, not by reproducing it.

In practice, that makes a UI test into more than a UI recording. Every browser interaction is synchronized with the underlying API traffic, console output, and page state at the moment it happened — which gives you an API debugging layer for free, without writing a single API test.

That one difference changes the economics of test debugging. This post covers what changes in your day-to-day workflow, how to turn it on, and how to justify it to the people who care about engineering time and CI spend rather than DOM snapshots.


The Problem: Debugging Requires Reproducing

CI fails → Try locally → Can't reproduce → Add debugging → Implement a fix → Push → Wait for CI → Repeat

A test fails on CI. Here's what that traditionally costs you:

  1. Read the error message and stack trace, which often aren't clear enough on their own.
  2. Pull the branch and try to reproduce the failure locally.
  3. It passes locally. CI-only failures are common — different browser, viewport, timing, environment, or data state.
  4. Add console.log, screenshots, tracing, or page.pause() calls and run the test again.
  5. It still doesn't reproduce. Try running headed, slow down actions, add waits, or tweak the environment until it finally fails.
  6. Eventually reproduce the issue, identify the root cause, remove the debugging code, and implement a fix.
  7. Push the fix and wait for CI to run again. If the failure persists, repeat the process.

Depending on the bug, that loop can take anywhere from a few minutes to most of an afternoon — and it scales linearly with how flaky or environment-dependent the failure is. Every step exists because you're missing information that already existed at the moment the test ran, and is now gone.

Trace Viewer's premise: stop throwing that information away.


The Fix: Open the Trace Instead of Re-Running the Test

With tracing enabled, every action, DOM snapshot, request, and log from the run is captured into a single trace.zip. When a test fails, you open that file — locally, from CI, or in the browser — and the run replays exactly as it happened.

Here's the same debugging tasks, before and after:

Task Without Trace Viewer With Trace Viewer
Find why a click hit the wrong element Re-run headed, add logs, hope it reproduces Click the action, see the before/after DOM and the exact click coordinates
Grab a locator for a new assertion Re-run in debug mode, use the inspector live Open the Locator tab on the already-captured screen and pick it — no re-run
Diagnose a failed network call Add request logging, re-run, inspect devtools Open Network, already filtered to that action
Find the exact line of code behind a step Search the file, count steps manually Click the action, Source jumps to that line
Investigate a CI-only flake SSH into CI, add debug output, wait for the next occurrence Download the trace CI already attached, open it locally

The pattern across every row: instead of recreating the conditions of the failure, you're looking at a recording of it.


Setup: Two Lines of Config

Locally, trace everything while you're developing:

npx playwright test --trace on
Enter fullscreen mode Exit fullscreen mode

Or use UI Mode, which traces every test automatically without the flag.

On CI, tracing every run is wasteful — trace only what fails, on retry:

// playwright.config.ts
import { defineConfig } from '@playwright/test';

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

Other values: on-all-retries, retain-on-failure (if you don't use retries), on (every run — expensive), off.

Opening a trace:

  • From the HTML report: click View trace on any test — it opens a local instance of Trace Viewer directly, no file hunting.
  npx playwright show-report
Enter fullscreen mode Exit fullscreen mode
  • From the CLI, pointing at a file or a URL:
  npx playwright show-trace path/to/trace.zip
  npx playwright show-trace https://example.com/trace.zip
Enter fullscreen mode Exit fullscreen mode
  • In the browser, no install required: trace.playwright.dev. Drag in a file, or pass one as a URL query parameter — handy for linking straight from a CI artifact. Everything renders locally in your browser; nothing is uploaded.

What's Inside a Trace

A timeline runs across the top of the viewer — click or drag anywhere on it, and every panel below updates to that moment. You never have to click through actions one by one to find the point you care about.

Tab What you get
Actions Every action, its locator, and its duration, with before/after DOM snapshots
Locator The exact screen, fully replicated, with Pick Locator available on it — build a new locator without executing anything
Source The exact line of test code behind the action you're viewing
Call Timing, resolved locator, and mode (e.g. strict) for the selected action
Log Playwright's internal narration — waiting for visible/enabled/stable, then acting
Errors The failure message, with a red marker on the timeline showing exactly when it happened
Console Browser and test console logs, filterable to a single action
Network Every request with headers/bodies, filterable to a single action
Metadata Browser, viewport, duration, and run context in one place
Attachments Expected vs. actual image diffs with a slider, for visual regression tests

The Network tab is easy to underestimate. This is the API debugging layer mentioned at the top of this post: even if your suite only exercises the UI, every backend call made during the test is captured and synchronized with the user's actions. Instead of opening DevTools and trying to reproduce the issue, you already have a complete timeline of both the frontend behavior and the API interactions that produced it.


Traces as Context for AI Agents

Everything a trace captures — actions, locators, DOM snapshots, network calls, console output — is structured data sitting in a zip file, not just a GUI to click through manually. That makes it a good fit for AI coding agents and testing skills that need to diagnose a failure without a human first reproducing it.

A few ways this shows up in practice:

  • Autonomous failure triage. An agent can be handed a trace.zip from a CI run and asked to identify the failing action, the locator involved, and the DOM state around it, then propose a fix — without ever spinning up a browser or re-running the suite itself.
  • Root-cause summaries instead of raw logs. Rather than pasting a stack trace into a chat, an agent (or a skill built around one) can walk the Actions, Network, and Console data from a trace and produce a plain-language explanation of what broke and where, which is a much shorter path to a fix than reading raw output.
  • Locator generation without execution. Because the Locator tab replicates the exact screen at a given moment, an agent can use that captured state to derive or validate a selector for a new assertion, the same way a human uses Pick Locator — without needing a live browser session.
  • Feeding "video receipts" back in. If you're also recording screencasts (Playwright's page.screencast API) alongside traces, an agent's own verification steps can be captured the same way — giving you a reviewable artifact of what an agent did, not just a claim that it passed.
  • CI feedback loops. Since traces are already CI artifacts with stable URLs, an agent watching a pipeline can fetch a failing test's trace automatically as soon as it's produced, rather than waiting on a person to attach logs or describe the failure.

The underlying shift is the same one this post keeps coming back to: a trace turns "the test failed" into a self-contained record that doesn't require a human — or an agent — to reproduce the failure to understand it.


The Efficiency Case

Trace Viewer isn't just a developer-experience nicety — it changes measurable costs. If you need to justify adopting it (or prioritizing better trace coverage in CI), these are the levers to point at:

  • Mean time to resolution (MTTR) on test failures. The reproduction loop above is where most debugging time goes. Removing the "make it fail again" step is the single biggest lever on how long a failure sits open.
  • Engineer context-switching cost. A flaky CI failure that can be diagnosed by opening a file, versus one that requires blocking time to reproduce locally, has a very different interruption cost — especially for failures that surface hours after the engineer has moved to other work.
  • CI compute spend. trace: 'on-first-retry' only records what actually fails, so you get debugging data without paying to trace every green run. Compare that to teams that resort to re-running whole suites repeatedly to catch a flake in the act.
  • Flaky test triage throughput. Because traces are attachable CI artifacts, failures can be triaged asynchronously by whoever has time, not only by whoever can reproduce the environment.

If you want to track the impact concretely, two numbers are enough to start: time from failure to root cause identified, and number of "couldn't reproduce, closed as flaky" tickets. Both should move once trace review replaces manual reproduction as the default first step.


CI/CD Recommendations

  • Trace on retry, not on every run. on-first-retry (or retain-on-failure without retries) gives full debugging data for failures at a fraction of the storage and runtime cost of on.
  • Link traces directly from CI output. Since show-trace and trace.playwright.dev both accept URLs, wire your CI's artifact link straight into a one-click trace view instead of a manual download-and-unzip step.
  • Treat "couldn't reproduce" as a process gap, not bad luck. If a failure recurs without a trace attached, that's a signal to widen trace coverage, not just re-run the suite again.

Official Resources


Final Thoughts

Most test-debugging time isn't spent fixing bugs — it's spent recreating the conditions that exposed them. Trace Viewer removes that step by keeping a full record of the run itself, so the question shifts from "can I reproduce this?" to "what does the trace show?"

For engineering teams, the value isn't measured by prettier debugging tools — it's measured by fewer engineering hours lost to reproducing failures. Shorter debugging cycles, fewer unnecessary CI reruns, and faster root-cause analysis are improvements that show up in both developer productivity and infrastructure costs.

Top comments (0)