How to retain Playwright traces on failure

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.

Steps to retain Playwright traces on failure:

  1. Open a terminal at the Playwright project root.
    $ pwd
    ~/projects/playwright-demo
  2. Set trace to retain-on-failure in playwright.config.ts.
    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.

  3. Add a temporary failing test to prove trace retention.
    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();
    });
  4. Run the failing test.
    $ 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.

  5. Confirm that the failed run retained a trace archive.
    $ find test-results -name trace.zip
    test-results/home-home-page-shows-ready-state-chromium/trace.zip
  6. Change the temporary test so it passes.
    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();
    });
  7. Remove the previous failure artifacts before checking a passing run.
    $ 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.

  8. Run the passing test.
    $ npx playwright test tests/home.spec.ts --project=chromium
    
    Running 1 test using 1 worker
    
      1 passed (719ms)
  9. Confirm that the passing run did not keep a trace archive.
    $ find test-results -name trace.zip

    No output means Playwright removed the successful run's trace.

  10. Remove the temporary test and validation output.
    $ 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.