Playwright traces make a failed browser test replayable after the run has finished. A retained trace stores the action timeline, DOM snapshots, screenshots, console messages, and network activity that explain what the browser saw at the point of failure.
The trace setting belongs under use in playwright.config.ts, so it applies to every test unless a project or test overrides it. The retain-on-failure mode records each run while it executes, keeps the trace for failed runs, and removes traces from successful runs.
Suites that already use retries often keep retry-only traces with on-first-retry. Use retain-on-failure when the first failing run should leave a trace even without retries, or when a failed run should remain available even if a later retry passes.
Related: How to record Playwright traces
Related: How to view Playwright traces
Related: How to set Playwright test retries
$ pwd ~/projects/playwright-demo
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
use: {
trace: 'retain-on-failure'
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] }
}
]
});
Keep the rest of an existing config file in place. The important change is the trace value under the active use scope.
import { test, expect } from '@playwright/test';
test('home page shows ready state', async ({ page }) => {
await page.setContent('<main>Playwright fixture ready</main>');
await expect(page.getByText('Playwright fixture ready')).toBeVisible();
await expect(page.getByText('Missing text')).toBeVisible();
});
$ npx playwright test tests/home.spec.ts --project=chromium
Running 1 test using 1 worker
1 failed
[chromium] > tests/home.spec.ts:3:5 > home page shows ready state
##### snipped #####
attachment #2: trace (application/zip)
test-results/home-home-page-shows-ready-state-chromium/trace.zip
Playwright prints a trace attachment path only because the run failed. The exact output directory includes the test file, test title, and project name.
$ find test-results -name trace.zip test-results/home-home-page-shows-ready-state-chromium/trace.zip
import { test, expect } from '@playwright/test';
test('home page shows ready state', async ({ page }) => {
await page.setContent('<main>Playwright fixture ready</main>');
await expect(page.getByText('Playwright fixture ready')).toBeVisible();
});
$ rm -rf test-results
This makes the next file check prove the passing run's artifact behavior instead of finding the older failed-run trace.
$ npx playwright test tests/home.spec.ts --project=chromium Running 1 test using 1 worker 1 passed (719ms)
$ find test-results -name trace.zip
No output means Playwright removed the successful run's trace.
$ rm -rf tests/home.spec.ts test-results
Run this cleanup only if tests/home.spec.ts was created for this validation. Keep or rename an existing project test instead of deleting it.