# @puppeteer/replay for Chrome Recorder JSON

> @puppeteer/replay parses, runs, and stringifies user flows recorded by Chrome DevTools Recorder. It suits browser automation developers who need the CLI, a TypeScript API, execution hooks, or conversion to Puppeteer code.

**puppeteer/replay** — Library that provides an API to replay and stringify recordings created using Chrome DevTools Recorder

- Repository: https://github.com/puppeteer/replay
- Stars: 1,390 · Forks: 615
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/puppeteer-replay

## Where @puppeteer/replay Fits in Browser Automation

@puppeteer/replay targets recordings produced by Chrome DevTools Recorder. Its purpose is practical: take a Recorder user-flow file, validate and parse it, execute the recorded steps in a browser, or turn the flow into a string representation that another part of a test system can consume. The intended audience includes developers who capture browser interactions in Chrome and want a reusable artifact instead of maintaining a hand-written test script for every navigation and interaction.

The package is not a browser automation framework in the broad sense. It describes how to execute a specific recording format and exposes hooks around that execution. The README also frames transformations as a first-class use. A recording can be converted into a custom script rather than executed directly, which is relevant when a team runs tests through Cypress, Nightwatch, WebdriverIO, TestCafe, or another environment.

This distinction matters for adoption. If the deliverable is a reproducible test, Replay can sit between Chrome Recorder and an existing automation system. If the requirement is to discover selectors, authenticate to an application, or build a general-purpose browser driver, those jobs belong to the surrounding tooling rather than this package. The library supplies the recording lifecycle, while Puppeteer supplies the browser process when the API example uses it directly.

The repository identifies the implementation language as TypeScript, and the npm package publishes declarations through `lib/main.d.ts`. Its public surface includes parsing, runner creation, stringification, and extension classes. That makes it more than a command wrapper, although the CLI remains a convenient entry point for a single file or directory.

## The User Flow Parse, Runner, and Extension Pipeline

The basic API path has four concrete stages. First, application code reads the Recorder file as UTF-8 text. Second, `JSON.parse` converts that text into a JavaScript value. Third, `parse` validates and parses the value into the library's recording representation. Fourth, `createRunner` produces a runner for that recording, and `runner.run()` executes it.

The recorded flow passed to `createRunner` can be supplied directly as an object. In the customization example, the object contains a `title` and a `steps` array. A navigation step has a `type` of `navigate` and a `url`. This object-oriented entry point is useful for small programmatic flows and for tests that construct a flow in memory, while file-based replay uses the preceding text, JSON, and parse stages.

Execution customization happens through `PuppeteerRunnerExtension`. An extension receives the browser and page in its constructor and can override four lifecycle points: `beforeAllSteps`, `beforeEachStep`, `afterEachStep`, and `afterAllSteps`. Each override shown in the README calls its corresponding superclass method before adding application behavior. The superclass calls are significant because the example does not treat the hooks as replacements for the base runner. They are extension points around the normal replay lifecycle.

That mechanism supports logging, screenshots, or integration with third-party libraries, as stated by the README. It also makes side effects explicit. A developer can run code before and after every step, rather than editing the serialized recording itself. For a long flow, however, such hooks execute on every step and should account for the browser context they receive.

## Installing the Package and Replaying a Recording

The documented installation adds `@puppeteer/replay` as a saved npm dependency. Applications that want to replay recordings through Puppeteer should install `puppeteer` as well. The repository's `package.json` requires Node.js `>=22.12`, so that version constraint should be checked before installation rather than discovered during setup.

Install the replay library with:

```bash
npm install @puppeteer/replay --save
```

Install Puppeteer when using the Puppeteer-based API:

```bash
npm install puppeteer --save
```

Save a Chrome DevTools Recorder download as `recording.json`. The simplest first run uses the package's `npx` command, with the recording path as its argument:

```bash
npx @puppeteer/replay recording.json
```

The README documents a `package.json` script as the alternative when the package is installed locally:

```json
{
  "scripts": {
    "replay": "replay recording.json"
  }
}
```

