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.
$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.
$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:
$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:
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:
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.