ScreenshotNeo

BlogHow-to

How to Record Puppeteer Browser Sessions

Record a Puppeteer-controlled page as an MP4 with Page.record(). Learn the correct lifecycle, version caveats, alternatives, and fixes for common failures.

By the ScreenshotNeo team4 October 20269 min read

Use Puppeteer’s page.record() method to record a page as an MP4 video. Navigate to the page, start recording, perform the browser actions you want to show, then call recorder.stop() before closing the browser. The API is currently marked experimental, so check that your installed Puppeteer version and browser support it. Puppeteer documents Page.record() as an MP4 recording API.

1. Record a Puppeteer page as MP4

The following ES module script launches Puppeteer, navigates to a page, records an interaction, and saves recording.mp4 in the current directory. Install Puppeteer with npm install puppeteer, save this as record.mjs, and run node record.mjs.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
let recorder;

try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 800 });
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });

  // Start recording after the page is in the state you want to show.
  recorder = await page.record({ path: 'recording.mp4' });

  // Perform the actions that should appear in the video.
  await page.mouse.move(400, 300);
  await page.waitForTimeout(1000);
  await page.mouse.click(400, 300);
  await page.waitForTimeout(1500);

  await recorder.stop();
  recorder = undefined;
} finally {
  // Finish the recording before closing its page/browser.
  if (recorder) {
    await recorder.stop();
  }
  await browser.close();
}

Page.record() returns a recording object with a stop() method. Call it after the interaction sequence; closing the browser first can interrupt the recording. The official example follows the same start, work, stop, close order. The try/finally cleanup above is application guidance based on that lifecycle.

Choose when recording begins

In this example, navigation finishes before recording begins, so the video focuses on the interaction. To include the navigation itself, start recording before page.goto():

const page = await browser.newPage();
const recorder = await page.record({ path: 'navigation-and-actions.mp4' });

try {
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  await page.waitForTimeout(1000);
  // Continue with interactions.
} finally {
  await recorder.stop();
}

Start recording after setup when you want a shorter clip without browser startup or page loading. Start before navigation when the loading sequence is part of the demonstration. In either case, stop only after the final state has had time to render.

2. Check version and browser support

Page.record() is experimental in the current Puppeteer API reference. Experimental APIs can change, and their availability depends on the Puppeteer version and its browser/protocol environment. Puppeteer’s current reference lists it on the Page class; the method documentation describes its use of Chrome DevTools Protocol’s Page.startScreenRecording API.

  1. Check the version installed in this project with npm ls puppeteer or npm ls puppeteer-core.
  2. Consult the API reference corresponding to that version. Do not assume the online “next” reference matches the version in your lockfile.
  3. Use the browser bundled with your Puppeteer installation unless your setup has a specific reason to use a separate executable.
  4. Run a short recording locally and in the target runtime. A browser or protocol mismatch may appear only in the deployment environment.

If page.record is missing, the installed Puppeteer package may predate the method. Upgrade to a version whose API reference includes it, then confirm the bundled or configured browser works with that version. Avoid upgrading production dependencies without first checking your project’s compatibility requirements.

3. Configure the recording workflow

The documented API accepts an optional options object and returns a ScreenRecording. The official example uses { path: 'recording.mp4' } to write the MP4 file. The recording object is a readable stream with a stop() method; obtain it from page.record() rather than constructing it yourself. See the method reference and ScreenRecording reference.

Need What to do
Choose the content shown Perform only the actions you want recorded between page.record() and stop().
Set a predictable viewport Call page.setViewport({ width, height }) before recording so the page layout has the intended dimensions.
Wait for a specific state Use page.waitForSelector() or an application-specific readiness condition before starting, or during the recorded sequence if that wait should be visible.
Include navigation Start recording before page.goto(). Wait for the chosen navigation condition, then perform the remaining actions.
Write to another location Pass a writable path in the documented path option and ensure the process can write to its directory.
Stop cleanly on errors Keep the recording reference and call stop() in cleanup before closing the browser.

Use waits that match the site rather than adding long fixed delays everywhere. For example, wait for a result panel to appear after submitting a form. Add a brief delay only when you need the recording to show a transition or leave a readable final state on screen.

4. Pick the right capture type

A browser recording, screenshot, and trace produce different artifacts. Select by what you need to inspect or share.

Output Puppeteer API Use it for
MP4 video page.record() A visual replay of page activity or a product flow.
Still image page.screenshot() A single viewport or full-page image at a particular state.
Diagnostic trace page.tracing.start() and page.tracing.stop() Timeline and performance investigation in Chrome DevTools or a timeline viewer.

Puppeteer’s screenshot guide covers still images. Its tracing reference describes trace files for Chrome DevTools or a timeline viewer; a trace is diagnostic timeline data, not an MP4 session video.

Capture a still screenshot instead

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

fullPage: true captures the full page rather than only the viewport. Other screenshot options include output type, quality for JPEG or WebP, clipping, and a transparent background; see the ScreenshotOptions reference.

