skip to content

Trace Capture Modes

Switching tracing on and choosing when it records: every run, only failures, or only a retry. Interviewers ask because always-on is the expensive answer and on-first-retry is the usual one.

on this pageshow

explore

questions

5

In Playwright, what does the config option trace: 'on-first-retry' record?

level: juniorimportance: must knowfreq 78%

answer

  1. Cost only when something already failed
  2. One attempt out of two is captured
  3. Not the failing attempt, the next one
  4. Useless when retries are zero

basics

~10 s

Playwright records a trace only while a test runs its first retry. The original failing attempt is never traced, and if the project allows no retries, no trace is produced at all.

solid answer

~40 s

`trace: 'on-first-retry'` in the `use` block of `playwright.config.ts` tells the test runner to switch tracing on for exactly one attempt: the first retry of a test that already failed once. Attempt one runs untraced, so a suite that mostly passes pays nothing; when something fails, the retry produces a `trace.zip` in that attempt's output folder and attaches it to the report. Two things follow. It needs `retries` above zero — with no retries the traced attempt never happens. And the zip shows a re-run, not the original failure, so a flake that does not reproduce leaves you with a trace of a passing attempt. That trade — near-zero cost on green runs, evidence only for reproducible failures — is why it is the mode most suites start with.

code

typescript · 9 lines
typescript
import { defineConfig } from '@playwright/test';

export default defineConfig({
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: 'https://orders.example.com',
    trace: 'on-first-retry',
  },
});

go deeper

for a junior

Remember the shape: no trace on the first attempt, a trace on the first retry. If you set this mode and see no zip after a failure, check that retries are enabled.

for a middle

Be able to explain that the option is a use option resolved per project, per file and per command line, and that the captured attempt is a re-run rather than the original failure.

for a senior

Show you weigh capture cost against evidence value, and that you know this mode is blind to flakes that pass on retry — say what you would switch to when chasing one.

for a principal

Own the policy: which projects record what, how the mode interacts with the retry budget, and how you stop a debugging setting like always-on tracing from silently becoming the suite default.

A **trace** is a zip file Playwright writes for one test attempt: an action-by-action timeline, DOM snapshots taken around each action, console messages, network records and optionally your test sources. The `trace` option decides *which attempts get one*, and `'on-first-retry'` is the narrowest useful setting. ## What the mode does, step by step 1. The test runs its first attempt with tracing **off**. 2. If it passes, nothing is recorded and nothing is written — a green run costs no capture time and no disk. 3. If it fails and the project allows retries, the runner re-runs the test and turns tracing **on** for that second attempt. 4. When the attempt ends, the zip is written to that attempt's folder under `test-results/` as `trace.zip` and registered as an attachment named `trace` on the test result. The crucial detail is *which* attempt is captured. `'on-first-retry'` never traces the attempt that originally failed; it traces a reproduction of it. ## Where the option lives It is a `use` option, so it can sit at the top level of the config or be narrowed per project: ```ts export default defineConfig({ retries: process.env.CI ? 2 : 0, use: { trace: 'on-first-retry' }, projects: [ { name: 'order-tracker-chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'order-tracker-mobile', use: { ...devices['Pixel 7'], trace: 'on' } }, ], }); ``` - A per-project `use` value **wins** over the top-level one, so one noisy project can record more than the rest. - `test.use({ trace: 'on' })` inside a file narrows it further, down to a describe block. - The command line wins over the config for that run: `npx playwright test --trace on`. - The value may also be written as an object — `trace: { mode: 'on-first-retry', sources: false }` — when you want the mode plus control over what goes inside the zip. ## Why suites reach for it Tracing is not free. Every recorded action stores a snapshot of the page, so traces are usually the largest thing a run produces — far heavier than a log line or a single image. `'on-first-retry'` inverts the cost model: the common case (everything green) records nothing, and capture only switches on for the small set of tests that already misbehaved once. For a food-delivery order tracker, where a suite drives live status polling and a driver map on every push, that difference is the gap between a fast pipeline and one that spends most of its time serialising page snapshots for tests that passed. ## What you give up | you want | `'on-first-retry'` gives you | |---|---| | evidence of the exact failing attempt | no — attempt one is untraced | | evidence of a deterministic bug | yes — the retry reproduces it faithfully | | evidence of a flake that passes on retry | a trace of a **passing** run, which rarely explains anything | | evidence when `retries: 0` | nothing at all | That last row is the most common surprise. Developers run locally with retries disabled, see a failure, look for a trace and find none — the mode is working exactly as specified. ## Choosing it, and when not to - Keep `'on-first-retry'` when failures are mostly reproducible and pipeline time matters. - Move to a retain-style mode when you need the *original* attempt captured rather than a re-run. - Move to `'on'` only for a small, deliberately scoped project or a debugging session — it records and keeps every attempt. - Remember that the mode says nothing about how many retries you get; that is the separate `retries` setting, and the two must be configured together for this mode to mean anything. A final practical note: with the test runner, tracing is started and stopped **for** you. You do not call the tracing API yourself on the fixture-provided context when a `trace` mode is set — the runner already owns that context's tracing, and doing both fights over the same recording.

  • If a test fails, is retried and passes, what does the trace you get actually contain?
    The retry that passed. Tracing was off for the failing attempt, so the zip is a recording of a green run: the actions all succeed and there is no error to inspect. That is the known blind spot of the mode for flaky tests, and the reason a suite chasing flakes usually needs a retain-style mode instead.
  • How would you keep 'on-first-retry' for the suite but always trace one problem spec?
    Narrow the option where the problem lives. Add `test.use({ trace: 'on' })` at the top of that spec or inside its describe block, or give the spec its own project with `use: { trace: 'on' }` and a matching `testMatch`. The `use` value closest to the test wins, so the rest of the suite keeps the cheap mode.

saying these in an interview costs you the question

  • Thinks the failing first attempt is the one traced
  • Expects traces with retries left at zero
  • Believes on-first-retry traces every retry attempt
  • Assumes tracing is free and always worth enabling
  • Calls the tracing API manually while the trace option is set
open as a page

How do Playwright's trace modes 'on' and 'retain-on-failure' differ in what survives a run?

level: middleimportance: must knowfreq 62%

basics

~10 s

Both record every test attempt, so both pay the full capture cost. The difference is afterwards: 'on' keeps every trace zip, while 'retain-on-failure' deletes the ones belonging to tests that passed.

open as a page

In Playwright, what do tracing's screenshots, snapshots and sources options each capture?

level: middleimportance: should knowfreq 45%

basics

~20 s

Screenshots capture image frames of the page over time, snapshots capture the DOM around each action so the page can be re-rendered, and sources copies the test files that drove the run into the zip.

open as a page

A Playwright CI job set trace: 'on-first-retry' but a failing test produced no trace zip; how do you diagnose it?

level: seniorimportance: should knowfreq 48%

basics

~20 s

Check whether a retry actually ran. That mode records only during a retry, so zero retries, a run aborted before the retry, or a command-line trace override all leave a failure with no trace at all.

open as a page

In a Playwright script, when would you use tracing.startChunk() instead of tracing.start()?

level: seniorimportance: nice to knowfreq 28%

basics

~10 s

Use chunks when one long-lived browser context should produce several separate trace zips. Tracing is started once on the context, then each startChunk and stopChunk pair records and exports one segment of the session.

open as a page