ScreenshotNeo

BlogHow-to

How to Record a Browser Screen with Puppeteer

Record browser activity as MP4 with Puppeteer’s experimental page.record() API. Learn setup, lifecycle, legacy options, troubleshooting, and when a screenshot is enough.

By the ScreenshotNeo team4 October 20267 min read

Use Puppeteer’s page.record() to record browser activity to an MP4 file. Create and navigate a page, start the recording, perform the interactions you want to capture, then call recorder.stop(). The method is marked experimental in Puppeteer’s Next API reference, so confirm that your installed Puppeteer version exposes it before building a workflow around it. See Page.record() and the Page API.

Record a page to MP4

Install Puppeteer in a Node.js project. Puppeteer’s getting-started guide covers installation and browser setup: Getting started.

npm install puppeteer

Save this as record.js. It records a page load and a short interaction. Replace the example URL and interaction with the page and actions you need to capture.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setViewport({ width: 1280, height: 720 });
    await page.goto('https://example.com', { waitUntil: 'networkidle2' });

    const recorder = await page.record({ path: 'recording.mp4' });
    await page.waitForTimeout(1000);
    // Replace this with the page actions to include in the recording.
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    await page.waitForTimeout(1000);
    await recorder.stop();
  } finally {
    await browser.close();
  }
})().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

The recording sequence follows Puppeteer’s documented page.record() example: launch, create and navigate a page, start recording, do work, stop the recorder, and close the browser. The API is experimental, and the example above is adapted from the reference rather than independently tested. Check your installed version’s API declarations and the version-specific RecordOptions reference for supported options.

Important lifecycle details

  1. Set the viewport and establish the page state before recording if those setup steps should not appear in the video.
  2. Start recording only after navigation or other prerequisites have completed.
  3. Await the actions you want recorded so they finish in a predictable order.
  4. Call await recorder.stop() explicitly. Do this in a cleanup path if later actions may throw.
  5. Close the browser after recording has stopped. The output path is relative to the process working directory unless you provide an absolute path.

For a longer-running script, track whether recording began and stop it in finally before closing the browser. This reduces the chance that an error during page interaction leaves the recording unfinished. Keep errors visible; do not treat a missing output file as a successful capture.

Recording API choices

API Use Output and requirements Status and caveats
page.record() New video-recording code MP4 video stream; can write to a path in the documented example Current Next reference recommends it; experimental, so verify installed-version support.
page.screencast() Maintaining older code that already uses it Documented default is WebM with VP9 at 30 FPS; requires ffmpeg Marked obsolete/deprecated. The reference says it works in Chrome 153 and later. Avoid choosing it for a new implementation when record() is available.
page.screenshot() Capturing one still image Image data such as PNG or JPEG Not a time-based video recording API.

These descriptions summarize Puppeteer’s Page API, screencast reference, and screenshot reference. The sources do not establish which video API is faster or produces better-looking output, so choose based on API status and the format and compatibility requirements documented for your version.

Recording output and stream handling

The ScreenRecording class extends ReadableStream<Uint8Array>, exposes pipe() for a destination stream, and provides stop() to end recording. For file output, use the path option shown in the page.record() example. For piping or other advanced handling, consult the RecordOptions and ScreenRecording references matching your installed Puppeteer version; do not assume option names or stream behavior from a different release.

Version and browser compatibility

Puppeteer releases are paired closely with browser releases because Puppeteer relies on browser protocols. Its FAQ explains that compatibility relationship. Since page.record() is experimental in the cited Next reference, verify both that your package version includes it and that its browser version supports the underlying operation.

  • Check the API documentation for the version you actually install, rather than relying solely on the Next reference.
  • Inspect your installed package’s TypeScript declarations or editor autocomplete for page.record and its accepted options.
  • Use the browser version installed or downloaded for that Puppeteer release unless you have verified a different pairing.
  • For reproducible recordings, pin Puppeteer in your project lockfile and keep the browser environment consistent across runs.

Waits, page state, and recording boundaries

