npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gowthaman-ravi/pw-recorder

v0.2.0

Published

Playwright-based manual-action recorder with right-click expectations, exposed via CLI and MCP for LLM-driven test generation.

Readme

pw-recorder

Record manual browser actions and right-click expectations, clean them into a per-session artifact, and generate a runnable @playwright/test spec — then replay it with the Playwright runner.

A QA drives a real browser. The tool captures what they do (clicks, fills, selects, hovers, drags, uploads, navigations…) and what they assert (right-click → "Expect visible / text =…"), plus per-action before/after HTML snapshots and per-request network JSON. A post-processing pass removes noise, and codegen turns the cleaned timeline into a real Playwright test.

Exposed two ways: a CLI and an MCP server your coding agent can call.

Install

npm install -g @gowthaman-ravi/pw-recorder   # or: npm i -D @gowthaman-ravi/pw-recorder
npx playwright install chromium              # one-time browser download

This provides two commands: pw-recorder (CLI) and pw-recorder-mcp (MCP server). The published package already ships the built dist/, so there's no build step. (If you didn't install globally, prefix with npx, e.g. npx pw-recorder …, or run npx @gowthaman-ravi/pw-recorder … without installing.)

To hack on the tool instead of just using it, see Development.

Quick start

# 1. Record — opens a real browser; drive it, right-click to add expectations,
#    click Stop (or close the window) when done.
pw-recorder launch https://example.com --name checkout

# 2. See the cleaned timeline
pw-recorder show <sessionId>

# 3. Generate a Playwright spec  →  sessions/<id>/<id>.spec.ts
pw-recorder codegen <sessionId>

# 4. Run it (generates if missing; runs your edits as-is otherwise)
pw-recorder rerun <sessionId>

While recording:

  • Drive the page normally — clicks, typing, selects, hovers, drag-drop, file uploads, scrolling, and clipboard paste are captured. Navigations are recorded too.
  • Right-click any element to add an expectation (visible, text =, contains text, value =, attribute, count).
  • Shift + right-click falls through to Chrome's native context menu.
  • A small red REC bar (top-right) has the Stop button.

CLI

pw-recorder launch [url] [options]     # record a session
pw-recorder list                        # list sessions
pw-recorder show <id> [--raw] [--json]  # print the timeline (cleaned by default)
pw-recorder export <id> [--snapshots]   # write actions.normalized.json (+ lean snapshots)
pw-recorder codegen <id> [--validate] [--config <f>] [--print]
pw-recorder rerun <id> [--regen] [--validate] [--headed] [--config <f>]

launch options: --name, --out <dir>, --headless, --viewport 1440x900, --storage-state <file>, --network xhr|graphql|all (default xhr).

Notes:

  • show prints the normalized (deduped) timeline; --raw shows the raw stream.
  • codegen always regenerates <id>.spec.ts (overwrites hand edits).
  • rerun runs your existing (possibly hand-edited) spec as-is; pass --regen to rebuild it from the recording first. --validate implies --regen.
  • --validate re-counts semantic locators with Playwright's real engine against the recorded snapshots and drops any it can't resolve (needs browsers).

MCP server

PW_RECORDER_OUT=./sessions pw-recorder-mcp

| Tool | Purpose | |---|---| | browser_launch | Open a browser, start recording, returns sessionId (networkFilter: xhr/graphql/all) | | browser_status | Live counts for a running session | | session_stop | Close browser, finalize artifacts (writes actions.normalized.json) | | session_list | All sessions on disk | | session_get | Metadata + actions (raw) and normalizedActions (cleaned) + network index | | session_export | Write actions.normalized.json (and, with snapshots, lean snapshots) | | session_codegen | Generate <id>.spec.ts and return it (validate, config) | | session_rerun | Run the spec (regen to rebuild, validate, headed, config) |

Wiring into an agent

{
  "mcpServers": {
    "pw-recorder": {
      "command": "npx",
      "args": ["-y", "@gowthaman-ravi/pw-recorder", "pw-recorder-mcp"],
      "env": { "PW_RECORDER_OUT": "/abs/path/to/your-repo/recordings" }
    }
  }
}

(If installed globally you can use "command": "pw-recorder-mcp" with no args.)