Capture a diagnostic trace instead

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.tracing.start({ path: 'trace.json', screenshots: true });
  await page.goto('https://example.com', { waitUntil: 'load' });
  await page.tracing.stop();
} finally {
  await browser.close();
}

Tracing options include a destination path, categories, a buffer size, and whether screenshots should be included. Only one trace can be active per browser. A trace can help diagnose timing, but it is not the visual session video produced by page.record(). See TracingOptions and Tracing.start().

5. Legacy guidance: Page.screencast()

Older examples may use page.screencast(). The current “next” Page reference marks that API deprecated and directs users to Page.record(). Its documentation describes the older flow as WebM using VP9 by default at 30 FPS and notes that ffmpeg must be installed. Treat those details as migration context for older code, not as options for page.record(). Check the API reference for the Puppeteer version you run before changing an existing implementation. See the Page API reference.

6. Troubleshoot common recording failures

Symptom Likely cause Fix
page.record is not a function The installed Puppeteer version does not expose the experimental method. Check the installed version and its matching API reference. Upgrade to a compatible version if appropriate, then use its supported browser.
Recording command fails or is unsupported The browser executable or DevTools Protocol does not support the recording method expected by this Puppeteer version. Use the browser bundled with Puppeteer, confirm the exact Puppeteer/browser pair, and check the current method reference. Avoid assuming a system-installed browser matches Puppeteer’s expected protocol.
MP4 file is missing The process cannot write to the path, the path is relative to a different working directory, or the recording was not stopped before shutdown. Use an absolute or known writable path, create the destination directory, and await recorder.stop() before closing the browser.
File exists but is empty or incomplete The process closed the browser before the recording finalized, or an error path skipped stop(). Await stop() in the normal and cleanup paths. Do not terminate the process immediately after requesting a stop.
Video starts on the wrong page state Recording began before navigation or the relevant UI had settled. Move page.record() after navigation and a readiness check, or deliberately start before navigation if the load belongs in the clip.
Important animation or content is absent The script stopped too soon, waited for the wrong readiness event, or the content is controlled by a timer or delayed request. Wait for the actual selector, response, or state transition your page requires. Add a short, intentional display delay before stopping if the final state needs to remain visible.
Recording works locally but not in deployment The deployment uses a different Puppeteer version, browser binary, operating system, or filesystem permissions. Pin and inspect dependencies, verify the browser executable and writable output location, and reproduce using the same runtime configuration.
Old screencast() example fails due to ffmpeg The legacy recording flow may require ffmpeg. For new work, consult the current reference and use page.record() where supported. If maintaining the deprecated flow, install and configure its stated dependency.

7. Reliability, runtime, and file handling

  • Keep the recording window focused. Start and stop around the actions needed for the clip. Longer recordings create more output data and take longer to finalize and move.
  • Use explicit readiness conditions. A navigation event alone may not mean a client-rendered page or delayed widget is ready. Wait for the content your scenario needs.
  • Always clean up. Await recording stop before browser close, including when an interaction throws. Close the browser in a finally block so failures do not leave browser processes behind.
  • Plan storage and permissions. Ensure the output directory exists, is writable, and has enough space for the recording. Treat videos as potentially sensitive: they can show account data, URLs, and page content.
  • Validate the resulting artifact. Check that the file exists, has nonzero size, and plays in the intended video player before attaching it to a bug report or publishing it.
  • Budget for browser work. Runtime includes browser launch, page loading, scripted waits, and recording finalization. Keep concurrent browser jobs within the CPU and memory capacity of the host; Puppeteer documentation provides no universal recording speed or file-size benchmark.

8. Or skip the browser setup

If you need a website screenshot rather than an MP4 recording, ScreenshotNeo returns a screenshot or PDF from one API request. It does not record a Puppeteer session or produce a video. For a static capture, use its API instead of launching and maintaining your own browser:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Python equivalent:

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js equivalent:

const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

In Node.js environments without Bun, save the response using your preferred file-writing method; the API request itself uses the standard fetch API.

ScreenshotNeo accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 screenshots.

Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.

9. Frequently asked questions

Does Page.record() capture the whole browser window?

The documented method records the page using Chrome DevTools Protocol’s page recording API. For browser chrome or desktop-wide recording, this Puppeteer page API is not documented as a full-desktop recorder.

Can I use Page.record() for a still screenshot?

Use page.screenshot() for a still image. A recording is useful when the order and timing of page actions matter.

Is Page.record() stable for production?

Puppeteer labels the API experimental. Confirm its availability and behavior against your pinned Puppeteer version and browser environment, and keep a fallback that matches your required output.

Should I use a trace to record a user flow?

Use a trace when you need diagnostic timeline data. Use page.record() when you need a video replay; the two files serve different purposes.

Does ScreenshotNeo replace Puppeteer video recording?

No. ScreenshotNeo captures a website as an image or PDF. Use Puppeteer Page.record() when the deliverable must be a video of browser actions.