A recording captures what the browser displays during its recording interval. Navigation completion does not necessarily mean that a page’s application data, animations, fonts, or delayed content have settled. Choose the start point deliberately.

  • Wait for navigation: use a suitable page.goto() wait condition for the site. networkidle2 is used in the example, but pages with persistent network activity may never become idle.
  • Wait for a specific state: prefer waiting for a selector or application condition when the page has a clear readiness signal.
  • Exclude setup: navigate, dismiss overlays, and establish the starting state before calling record() if those changes should not be in the clip.
  • Include loading: start earlier when the loading experience itself is what you need to document.
  • Control timing: use explicit waits for meaningful transitions; arbitrary delays can make automation slow and still fail to cover variable load times.

Troubleshooting

Symptom Likely cause What to check or change
page.record is not a function or a TypeScript error The installed Puppeteer release does not expose the experimental method, or the type definitions differ from the Next docs. Check the installed version’s Page API and declarations. Upgrade only after checking the matching browser support and API options.
No MP4 appears at the expected location The path is relative to another working directory, the recorder was not stopped, or an error interrupted the script. Use an absolute output path while diagnosing, await recorder.stop(), log the process working directory, and preserve the original exception.
The clip ends early or is incomplete The browser or process closed before recording finished, or stop/cleanup was skipped after an exception. Stop the recorder before closing the browser, and put recorder shutdown in structured cleanup logic.
The page is blank or shows an intermediate state Recording started before navigation or client-side rendering completed. Wait for a page-specific selector or state before starting the recording. If the loading state is intentional, start earlier by design.
networkidle2 times out The page keeps connections open or generates ongoing requests. Choose a different navigation condition and wait for the actual content or control needed for the recording.
Legacy screencast fails to start The Chrome version may not meet the documented Chrome 153+ requirement, or ffmpeg is unavailable. For existing screencast() code, verify the browser version and ffmpeg installation. For new work, check whether page.record() is available in the installed release.
Output differs between environments Browser versions, viewport, page data, timing, fonts, or animation state differ. Pin the Puppeteer/browser pairing, set the viewport, use deterministic page data where possible, and wait for explicit page conditions.

Performance, reliability, and cost

Video recording produces a time-based artifact, so the work lasts as long as the recorded interaction. Keep the recording interval limited to the sequence you need and avoid unnecessary browser sessions. The cited Puppeteer references do not publish performance benchmarks, recording size estimates, or a cost per capture; those depend on the page, browser environment, duration, and your compute and storage setup.

For reliability, use a pinned dependency and compatible browser, explicit readiness conditions, a known output path, and guaranteed recorder shutdown. Treat browser crashes, navigation failures, and missing output as failed jobs, and retain enough logs to identify the page, Puppeteer version, browser version, and failing stage. For production automation, clean up temporary video files according to your own retention needs.

When you need a screenshot instead of a video

If the deliverable is one still image of a page, use page.screenshot(); it returns image data and is separate from the video API. Puppeteer’s screenshot documentation describes screenshot options. For website captures without managing a browser session, ScreenshotNeo is a screenshot API and MCP server: one GET request can return a PNG, JPEG, WebP, or PDF. It does not replace Puppeteer video recording.

Or skip the browser setup

For a still screenshot of a page, ScreenshotNeo accepts one GET request. This does not record video; use Puppeteer above when you need a browser activity recording. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners, newsletter popups, and chat widgets are removed before the shot, and each step can be turned off.
  • Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing; responses identify page verdict and billing status in headers.
  • An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
  • The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo and get 1,000 free screenshots a month with no card.

FAQ

Does Puppeteer record browser audio with page.record()?

The cited API reference describes page video recording and does not establish audio capture. Check the version-specific documentation for any audio capability you require.

Can I use this to record a browser tab in a person’s desktop session?

The example records a Puppeteer-controlled page. It is browser automation, not a guide to capturing a user’s existing desktop browser session.

Is page.screenshot() suitable for a video?

No. It captures still image data. Use page.record() for a time-based recording where supported by your installed version.

Do I need ffmpeg for page.record()?

The cited reference lists ffmpeg as a requirement for the older page.screencast() method. Verify requirements for the exact API and Puppeteer version you use.