Then: "Use pw-recorder to launch a browser on staging so I can record a test." The agent calls browser_launch, you drive + add expectations, it calls session_stop, then session_codegen / session_rerun.

Normalization

The raw recording is noisy, so codegen consumes a cleaned, causally-ordered view (normalizedActions), derived non-destructively — the raw actions.json is never modified. session_stop also persists it as actions.normalized.json.

Passes: sort by sequence; drop scrolls (Playwright auto-scrolls); drop a clipboard paste a later fill reproduces; drop focus-clicks (a click whose element is then filled); collapse redirect chains and drop gesture-induced navigations (a navigation a click/press triggered — even with a hover/expect in between — since Playwright waits for it automatically); drop a hover that's just the mouse moving to a click/expect target.

Codegen

codegen / rerun produce a real @playwright/test spec:

  • Locators, best candidate wins. Each element records candidates (getByTestIdgetByLabel/getByPlaceholder/getByRolegetByText#id/[name] → css → xpath) each with a match count. Codegen picks the highest-priority candidate that's unique, and for form controls prefers the attribute-reliable label/placeholder over an ARIA-computed role name.
  • Exact matching. Text locators emit { exact: true } so getByText('Location') doesn't also match 'Location Launcher'.
  • Scoped locators. When a semantic locator is ambiguous but unique inside a stable container, codegen scopes it — e.g. page.locator('.chakra-modal__footer').getByRole('button', { name: 'Save', exact: true }) instead of a brittle nth-of-type css chain.
  • Hoisted variables. Every locator becomes a const locatorNNN = … at the top of the test, deduped and reused; scoped chains are split so the container is its own reusable const.
  • Value consts. Fill/paste values become named consts (const password = …) and are reused everywhere they appear, including in assertions.
  • Loader waits. Where a step's snapshot shows a configured loading indicator, codegen inserts await locator.first().waitFor({ state: 'detached', timeout }) so the test waits for spinners/skeletons to clear.
  • --validate verifies locators against Playwright's real engine.

Configuration

Loader selectors and their timeout come from an optional config file, discovered via --config <path>, the PW_RECORDER_CONFIG env var, or pw-recorder.config.(yml|yaml|json) found by walking up from the working dir. See pw-recorder.config.example.yml.

# User loaders EXTEND the built-in defaults (they don't replace them):
#   .chakra-spinner .chakra-skeleton .ant-spin .ant-spin-spinning
#   .ant-skeleton [data-loading] [aria-busy="true"]
loaders:
  - .my-app-spinner
  - '[data-busy]'
loaderTimeout: 10000   # ms to wait for a loader to leave the DOM (default 10000)

Network capture

By default XHR + fetch requests are persisted (--network xhr), which includes GraphQL; documents, scripts, styles, images and fonts are ignored. Choose graphql for GraphQL-only or all for everything. GraphQL requests are detected (URL, JSON query body incl. batches, application/graphql, or a GET query param) and their operationName / operationType are stored and used in the filename (0001-POST-host-Login.json).

Session layout

sessions/<sessionId>/
  meta.json                  # url, viewport, ua, counts, timestamps
  actions.json               # raw ordered timeline (actions + expectations)
  actions.normalized.json    # cleaned, causally-ordered timeline (codegen input)
  <sessionId>.spec.ts        # generated @playwright/test spec
  snapshots/                 # <id>.before.html / <id>.after.html per action
  network/                   # one JSON per request: 0001-POST-host-path.json

actions.json entries are typed; type:"expect" entries carry an expect block (kind, expected, actual). Selectors carry primary plus best-first candidates (each with a matchCount) for robust generation.

Architecture

The browser is a real Playwright persistent context; the QA interacts with it directly. The recorder is injected via addInitScript. Match counts for semantic locators are computed in-page at capture; --validate refines them at codegen time with Playwright's real selector engine against the stored snapshots.

Development

Working on the tool itself (from a clone of this repo):

npm install
npm run setup          # playwright install chromium
npm run build          # tsc → dist/

# run the CLI from source (equivalent to the pw-recorder bin):
npm run cli -- launch https://example.com --name checkout
npm run codegen -- <sessionId>
npm run rerun -- <sessionId>

npm run verify:offline # browser-free unit checks (candidates, normalize, codegen, config)
npm run verify         # full headless end-to-end pipeline check (needs browsers)