Implementation:Microsoft Playwright Tracing Lifecycle
| Knowledge Sources | |
|---|---|
| Domains | Debugging, Testing |
| Last Updated | 2026-02-11 00:00 GMT |
Overview
Concrete instrumentation APIs for capturing all test execution events (actions, network traffic, DOM snapshots, console output) into the Playwright trace format.
Description
The trace capture lifecycle is implemented across two primary classes:
1. Tracing class (tracing.ts) implements the InstrumentationListener interface to intercept every Playwright API call. The onBeforeCall(), onBeforeInputAction(), onCallLog(), and onAfterCall() methods form the core capture pipeline. Each API call generates a sequence of trace events:
- BeforeActionTraceEvent: Created synchronously in
onBeforeCall()with the call ID, method name, parameters, start time, and optionally abeforeSnapshotreference. - InputActionTraceEvent: Created in
onBeforeInputAction()with the input coordinates, optionally with aninputSnapshotreference. - LogTraceEvent: Created in
onCallLog()for API-level log messages. - AfterActionTraceEvent: Created in
onAfterCall()with the result, error, end time, and optionally anafterSnapshotreference.
Events are serialized to JSON and appended to the .trace file via _appendTraceEvent() (Line 617-622). The visitTraceEvent() function traverses each event to collect SHA1 references for resource tracking.
2. Snapshotter class (snapshotter.ts) handles DOM snapshot capture. It injects a frameSnapshotStreamer script into every page frame via addInitScript(). When captureSnapshot() is called, it evaluates the streamer's captureSnapshot() method in each frame, which serializes the DOM tree into a compact array format. Resource overrides (inlined CSS, images) are extracted, hashed with SHA1, and stored as blobs in the resources directory.
Additional event sources captured by the Tracing class:
- Console messages: Via
_onConsoleMessage()producingConsoleMessageTraceEvent. - Page errors: Via
_onPageError()producingEventTraceEvent. - Dialogs: Via
onDialog()producingEventTraceEvent. - Downloads: Via
onDownload()producingEventTraceEvent. - Page open/close: Via
onPageOpen()/onPageClose(). - Network entries: Via
onEntryStarted()/onEntryFinished()writing to the.networkfile. - Screencast frames: Via page screencast event listeners, producing
ScreencastFrameTraceEvent.
Usage
These APIs are called automatically by Playwright's instrumentation infrastructure during test execution. Developers do not invoke them directly. Understanding the lifecycle is valuable for:
- Debugging trace file contents: Knowing the event format helps when manually inspecting trace files.
- Optimizing trace performance: Understanding that snapshot capture is the costliest operation.
- Extending trace capture: Adding custom events to the trace stream.
Code Reference
Source Location
- Repository: playwright
- Tracing recorder:
packages/playwright-core/src/server/trace/recorder/tracing.ts(Lines 436-488 for call hooks, Lines 617-622 for event appending) - Snapshotter:
packages/playwright-core/src/server/trace/recorder/snapshotter.ts(Lines 42-155) - Snapshot injected script:
packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts
Signature
// InstrumentationListener methods on Tracing class
class Tracing {
onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata,
parentId?: string): Promise<void>;
onBeforeInputAction(sdkObject: SdkObject,
metadata: CallMetadata): Promise<void>;
onCallLog(sdkObject: SdkObject, metadata: CallMetadata,
logName: string, message: string): void;
onAfterCall(sdkObject: SdkObject,
metadata: CallMetadata): Promise<void>;
}
// Snapshotter class
class Snapshotter {
constructor(context: BrowserContext, delegate: SnapshotterDelegate);
start(): Promise<void>;
stop(): void;
captureSnapshot(page: Page, callId: string,
snapshotName: string): Promise<void>;
}
// SnapshotterDelegate interface
interface SnapshotterDelegate {
onSnapshotterBlob(blob: SnapshotterBlob): void;
onFrameSnapshot(snapshot: FrameSnapshot): void;
}
// SnapshotterBlob type
type SnapshotterBlob = {
buffer: Buffer;
sha1: string;
};
Import
// These are internal APIs, not directly imported by users.
// The Tracing class is instantiated by BrowserContext:
// packages/playwright-core/src/server/browserContext.ts
// For trace event types:
import type * as trace from '@trace/trace';
import type { FrameSnapshot } from '@trace/snapshot';
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| sdkObject | SdkObject |
Yes | The Playwright SDK object being acted upon (e.g., Page, Frame, ElementHandle). Provides attribution info (page, context). |
| metadata | CallMetadata |
Yes | Metadata for the current API call including id, type, method, params, startTime, endTime, error, result, pageId, stepId. |
| page | Page |
Yes | For snapshot capture: the Page instance whose frames will be snapshotted. |
| callId | string |
Yes | Unique identifier for the API call, used to correlate before/after events and snapshots. |
| snapshotName | string |
Yes | Name for the snapshot (e.g., 'before@callId', 'after@callId'). Used to look up snapshots in the viewer.
|
Outputs
| Name | Type | Description |
|---|---|---|
| BeforeActionTraceEvent | JSON |
Written to .trace file. Contains: type='before', callId, startTime, class, method, params, stack, beforeSnapshot.
|
| InputActionTraceEvent | JSON |
Written to .trace file. Contains: type='input', callId, point coordinates.
|
| AfterActionTraceEvent | JSON |
Written to .trace file. Contains: type='after', callId, endTime, error, result, afterSnapshot.
|
| FrameSnapshot | JSON |
Written to .trace file as type='frame-snapshot'. Contains callId, snapshotName, pageId, frameId, doctype, html (serialized DOM), viewport, resourceOverrides.
|
| ResourceSnapshotTraceEvent | JSON |
Written to .network file as type='resource-snapshot'. Contains HAR entry data with request/response details.
|
| ScreencastFrameTraceEvent | JSON |
Written to .trace file. Contains: type='screencast-frame', pageId, sha1, width, height, timestamp.
|
| Resource blobs | files |
SHA1-named files in the resources/ directory containing images, stylesheets, and other binary content.
|
Usage Examples
Basic Example
// The trace lifecycle is automatic. Here is what happens internally
// when a test calls page.click('#button'):
// 1. onBeforeCall() is triggered:
// - Creates BeforeActionTraceEvent with method='click', params={selector:'#button'}
// - If snapshots enabled, captures DOM snapshot named 'before@call-id'
// - Appends event to .trace file
// 2. onBeforeInputAction() is triggered:
// - Creates InputActionTraceEvent with point={x:100, y:200}
// - If snapshots enabled, captures DOM snapshot named 'input@call-id'
// - Appends event to .trace file
// 3. The actual click is performed by the browser
// 4. onAfterCall() is triggered:
// - Creates AfterActionTraceEvent with endTime, result
// - If snapshots enabled, captures DOM snapshot named 'after@call-id'
// - Appends event to .trace file
Trace Event Format Example
{"type":"before","callId":"call@1","startTime":1234567890,"class":"Page","method":"click","params":{"selector":"#button"},"beforeSnapshot":"before@call@1"}
{"type":"input","callId":"call@1","point":{"x":150,"y":200},"inputSnapshot":"input@call@1"}
{"type":"frame-snapshot","snapshot":{"callId":"call@1","snapshotName":"before@call@1","pageId":"page@1","frameId":"frame@1","html":["HTML",{},["HEAD",{}],["BODY",{},["BUTTON",{"id":"button"},"Click me"]]],"viewport":{"width":1280,"height":720}}}
{"type":"after","callId":"call@1","endTime":1234567990}
Chunk Management Example
// startChunk() at tracing.ts:L178-220 begins a recording segment:
// - Clears callIds set
// - Allocates new trace file path
// - Writes context-options event
// - Registers instrumentation listener
// - Starts screencast if enabled
// - Starts snapshotter if enabled
// stopChunk() at tracing.ts:L347-424 ends the segment:
// - Closes all open groups
// - Removes instrumentation listener
// - Stops screencast and snapshotter
// - Flushes pending HAR entries
// - Collects all file entries (trace, network, resources)
// - Optionally creates ZIP archive