A community-driven registry for Claude, Cursor, Windsurf, Cline & more. Not affiliated with Anthropic.
Are you the author? Sign in to claim
Open-source statement-level Playwright tracer, purpose-built for AI agents. Analyzes test runs with increased accuracy.
Open-source statement-level Playwright tracer, purpose-built for AI agents.
heal-playwright-tracer is an agent-first diagnostic layer for your Playwright tests. It gives agents (and humans) everything they need to quickly analyze test results.
👉 Add this to your playwright config, run your tests, point Claude to the improved heal trace, get more accurate test diagnosis
The playwright trace doesn't contain enough data for LLM-based agents such as Claude or Open Code to analyze tests results reliably. That's because the trace ifs focused on locator evaluation, while real-life tests also evaluate non-playwright code. Heal adds the missing instrumentation layer to let LLM agents work their magic. And it's useful for humans in complex test codebases, too!
| Feature | Playwright Trace | Heal Tracer | Example: What Heal Adds |
|---|---|---|---|
| Granularity | Action-level | Statement-level | Shows let x = calculate() line-by-line, not just the final page.click(). |
| Data Format | ZIP/Binary | NDJSON Stream | {"type":"step","file":"auth.spec.ts","line":12,"val":{"user":"dev"}} |
| Visual Context | Standard screenshots | Highlighted locators | An image where the target button is outlined in a neon overlay to prove hit-box accuracy. |
| Variable State | Limited/Debugger only | Full Variable Values | Captures that status_code was 403 inside a hidden helper function. |
| Error Detail | Standard stack trace | Serialized Errors | A JSON object containing the DOM snapshot at the exact millisecond of the throw. |
| Timing | Action durations | Per-statement timing | Identifies that a specific if statement logic took 2.5s to evaluate. |
| Correlations | Loose logs/network | API Correlations | Links Trace_ID_99 directly to Source_Line_45 in the NDJSON stream. |
npm install -D @heal-dev/heal-playwright-tracer
Wire the Babel plugin and the reporter in playwright.config.ts:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// @ts-ignore — `babelPlugins` is a supported Playwright option not yet in its public types
'@playwright/test': {
babelPlugins: [
[
require.resolve('@heal-dev/heal-playwright-tracer/code-hook-injector'),
{ include: [/\/tests\//] },
],
],
},
reporter: [['@heal-dev/heal-playwright-tracer/reporter']],
});
Both are required: if you wire the Babel plugin without the
reporter, the fixture fails fast on the first test of every worker.
For why the reporter is mandatory (crash rescue, Playwright
attachment copy, execution-history index), see
docs/configuration.md.
If you prefer to keep the config fully typed, declare the
babelPlugins option once at the top of the file instead of using
@ts-ignore:
declare module '@playwright/test' {
interface Config {
'@playwright/test'?: {
babelPlugins?: Array<[string, object?]>;
};
}
}
Per-test output lands at
heal-traces/<executionId>/<playwrightTestId>/<attempt>/heal-traces.ndjson.
See Output layout below for the full tree.
Every run produces a self-contained execution dir under:
heal-traces/<executionId>/<playwrightTestId>/<attempt>/heal-traces.ndjson.
<cwd>/heal-traces/
├── executions.ndjson # append-only run index
└── <executionId>/ # auto-generated uuidv4 per run
├── execution.json # per-run manifest
└── <playwrightTestId>/ # Playwright testInfo.testId
└── <attempt>/ # 1-indexed
├── heal-traces.ndjson
├── trace.zip # if Playwright recorded one
├── screenshots/
│ └── stmt-0001.png
└── videos/
└── video.webm
Keys are shaped {executionId}/{testId}/{attempt}/... so the layout
maps cleanly onto any object-store key prefix if you ship traces
elsewhere later.
History is append-only — runs accumulate, nothing is pruned.
Clean up manually with rm -rf heal-traces/<id>/ when needed.
Note: add
heal-traces/to your.gitignore— these are local build artefacts and should never be committed.
<executionId> is a uuidv4 the reporter generates at the start of
each run; the trace viewer uses it to scope and group artefacts per
run.
npx playwright test command.heal-traces.ndjson.A small CLI ships alongside the tracer so humans can browse the captured traces in a local browser without setting up a Heal account:
npx heal-tracer view
The CLI starts a local HTTP server on a free OS-assigned port,
reads <cwd>/heal-traces/, lists every recorded execution in the
header dropdown (newest first), and opens the latest one in your
default browser. Switch executions from the dropdown to inspect
history. Press Ctrl+C to stop.
| Flag | Description |
|---|---|
--port <port> | Bind a fixed port instead of an OS-assigned ephemeral one. Useful when an external frontend needs a stable URL. Falls back to the HEAL_TRACER_PORT env var. |
--api-only | Serve only the /api/* routes — no SPA bundle, no browser auto-open. For driving the REST API from a separate frontend dev server. |
--verbose | Mirror spawned subprocess output (heal analyze, heal login) to the tracer console. |
To consume the REST API from your own frontend during development, run the server on a fixed port without the bundled UI:
npx heal-tracer view --api-only --port 3001
# or, via env (e.g. from a .env loaded with `node --env-file`, direnv, or your shell):
HEAL_TRACER_PORT=3001 npx heal-tracer view --api-only
CORS is wide-open (Access-Control-Allow-Origin: *), so a frontend
on its own dev server can fetch('http://localhost:3001/api/executions')
cross-origin with no extra setup. The API is unauthenticated and
localhost-bound by design — don't expose it on a public interface.
See this Claude skill for a starter.
heal-data/heal-traces.ndjson — one record per line:
{"kind":"test-header","schemaVersion":1,"test":{"title":"it works","file":"tests/example.spec.ts","context":{"testId":"...","attempt":1}}}
{"kind":"statement","statement":{"loc":{"line":5},"source":"await page.goto('https://example.com')","durationMs":412,"status":"ok","children":[...]}}
{"kind":"statement","statement":{"loc":{"line":6},"source":"await expect(page.getByRole('heading')).toBeVisible()","durationMs":73,"status":"ok"}}
{"kind":"test-result","status":"passed","duration":1234,"stdout":"...","stderr":""}
Schema: src/domain/trace-event-recorder/model/statement-trace-schema.ts
(also exported as @heal-dev/heal-playwright-tracer/statement-trace-schema).
Every statement that calls a patched Playwright locator action
(click, fill, hover, press, …) or a locator assertion
(expect(locator).toBeVisible(), toHaveText(), …) produces a
PNG screenshot with the targeted element outlined via an overlay
drawn in-page — so the agent sees what Playwright was actually
pointing at at the moment the action ran, not just the raw page.
Files are written to the per-test heal-data/ directory and
referenced on the corresponding statement via the screenshot
field:
{"kind":"statement","statement":{"source":"await page.getByRole('button', { name: 'Submit' }).click()","status":"ok","screenshot":"stmt-0007.png"}}
{"kind":"statement","statement":{"source":"await expect(page.getByRole('alert')).toBeVisible()","status":"ok","screenshot":"stmt-0008.png"}}
Statements that don't touch a locator (plain JS, utility calls,
page.goto) have no screenshot field — capture is scoped to the
Playwright surface where it adds diagnostic signal.
See development.md
The Babel plugin rewrites every leaf statement with a try/catch/finally
and three hook calls — the same shape of transformation Istanbul applies
for code coverage. Two consequences to be aware of:
await page.click(...), network, navigation) are dominated by the browser
and barely move.Scope the include filter in playwright.config.ts so only your
tests/ directory is instrumented — never your app code or
node_modules — to keep the cost contained.
Copyright © 2026 MYIA SAS.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), except for the tracer-viewer-bundle which is a vendored, free to use version of the Heal trace viewer.
See the LICENSE file for the full text.
Claude Code skill for YouTube creators — channel audits, video SEO, retention scripts, thumbnails, content strategy, Sho
AI image generation skill for Claude Code -- Creative Director powered by Gemini
A Claude Code skill by Hao (駱君昊) that learns your Facebook voice and auto-posts to FB / IG / Threads / X with a 14-day c
Universal SEO skill for Claude Code. 25 sub-skills + 18 sub-agents covering technical SEO, E-E-A-T, schema, GEO/AEO, bac