Puppeteer Screencast Options: Record Browser Activity
Record browser activity with Puppeteer’s recommended Page.record() API, understand the obsolete screencast options, and fix common recording problems.
Short answer: For new Puppeteer recordings, use the experimental page.record() API. It records an MP4 video stream and returns a ScreenRecording whose stop() method ends the recording. The familiar page.screencast() API is marked obsolete in Puppeteer’s Next reference; it has a separate ScreencastOptions interface, writes a file such as WebM, works in Chrome 153+, and requires ffmpeg. Do not apply its options to page.record(). Page.record() · Page.screencast()
1. Record browser activity with Page.record()
The following Node.js script navigates to a page, starts recording, performs browser actions, stops recording, and closes the browser. Install Puppeteer first with npm install puppeteer, save this as record.mjs, and run node record.mjs.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
// Page.record() produces an MP4 video stream.
const recording = await page.record({ path: 'activity.mp4' });
try {
await page.locator('a').first().click();
await page.waitForNavigation({ waitUntil: 'domcontentloaded' });
await page.waitForTimeout(1000);
} finally {
await recording.stop();
}
} finally {
await browser.close();
}
Page.record() is experimental in the cited Puppeteer Next documentation. Its reference says it uses Chrome DevTools Protocol’s Page.startScreenRecording and outputs an MP4 video stream. The signature accepts optional RecordOptions, but the documentation consulted here does not establish those fields; avoid copying ScreencastOptions into this call. Check the current Page.record() reference for the supported options in the Puppeteer version you install.
Set up a useful recording
- Choose the browser state first. Set the viewport, cookies, authentication, locale, or other page state before starting so the recording begins at the intended point.
- Navigate and wait for the relevant content. Use a meaningful navigation condition or wait for a selector.
networkidle2can be unsuitable for pages with long-lived requests; waiting for the specific interface element is often more reliable. - Start recording immediately before the actions you need. Setup and navigation generally do not belong in the video unless you want them documented.
- Stop in a
finallyblock. This lets Puppeteer finish the recording when an interaction throws, instead of leaving the recording lifecycle unfinished. - Close the browser after stopping. Await both calls so the process does not exit while the recording or browser is still shutting down.
The example uses path because it is a common output-oriented choice, but confirm the option against the installed version’s RecordOptions documentation. The reference describes a returned recording stream; if your integration needs to consume or pipe that stream rather than save a path, follow the version-specific ScreenRecording API. That reference is the right place to check stream consumption details.
2. Existing code: Page.screencast() and its options
page.screencast() is documented as obsolete, with an instruction to use Page.record() instead. It remains useful to understand when maintaining an existing implementation. The documented method returns a ScreenRecorder; start it, perform page actions, and await recorder.stop(). The legacy workflow needs Chrome 153+ and ffmpeg installed. Its defaults are WebM, VP9, and 30 FPS (20 FPS for GIF). See the official method documentation.
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const recorder = await page.screencast({ path: 'activity.webm' });
try {
await page.locator('a').first().click();
await page.waitForTimeout(1000);
} finally {
await recorder.stop();
}
} finally {
await browser.close();
}
Install ffmpeg using the package manager for your operating system and make sure its executable is available on PATH. If it is installed elsewhere, set the legacy ffmpegPath option to the executable path. The installed Chrome must also meet the documented Chrome 153+ requirement.
ScreencastOptions reference
These options belong to page.screencast() only. Defaults and descriptions below follow Puppeteer’s ScreencastOptions reference.
| Option | What it controls | Documented default or constraint |
|---|---|---|
path |
Output file path; the extension should match the selected format. | None specified |
format |
Output file format. | webm |
fps |
Frames per second. | 30; 20 for GIF |
quality |
Constant Rate Factor (CRF); lower values mean better quality. | 30; documented range 0–63 |
crop |
Region of the viewport to capture. | No default listed |
scale |
Multiplier for output width and height. | 1; for example, 0.5 halves both dimensions |
speed |
Recording playback speed multiplier. | 1; 0.5 slows by 50%, 2 doubles speed |
colors |
Maximum palette colors, useful for reducing file size through quantization. | 256; GIF is limited to 256 |
delay |
Delay between loop iterations, in milliseconds. | -1 reuses previous delay |
loop |
Number of playback loops. | Undefined; zero or undefined disables looping, range 0 to Infinity |
overwrite |
Whether an existing output file is replaced. | true |
ffmpegPath |
Path to the ffmpeg executable. | ffmpeg; change it if ffmpeg is not on PATH |
Example using a few legacy options together:
const recorder = await page.screencast({
path: 'checkout-demo.webm',
format: 'webm',
fps: 24,
quality: 24,
scale: 0.75,
speed: 1,
overwrite: true,
ffmpegPath: '/usr/bin/ffmpeg',
});
try {
await page.locator('[data-testid="checkout"]').click();
await page.waitForTimeout(1500);
} finally {
await recorder.stop();
}
Use a quality value within the documented 0–63 range; smaller CRF values preserve more quality and usually increase output size. Keep the output extension aligned with format. A crop is a viewport region, so make sure the page viewport and target coordinates match the intended framing. The option table is not a list of Page.record() settings.
3. Choose video, a still screenshot, or a screenshot API
| Need | Use | What you get |
|---|---|---|
| Document a sequence of interactions as video | Page.record() for new Puppeteer code |
MP4 video stream; experimental API |
| Maintain an existing WebM/GIF/ffmpeg workflow | Page.screencast() |
File-oriented recorder with documented ScreencastOptions; obsolete API |
| Capture one frame or a page image | Page.screenshot() |
Still image, not a video; use its separate ScreenshotOptions |
| Capture a website without managing a local browser | ScreenshotNeo | Website screenshot API and MCP server; a GET request can return PNG, JPEG, WebP, or PDF |
For one still image with Puppeteer, the basic call is:
const image = await page.screenshot({ path: 'page.png', fullPage: true });
The screenshot API’s options are different from both recording interfaces. Use the ScreenshotOptions reference for image settings such as full-page capture and format.
4. Troubleshoot Puppeteer recordings
| Symptom | Likely cause | Fix |
|---|---|---|
page.screencast is not a function |
The installed Puppeteer version or its types do not expose that method, or the code is using an unsupported version. | Check the installed version’s API reference. For new work, use page.record() when available; do not assume the Next reference describes every released version. |
| Recording reports ffmpeg missing or cannot spawn it | Legacy screencast cannot find the ffmpeg executable. | Install ffmpeg, put it on PATH, or set ffmpegPath to its executable. This prerequisite is documented for Page.screencast(). |
| Legacy screencast is unsupported by the browser | The reference requires Chrome 153 or later for Page.screencast(). |
Use a compatible Chrome build, or use Page.record() if supported by the installed Puppeteer/browser combination. |
| Output is missing or truncated | The recorder was not stopped and awaited, or the browser was closed too early. | Await recording.stop() or recorder.stop() before closing the browser. Put stop and close in nested finally blocks. |
| Video captures the wrong part of the flow | Recording began before setup finished, or the interaction started before the page reached the intended state. | Navigate and wait for the target UI first, then start the recorder immediately before the actions to retain. |
| Navigation wait times out after a click | The click may update a single-page app without a full navigation, or it may not trigger a navigation at all. | Wait for the result selector or an application-specific state instead of waitForNavigation(). |
| Video is too large or hard to review | Long capture duration, large viewport, or high frame rate can produce a larger recording. | Record only the necessary actions. For the legacy API, lower fps, use scale, or tune quality; verify visual readability after changing settings. |
| Legacy output does not match the extension or expected format | format and path use inconsistent values. |
Match the path extension to the chosen format, such as activity.webm with format: 'webm'. |
5. Performance, reliability, and cost
Recording adds work to a browser session and produces data proportional to the activity captured. Keep videos short, choose only the viewport you need, and use a lower frame rate or scaled dimensions when maintaining a legacy screencast. Lower legacy CRF means better quality, so it can work against file-size reduction. Measure output size and legibility for your own pages; the references provide option behavior, not universal performance benchmarks.
For repeatable recordings, pin the Puppeteer and browser versions, wait for the actual content you need, and use deterministic test data where possible. Always stop the recording before browser teardown, including on errors. Treat Page.record() as experimental and review its current reference when upgrading. For legacy recordings, provision ffmpeg and Chrome 153+ as runtime dependencies.
Puppeteer recordings have no per-capture API fee described in these references; your costs are the compute, storage, and operational work of running the browser and retaining files. ScreenshotNeo is a paid screenshot service with a free monthly tier; it bills only clean shots, and its response includes X-Page-Verdict and X-Billed headers to indicate the result and billing status. Use it for still captures, PDFs, or agent-driven screenshot workflows, not as a substitute for recording an interaction video.
6. Or skip the browser setup
If the task is a website screenshot rather than an interaction video, ScreenshotNeo provides a screenshot API and MCP server. Its API documentation covers request options.
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 are accepted and removed before the shot; more than 60 known consent platforms, newsletter popups, and chat widgets can be removed, and each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses include
X-Page-VerdictandX-Billed. - An MCP server lets AI agents, including Claude and Cursor, call
take_screenshot,get_page_info, andcapture_pdf. - The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Every feature is available on every plan.
Sign up for ScreenshotNeo and get 1,000 free screenshots a month, with no card.
7. FAQ
Does Puppeteer record mouse clicks and keystrokes?
The APIs record the page while your automation performs actions. Include the interactions you want in the recording window; stop it when the sequence is complete.
Can I use the legacy options with Page.record()?
No such compatibility is established by the cited references. ScreencastOptions is documented for Page.screencast(); consult the version-specific RecordOptions reference for Page.record().
Can ScreenshotNeo record a browser session as MP4?
No. ScreenshotNeo is a website screenshot API and MCP server that returns still images or PDFs. Use Puppeteer’s recording APIs when you need video.
When should I use a screenshot instead of a recording?
Use a screenshot when one visual state answers the question. Use a recording when the sequence and transitions between states matter.


