Record and open a trace

Capture actions, DOM snapshots, and network activity from a run, then inspect the trace locally.

Capture a trace of the run: actions, DOM snapshots, screenshots, and network activity. Then inspect the recorded timeline.

Start tracing with the helper API

Tracing lives on the context, but it records a page, so the page is its first argument. Snapshots give you the inspectable DOM; screenshots feed the timeline filmstrip; sources attach the PHP that drove each step.

php
$context = Playwright::chromium();
$page = $context->newPage();

$context->startTracing($page, [
    'screenshots' => true,
    'snapshots' => true,
    'sources' => true,
]);

The options go in an array. Use this helper form for the common case; use tracing() only when you need chunks or named groups.

Run your steps, then stop with a path

Everything between the start and the stop lands in the archive.

php
$page->goto('https://example.com/checkout');
$page->getByRole('button', ['name' => 'Pay now'])->click();

$context->stopTracing($page, 'trace.zip');

stopTracing() takes the same page, then the path to write. The archive is self-contained.

Use chunks when you need them

For advanced runs, use the tracing object directly:

php
$context->tracing()->start(['screenshots' => true, 'snapshots' => true]);
$context->tracing()->startChunk(['title' => 'checkout']);

$page->goto('https://example.com/checkout');
$page->getByRole('button', ['name' => 'Pay now'])->click();

$context->tracing()->stopChunk(['path' => 'checkout.zip']);
$context->tracing()->stop();

Most tests should use the helper form above. Reach for chunks only when one browser session contains several flows worth saving separately.

Open the viewer

The trace format is Playwright's own, so Playwright's viewer reads it. That viewer ships with the Node package, not the PHP one:

bash
npx playwright show-trace trace.zip

It runs locally. Nothing leaves your machine.

Timeline below, DOM snapshot above. Click any step to see the page exactly as it was, network and console included.

Expected result

The trace path exists and is a non-empty .zip file:

php
self::assertFileExists('trace.zip');
self::assertGreaterThan(0, filesize('trace.zip'));

Open it with the trace viewer before treating the capture as useful. A trace that exists but does not contain the failing action usually means tracing started too late or stopped too early.

On CI

Keep the run headless and record a trace when a test fails, then upload trace.zip as a build artifact. You get the whole run back with no display attached. See continuous integration.

Go next

← All recipes