A directory can be passed in place of a single file. The documentation says this runs every recording in that directory:

```bash
npx @puppeteer/replay all-recordings
```

Browser visibility is controlled by `PUPPETEER_HEADLESS` or the `--headless` CLI flag. According to the README, headless mode is the default. These documented invocations select true, false, or the experimental `chrome` value:

```bash
PUPPETEER_HEADLESS=true npx @puppeteer/replay recording.json
PUPPETEER_HEADLESS=false npx @puppeteer/replay recording.json
PUPPETEER_HEADLESS=chrome npx @puppeteer/replay recording.json
```

For a first programmatic run, the documented file API reads and parses `recording.json`, creates a runner, and executes it:

```js
import { createRunner, parse } from '@puppeteer/replay';
import fs from 'fs';

const recordingText = fs.readFileSync('./recording.json', 'utf8');
const recording = parse(JSON.parse(recordingText));
const runner = await createRunner(recording);
await runner.run();
```

The output visible from that example is the executed browser flow, not a console report. Errors during file access, JSON decoding, parsing, browser setup, or replay will surface at their respective code stages.

## Adding Step Hooks Around Puppeteer Replay

Runner customization uses a subclass rather than a callback array. This gives each extension a defined place for flow-level and step-level behavior. The following is the complete mechanism shown by the README's extension example: launch Puppeteer, create a page, subclass `PuppeteerRunnerExtension`, pass the extension to `createRunner`, run the flow, and close the browser.

```js
import { createRunner, PuppeteerRunnerExtension } from '@puppeteer/replay';
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: true,
});
const page = await browser.newPage();

class Extension extends PuppeteerRunnerExtension {
  async beforeAllSteps(flow) {
    await super.beforeAllSteps(flow);
    console.log('starting');
  }

  async beforeEachStep(step, flow) {
    await super.beforeEachStep(step, flow);
    console.log('before', step);
  }

  async afterEachStep(step, flow) {
    await super.afterEachStep(step, flow);
    console.log('after', step);
  }

  async afterAllSteps(flow) {
    await super.afterAllSteps(flow);
    console.log('done');
  }
}

const runner = await createRunner(
  {
    title: 'Test recording',
    steps: [
      {
        type: 'navigate',
        url: 'https://wikipedia.org',
      },
    ],
  },
  new Extension(browser, page, 7000)
);

await runner.run();
await browser.close();
```

The hooks provide visibility into execution order: `starting` runs once before the flow, `before` and `after` run around each step, and `done` runs after the flow. The extension receives `browser`, `page`, and `7000` when constructed. The README does not explain the final numeric argument in this excerpt, so its meaning should be checked in the API documentation before copying the pattern into unrelated code.

This design is a good fit for screenshot capture and third-party integration because those actions can be tied to lifecycle boundaries. It also creates a responsibility: extension code must preserve the expected lifecycle by calling `super`, and the application must close the browser it launched. The example performs that cleanup after `runner.run()`, but an unsuccessful run may require an application-level policy for cleanup if the surrounding code is expanded.

## Stringifying Recorder Flows into Executable Test Code

The `stringify` function handles the conversion side of the package. It accepts a recording object and returns its string representation. The minimal example contains a title and an empty `steps` array:

```js
import { stringify } from '@puppeteer/replay';

console.log(
  await stringify({
    title: 'Test recording',
    steps: [],
  })
);
```

The README names the default use as stringifying a recording as a Puppeteer script. For custom formats, `PuppeteerStringifyExtension` extends the same flow-level and step-level extension pattern. Its hooks accept a `LineWriter`, `UserFlow`, or `Step`, depending on the lifecycle point. The writer's `appendLine` method adds lines to the generated output.

This is a different extension boundary from runner hooks. `PuppeteerRunnerExtension` changes what happens during execution, while `PuppeteerStringifyExtension` changes what gets written into the transformed artifact. A tool that imports the generated script does not need the replay runner, which is why conversion can serve a separate test framework. Conversely, a direct replay does not require the generated source to be inspected or maintained.

