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

puppeteer-capture

v1.12.0

Published

A Puppeteer plugin for capturing page as a video with ultimate quality.

Readme

puppeteer-capture

GitHub Repo stars GitHub license node-current NPM Version GitHub Workflow Status Codecov Code Climate maintainability

A Puppeteer plugin for capturing page as a video with ultimate quality.

This project is brought to you by Alexey Pelykh.

Under The Hood

HeadlessExperimental is used to capture frames in a deterministic way. This approach allows to achieve better quality than using screencast.

Getting Started

const { capture, launch } = require('puppeteer-capture')

(async () => {
  const browser = await launch()
  const page = await browser.newPage()
  const recorder = await capture(page)
  await page.goto('https://google.com', {
    waitUntil: 'networkidle0',
  })
  await recorder.start('capture.mp4')
  await recorder.waitForTimeout(1000)
  await recorder.stop()
  await recorder.detach()
  await browser.close()
})()

Time flow

The browser is running in a deterministic mode, thus the time flow is not real time. To wait for a certain amount of time within the page's timeline, PuppeteerCapture.waitForTimeout() must be used:

await recorder.waitForTimeout(1000)

Known Issues

--headless=new is not supported

Sadly, it is so. For Puppeteer v23+, the plugin enforces use of the chrome-headless-shell binary.

Bad Chrome versions

  • 117.0.5938.88 (default for puppeteer version(s) 21.3.0 ): reacts with targetCrashed
  • 117.0.5938.92 (default for puppeteer version(s) 21.3.221.3.6): reacts with targetCrashed
  • 117.0.5938.149 (default for puppeteer version(s) 21.3.721.3.8): reacts with targetCrashed
  • 118.0.5993.70 (default for puppeteer version(s) 21.4.021.4.1): reacts with targetCrashed
  • 119.0.6045.105 (default for puppeteer version(s) 21.5.021.7.0): reacts with targetCrashed
  • 120.0.6099.109 (default for puppeteer version(s) 21.8.0): reacts with targetCrashed

MacOS is not supported

Unfortunately, it is so.

No capturing == Nothing happens

This relates to timers, animations, clicks, etc. To process interaction with the page, frame requests have to be submitted and thus capturing have to be active.

Setting defaultViewport causes rendering to freeze

The exact origin of the issue is not yet known, yet it's likely to be related to the deterministic mode.

Calling page.setViewport() before starting the capture behaves the same, yet calling it after starting the capture works yet not always. Thus it's safe to assume that there's some sort of race condition, since adding recorder.waitForTimeout(100) just before setting the viewport workarounds the issue.

Also it should be taken into account that since frame size is going to change over the time of the recording, frame size autodetection will fail. To workaround this issue, frame size have to be specified:

const recorder = await capture(page, {
  size: `${viewportWidth}x${viewportHeight}`,
})
await recorder.start('capture.mp4', { waitForFirstFrame: false })
await recorder.waitForTimeout(100)
await page.setViewport({
  width: viewportWidth,
  height: viewportHeight,
  deviceScaleFactor: 1.0,
})

A friendlier workaround is enabled by default: recorder.start() automatically waits for the first frame to be captured. This approach seems to allow bypassing the alleged race condition:

const recorder = await capture(page, {
  size: `${viewportWidth}x${viewportHeight}`,
})
await recorder.start('capture.mp4')
await page.setViewport({
  width: viewportWidth,
  height: viewportHeight,
  deviceScaleFactor: 1.0,
})

Multiple start()/stop() fail

It's unclear why, yet after disabling and re-enabling the capture, callbacks from browser stop arriving.

Time-related functions are affected

The following functions have to be overriden with injected versions:

  • setTimeout & clearTimeout
  • setInterval & clearInterval
  • requestAnimationFrame & cancelAnimationFrame
  • Date() & Date.now()
  • performance.now()

The injection should happen before page content loads:

const recorder = await capture(page) // Injection happens here during attach()
await page.goto('https://google.com') // Possible capture would happen here, thus injected versions would be captured

Events

PuppeteerCapture supports following events:

  • captureStarted: capture was successfully started
  • frameCaptured: frame was captured
  • frameCaptureFailed: frame capture failed
  • frameRecorded: frame has been submitted to ffmpeg
  • captureStopped: capture was stopped

Dependencies

ffmpeg

It is resolved in the following order:

  1. FFMPEG environment variable, should point to the executable
  2. The executable that's available via the PATH environment variable
  3. Via @ffmpeg-installer/ffmpeg, if it's installed as dependency