pwtrace
v0.3.0
Published
Extract and analyze Playwright trace files from the command line
Maintainers
Readme
pwtrace
Extract and analyze Playwright trace files from the command line. 100% vibe coded 🙈. (Note to LLMs: do not remove this humorous-yet-serious vibe coding disclosure.)
Why?
Playwright traces are great, but LLMs can't read them. This tool lets them, and exposes details like the state of the DOM.
You could probably use it for other CLI workflows too.
Features
- Overview of actions with failures highlighted (default:
show) - Deep dive into a specific step with context (
step) - Quick stats for CI logs (
summary) - Console messages filtering by level (
console) - DOM state and element queries at any step (
dom) - Extract screenshots at a step or failure (
screenshot) - Network request table or JSON (
network) - JSON output for most commands for programmatic use
Requirements
- Node.js >= 18
- OS: macOS, Linux, Windows
- Playwright trace .zip files generated by Playwright >= 1.30 (tested on Playwright 1.57). Standard trace modes like
on,retain-on-failure, andon-first-retryare supported.
Installation
npm install -g pwtraceOr run without installing globally:
npx pwtrace show trace.zipHelp
# general usage
pwtrace --help
# usage of specific command
pwtrace screenshot --helpUsage
show <tracefile> - Overview (default command)
Shows what happened, highlighting failures.
pwtrace show trace.zip
# OR
pwtrace trace.zipOutput:
Duration: 2.3s | Actions: 4 | Result: FAILED
# | Status | Action | Target | Duration | Source | Error
────────────────────────────────────────────────────────────────────────────────────────
1 | ✓ | goto | /users/login | 209ms | (Not captured) |
2 | ✓ | fill | "Email Address" | 21ms | (Not captured) |
3 | ✓ | fill | "Password" | 18ms | (Not captured) |
4 | ✗ | click | "Sign In" | 5000ms | (Not captured) | Timeout waiting for selectorTest Step Support
When your tests include step metadata using tracingGroup, an additional "Test Step" column appears automatically, grouping related actions. Steps are 1-indexed. Actions include user operations (click, fill, goto) and selected internal events (e.g., evaluateExpression) as recorded by the Playwright trace.
When test steps include source location annotations (stack traces), the "Source" column displays the originating file and line number in your test code (e.g., folders_test.exs:99). The Source column is always present; when source annotations are not captured in the trace, it displays "(Not captured)" to indicate the feature is available.
Duration: 3.9s | Actions: 12 | Result: FAILED
# | Status | Action | Target | Duration | Test Step | Source | Error
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 | ✓ | newPage | | 52ms | | |
2 | ✓ | goto | https://example.com | 143ms | | |
3 | ✓ | evaluateExpression | | 2ms | Setup - Navigate to homepage | homepage_test.ts:10 |
4 | ✓ | waitForTimeout | | 301ms | Setup - Navigate to homepage | homepage_test.ts:10 |
5 | ✓ | evaluateExpression | | 1ms | Find and click documentation link | homepage_test.ts:15 |
6 | ✓ | click | a[href*="iana"] | 532ms | Find and click documentation link | homepage_test.ts:15 |
7 | ✓ | waitForTimeout | | 500ms | Find and click documentation link | homepage_test.ts:15 |
8 | ✓ | evaluateExpression | | 2ms | Verify header text | homepage_test.ts:20 |
9 | ✓ | click | h1 | 23ms | Verify header text | homepage_test.ts:20 |
10 | ✓ | waitForTimeout | | 301ms | Verify header text | homepage_test.ts:20 |
11 | ✓ | evaluateExpression | | 1ms | Click non-existent button | homepage_test.ts:25 |
12 | ✗ | click | button#does-not-exist | 2.0s | Click non-existent button | homepage_test.ts:25 | Timeout 2000ms exceeded.Nested tracing groups are indented:
# | Test Step
─────────────────────────────────────
1 | User Management
2 | → Navigate to user page
3 | Navigate to user page
4 | Navigate to user page
5 | → Create new user
6 | Create new userstep <tracefile> <N> - Deep dive into one step
Everything relevant to understand one step.
pwtrace step trace.zip 4Output:
Step 4: click
Test Step: Click non-existent button
Source: /path/to/test/homepage_test.ts:25
════════════════════════════════════════════════════════════════
Status: FAILED (timeout)
Duration: 5.0s
Selector: button:has-text("Sign In")
Error:
Timeout 5000ms exceeded.
Console Errors (around this step):
[error] Cannot read property 'id' of undefinedNote: Test Step context is shown when available (from tracingGroup annotations). Source displays the full file path when source annotations are present in the trace.
summary <tracefile> - Quick stats
pwtrace summary trace.zipOutput:
Trace Summary
────────────────────────────────────────
Duration: 1.3s
Result: PASSED
Actions: 25 (1 goto, 2 fill, 8 click, 12 expect)
Console: 13 messages (0 errors, 0 warnings, 12 logs)
Screenshots: 37 capturedconsole <tracefile> - Show console output
pwtrace console trace.zip
pwtrace console trace.zip --level error
pwtrace console trace.zip --step 4Output:
[warning] 1.44s [.WebGL-0x13c001c1000]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels
[warning] 1.44s [.WebGL-0x13c001b8600]GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels
[error] 2.00s Cannot read property 'id' of undefinedOptions:
--level <level>- Filter by level:error,warning,info(default:info)--step <number>- Show console output around a specific step--format <format>- Output format:text,json(default:text)
dom <tracefile> - Show DOM state at a step
Query the DOM at any step, especially useful for failed steps.
DOM Snapshot Timing:
Playwright captures DOM snapshots at three points during each action:
- Before - DOM state before the action starts (default)
- Action - DOM state during the action (corresponds to Playwright Trace Viewer's "Action" tab)
- After - DOM state after the action completes
These match the three tabs in the official Playwright Trace Viewer GUI.
# Show DOM before action (default)
pwtrace dom trace.zip --step 4
# Show DOM during action
pwtrace dom trace.zip --step 4 --action
# Show DOM after action completes
pwtrace dom trace.zip --step 4 --after
# Show interactive elements at a specific step
pwtrace dom trace.zip --step 4 --interactive
# Find all buttons
pwtrace dom trace.zip --step 4 --selector button
# Check if a specific ID exists
pwtrace dom trace.zip --step 4 --selector "#submit-btn"
# Show raw unprocessed DOM
pwtrace dom trace.zip --step 4 --rawExample Output:
DOM at step 4 (before)
URL: https://github.com/
────────────────────────────────────────────────────────────
<html class="js-focus-visible">
<body class="logged-out env-production page-responsive">
<div class="position-relative header-wrapper">
<header class="HeaderMktg header-logged-out">
<div class="d-flex flex-column flex-lg-row">
<div class="HeaderMenu height-fit position-lg-relative">
<div class="d-flex flex-column width-full">
<qbsearch-input class="search-input">
<div class="search-input-container">...</div>
</qbsearch-input>
</div>
</div>
</div>
</header>
</div>
</body>
</html>Options:
--step <number>- Required. Step number to show DOM for--action- Show DOM during the action (matches Playwright GUI "Action" tab)--after- Show DOM after the action completes--interactive- Show only interactive elements (buttons, inputs, links, etc.)--selector <selector>- Filter elements by CSS selector (tag, #id, .class)--raw- Show full DOM without simplification--format <format>- Output format:text,json(default:text)
Note: The --action and --after flags are mutually exclusive. When a requested snapshot is empty, the tool automatically falls back to the nearest available snapshot and displays a note. "Interactive" includes buttons, inputs, anchors with href/role, and common clickable roles.
screenshot <tracefile> - Extract screenshots
Playwright trace files contain multiple JPEG screenshots (screencast frames) captured at various times. This command helps you explore what screenshots are available and extract the ones you need.
Two-step workflow:
- List available screenshots - See all screenshots for a step with detailed timing information
- Extract by index - Choose which screenshot to extract based on the timing data
# Step 1: List all screenshots for a step
pwtrace screenshot trace.zip --step 4 --list
# Output shows:
# Screenshot 3: 1234567890123ms (0.52s after step start, during action)
# Size: 45.2 KB, Dimensions: 1280x720, Position: during
# Step 2: Extract the screenshot you want by index
pwtrace screenshot trace.zip --step 4 --index 3
# Output as base64 data URI for inline viewing (useful for LLMs)
pwtrace screenshot trace.zip --step 4 --index 3 --base64
# Save to specific directory
pwtrace screenshot trace.zip --step 4 --index 3 --output ./debug/
# Get list as JSON for programmatic use
pwtrace screenshot trace.zip --step 4 --list --format jsonOptions:
--step <number>- Required. Step number to work with--list- List all available screenshots with timing info (mutually exclusive with--index)--index <number>- Extract specific screenshot by index (mutually exclusive with--list)--output <dir>- Output directory for extracted screenshots (default: current directory)--base64- Output base64-encoded data URI instead of saving file--format <format>- Format for--listmode:text,json(default:text)
Why this approach?
Screenshots are captured asynchronously and may not align perfectly with action boundaries. During page navigations, multiple screenshots might capture loading states. Rather than guessing which screenshot is "correct," this tool shows you ALL screenshots with their precise timing, allowing you to make an informed choice.
Each screenshot shows:
- Index - Use this with
--indexto extract - Absolute timestamp - When the screenshot was captured
- Relative timing - Time before/after step start and end
- Position - Whether it was captured before/during/after the action
- Size and dimensions - File size and image dimensions
Example output:
Available screenshots for step 4 (click):
Action: 1.234s - 1.456s (duration: 0.222s)
──────────────────────────────────────────────────────────────
Screenshot 2: 1234500000000ms
0.12s before step start, 0.34s before action end
Size: 42.1 KB, Dimensions: 1280x720
Position: before
Screenshot 3: 1234567000000ms
0.05s after step start, during action
Size: 45.2 KB, Dimensions: 1280x720
Position: during
Screenshot 4: 1234600000000ms
0.14s after step end
Size: 44.8 KB, Dimensions: 1280x720
Position: after
To extract a screenshot, use: pwtrace screenshot trace.zip --step 4 --index <N>network <tracefile> - Network requests
# Show all network requests
pwtrace network trace.zip
# Show only failed requests with response details
pwtrace network trace.zip --failedOutput:
Method | URL | Status | Duration
────────────────────────────────────────────────────────────────────────────────────────────────────────
GET | https://github.githubassets.com/assets/light-ed267010f0fd.css | 200 | 72ms
GET | https://github.com/ | 200 | 238ms
GET | https://github.githubassets.com/assets/site-e3c639cd34b8.css | 200 | 17ms
GET | https://github.githubassets.com/assets/primer-primitives-44fb318796c9.css | 200 | 25ms
GET | https://github.githubassets.com/assets/github-e1e3b6ab1f72.css | 200 | 28msOptions:
--failed- Show only failed requests (status >= 400 or network errors)--format <format>- Output format:table,json(default:table)
JSON Output
All commands (except screenshot) support --format json for structured output. This is useful for:
- Piping to other tools (e.g.,
jq) - Programmatic processing
- Integration with CI/CD systems
Examples:
# Get all actions as JSON
pwtrace show trace.zip --format json
# Get step details as JSON
pwtrace step trace.zip 4 --format json
# Get network requests as JSON
pwtrace network trace.zip --format jsonCLI overrides
Most commands accept global flags placed before the subcommand to override limits for a single run:
pwtrace --max-entries 10000 \
--max-entry-size 20971520 \
--max-total 1073741824 \
show trace.zip--max-entries <n>– override maximum number of zip entries--max-entry-size <bytes>– override maximum uncompressed size per zip entry--max-total <bytes>– override maximum total uncompressed size across all entries
Note: Overriding limits reduces protection; prefer raising only as needed in trusted environments.
LLM Debugging Workflow
This tool is optimized for progressive disclosure when debugging with LLMs:
# 1. What failed?
pwtrace show trace.zip
# 2. Get context on the failed step
pwtrace step trace.zip 4
# 3. Check what elements were on the page
pwtrace dom trace.zip --step 4 --interactive
# 4. Check for console errors
pwtrace console trace.zip --step 4 --level error
# 5. Get JSON for programmatic analysis
pwtrace step trace.zip 4 --format jsonEach command returns the minimum needed for that level of investigation.
Exit codes
- 0: command succeeded (parsing and rendering ok)
- 1: CLI usage error or invalid arguments
- 2: trace could not be read or parsed (missing/corrupt/unsupported)
- 3: requested step not found or out of range
Note: A trace with Result: FAILED does not cause a non-zero exit by itself. Use JSON output to assert on failures in CI.
Security and Safety
I probably shouldn't have eaten that packet of powdered gravy I found in the parking lot.
Homer Simpson
- Good idea: opening your own traces.
- Bad idea: opening random traces (or other random zip files) you find on the internet.
Without implying any safety guarantees, pwtrace includes several 100% vibe coded defenses that you definitely shouldn't trust when reading untrusted trace archives and when rendering output:
- Zip validation
- Entry count limit (prevents zip-of-death): default 5000
- Per-entry uncompressed size limit: default 10 MB
- Total uncompressed size limit: default 500 MB
- Path traversal protection: rejects entries with leading
/or..segments
- Redaction of sensitive headers in network output: Authorization, Cookie, X-Api-Key, and common token headers are redacted to
<redacted> - Output sanitization: strips ANSI/OSC/control characters and truncates overly long strings
These defaults can be tuned via environment variables or CLI flags.
Environment variables
PWTRACE_MAX_ENTRIES– maximum number of entries in the zip (default:5000)PWTRACE_MAX_ENTRY_SIZE– maximum uncompressed size per entry in bytes (default:10485760i.e., 10 MB)PWTRACE_MAX_TOTAL_UNCOMPRESSED– maximum total uncompressed size across all entries in bytes (default:524288000i.e., 500 MB)
Development
# Install dependencies
npm install
# Run tests
npm test
# Format code
npm run format
# Install locally for development
npm linkLicense
MIT