The package's `files` list shows that the distributed npm content is built from `lib`, with `lib/main.d.ts` retained as the public type entry. The TypeScript implementation is therefore consumed as compiled JavaScript with declarations rather than as source directly from `src`. Users who need the exact generated format should inspect it for their flow because the repository examples demonstrate the extension mechanism but do not define an application-specific assertion strategy.

## Integration Choices, Constraints, and Release Maintenance

A real alternative is to convert the Recorder JSON into syntax for the test framework already used by a team. The README lists Cypress Chrome Recorder, Nightwatch Chrome Recorder, and WebdriverIO Chrome Recorder as transformations that produce framework-specific test scripts. This differs from running the recording with `@puppeteer/replay`: conversion moves the flow into another runner and syntax, whereas Replay's native path validates and runs the user flow itself. If an organization already standardizes on one of these frameworks, a converter may fit its reporting and execution model more closely than adding Replay as another execution layer.

Replay can also operate inside third-party environments. TestCafe is documented as a replay integration that can generate reports, while Sauce Labs uses `saucectl` for JSON flow replay. Those examples show that package selection is not only a choice between a local browser and a remote service. It also changes where the flow runs and which surrounding tool owns execution.

There are clear constraints. The package requires Node.js `>=22.12`. The README describes headful, headless, and experimental headless browser modes, but it does not document rollback, retry policy, artifact capture, parallel execution, or behavior for application-specific interaction failures. The API also relies on recorded steps matching the target application's current interface. A recording captured against one version of a site cannot be assumed to remain valid when routes, selectors, timing, or expected responses change.

The repository is not archived, and its last push was on 2026-10-11. Releases `v4.0.0`, `v4.0.1`, and `v4.0.2` were published on 2026-05-27, 2026-05-28, and 2026-05-28 respectively. The presence of a recent patch release does not remove the cost of reviewing major-version changes. Consumers must compare recorded-flow behavior and extension APIs when upgrading across `v4.0.0`.

The package declares the Apache-2.0 license. The repository includes a `LICENSE` file, which is the source to consult for its complete terms and notice requirements. This review does not interpret those terms or provide legal advice. The practical upgrade work is checking Node compatibility, running the existing recordings, reviewing generated scripts, and confirming that custom runner and stringifier extensions still behave as expected after a version change.

## Conclusion

Adopt @puppeteer/replay when your source of truth is a Chrome DevTools Recorder user flow and you need repeatable local execution, TypeScript integration, or code generation. Do not adopt it if you require a supported framework-native test format without an additional integration. Before committing, verify Node.js 22.12 or later is available, then replay the recording you intend to keep under version control and review the generated output for unsupported steps or application-specific assumptions.

## FAQ

### What is @puppeteer/replay used for?

It replays and stringifies recordings created by Chrome DevTools Recorder. The package also supports extensions for changing execution hooks or generated script output.

### How do I install @puppeteer/replay?

Run `npm install @puppeteer/replay --save`. Install `puppeteer --save` as well when using recordings through Puppeteer, and use Node.js 22.12 or later.

### Can @puppeteer/replay run all recordings in a folder?

Yes. The README documents passing a folder path to the CLI, such as `npx @puppeteer/replay all-recordings`, to run all recordings in that folder.

### Can I customize how a Chrome Recorder flow is replayed?

Yes. Extend `PuppeteerRunnerExtension` and override its lifecycle methods to add behavior before or after the flow and individual steps.

### Does @puppeteer/replay generate code for other test frameworks?

The package can stringify flows, while the README lists third-party integrations for Cypress, Nightwatch, WebdriverIO, TestCafe, and Sauce Labs. Those integrations differ from the package's direct Replay API.

## Sources

- [Issues](https://github.com/puppeteer/replay/issues)
- [License: Apache-2.0](https://github.com/puppeteer/replay/blob/main/LICENSE)
- [puppeteer/replay on GitHub](https://github.com/puppeteer/replay)
- [README](https://github.com/puppeteer/replay/blob/main/README.md)
- [Releases](https://github.com/puppeteer/replay/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/puppeteer-replay
