Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Playwright records browser video in two ways: configure the Playwright Test runner with use.video, or enable recordVideo on a browser context when using the library directly. In both cases, wait for the browser context to close before treating the file as complete. Use the test-runner modes for automatic retention (all tests, failures only, or first retries); use the library API or Screencast API when your script needs destination or start/stop control.

Choose the recording method

Use case API When the file is finalized Retention control
Playwright Test debugging use.video in playwright.config.ts At the end of the test, when its browser context closes off, on, retain-on-failure, or on-first-retry
Standalone Playwright script recordVideo in browser.newContext() When you close the recording context Your script decides which files to keep
Explicit start and stop page.screencast.start() and stop() When stop() completes Controlled around a particular interaction

The official references are the Playwright video guide, Browser API, Video API, and Screencast API.

Record videos in Playwright Test

Configure recording in playwright.config.ts

Video is off by default. Add a use.video setting to your Playwright Test configuration:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    video: 'on-first-retry',
  },
});

This records a test when it is retried and keeps the video from the first retry. The output is written under the test output directory, typically test-results. The recording is saved as the test’s browser context closes.

Pick the retention mode

  • off: no videos (the default).
  • on: record every test, useful when you need a complete visual archive but produces the most artifacts.
  • retain-on-failure: record tests and remove videos for successful tests, keeping failures for diagnosis.
  • on-first-retry: record only the first retry, which limits storage while preserving a reproduction attempt.

Choose the mode according to retention rather than image quality: all four modes use the same browser recording mechanism. For CI, failure-only or first-retry recording usually keeps artifact volume manageable; for investigating a flaky flow, first-retry captures the run where the failure is being reproduced.

Find the resulting file

After a run, inspect the configured test output directory (normally test-results) and the test’s artifact folder. A video is not guaranteed to exist for a successful test when you selected retain-on-failure or on-first-retry; that is expected retention behavior, not a capture error.

Record a video with the Playwright library

Minimal runnable JavaScript example

Set recordVideo.dir when creating a browser context. Perform all interactions, then close that context:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { chromium } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext({
  recordVideo: { dir: 'videos/' },
});
const page = await context.newPage();

await page.goto('https://example.com');
await page.getByRole('heading').waitFor();
// Perform the browser actions you want to capture.

await context.close(); // finalizes the recording
await browser.close();

The directory is created or used as the destination for the recording. Closing only the page is not the normal save boundary for context recording; close the context and await the promise before uploading, renaming, or inspecting the file.

Set the output dimensions

const context = await browser.newContext({
  viewport: { width: 1280, height: 800 },
  recordVideo: {
    dir: 'videos/',
    size: { width: 1280, height: 800 },
  },
});

recordVideo.size sets the video frame dimensions. If you omit dimensions, Playwright scales the viewport to fit 800×800. If you also omit an explicit viewport, the documented default viewport is 800×450. Set both values when a downstream editor, review system, or regression comparison requires a predictable 16:10, 16:9, or other size. The recording dimensions and the browser viewport serve different purposes: the viewport controls layout, while size controls the encoded frame.

Capture a scenario reliably

  1. Create one context with recordVideo enabled.
  2. Create pages from that context; pages associated with recording expose a video object.
  3. Navigate and wait for the state you want visible in the artifact (for example, wait for a selector rather than relying on a fixed sleep).
  4. Perform the interaction sequence.
  5. Await context.close() before checking that the file exists.

Get, save, or delete a recording

Use the page’s Video object

const video = page.video();

await context.close();
const path = await video.path();
console.log(`Saved to ${path}`);

video.path() returns the output path after the context closes. It throws when the browser is connected remotely, so do not build a remote execution workflow that depends on a local path being available.

Copy the artifact with saveAs

const video = page.video();
await video.saveAs('artifacts/login-flow.webm');

saveAs(path) can be called while recording is in progress or after the page closes. It waits for the page to close and for the video to be fully saved, making it suitable when you need a known artifact name. To remove an unwanted recording, call await video.delete() after the recording has been finalized.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Control exactly when recording starts and stops

Context recording runs for the context lifetime. If you need to capture only one portion of a longer script, use the Screencast API:

await page.screencast.start({
  path: 'video.webm',
  size: { width: 1280, height: 800 },
});

await page.goto('https://example.com');
// Interactions to include in the clip.

await page.screencast.stop();

start accepts a destination path and optional dimensions; stop saves the recording to that path. This is the direct start/stop choice when a context-wide recording would include setup or teardown that you do not want in the final clip.

Dimensions, timing, and artifact management

Make the frame match the intended layout

  • Set an explicit viewport for deterministic responsive behavior.
  • Set matching recordVideo.size (or Screencast size) when consumers expect fixed dimensions.
  • Use the default only when the 800×800 scaling behavior, or the 800×450 default viewport, is acceptable.

Wait for meaningful visual states

Video captures what the browser displays, not what your test intended to display. Wait for a selector, navigation state, or application-ready condition before the interaction you want reviewers to see. Avoid making a fixed delay the only synchronization mechanism; network and rendering time vary between runs.

Close in a predictable order

For normal context recording, await context.close() first, then read or upload the file, and finally close the browser. If your script has multiple contexts, close each recording context and retain its corresponding Video object so artifacts are not mixed up.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Troubleshooting

No video appears

  • Test runner: verify that use.video is not off and that your selected retention mode would keep this test. A passing test with retain-on-failure is intentionally deleted.
  • Library script: verify that the context, rather than the browser, was created with recordVideo.
  • Premature inspection: await context.close() before checking the directory or calling video.path().

The file is incomplete or cannot be opened

Ensure the close or stop promise is awaited. Do not terminate the process immediately after an interaction; finalization occurs at context close for recordVideo, and at screencast.stop() for Screencast.

video.path() fails in CI

The Video API documents that path() throws for remotely connected browsers. Use video.saveAs() where supported, or collect artifacts through the remote runner’s own storage mechanism instead of assuming a local filesystem path.

The video has the wrong size

Set both viewport and the recording size. Omitting size invokes Playwright’s scaling rule, while omitting viewport invokes the documented 800×450 default viewport.

The clip includes unwanted setup

Use Screencast start/stop around the exact interaction, or create a fresh recording context immediately before the scenario. Test-runner video modes are designed for test artifacts, not arbitrary clip boundaries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need a still screenshot of a page rather than a time-based browser video, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one GET request. It is not a replacement for Playwright video recording, but it avoids maintaining a browser capture script for static artifacts.

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 documentation for options. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed as clean shots, and response headers report the page verdict and billing status. ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Sign up for the free plan.

FAQ

Is Playwright video recording enabled automatically?

No. Playwright Test defaults to video: 'off'; standalone scripts must explicitly set recordVideo on the context.

Can I choose MP4 instead of the default recording format?

The documented APIs in this workflow specify destination, dimensions, and lifecycle, but do not state an MP4 output option. Plan your post-processing around the format produced by your installed Playwright/browser setup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I use context recording or Screencast?

Use context recording for whole-test artifacts and Screencast when you need an explicit start and stop around a smaller segment.

Frequently Asked Questions

Does closing a page finalize a Playwright video?

Normal recordVideo recordings are finalized when the browser context closes; await browserContext.close() before relying on the file.

Can I access a video path with a remote browser?

video.path() throws when connected remotely. Use an available artifact-transfer mechanism or saveAs() where supported.

How do I keep videos only for failed tests?

Set use.video to 'retain-on-failure' in playwright.config.ts.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.