Playwright Screenshots and Video Recording: Complete Guide

Screenshots and videos turn a confusing test failure into an obvious one. In this lesson you will capture full-page and element screenshots, mask sensitive data, attach images to the HTML report, and configure automatic screenshots and videos for failed tests.

Advertisement

📖 What You’ll Learn: page and element screenshots, screenshot options (fullPage, clip, mask, animations), attaching images with testInfo.attach, automatic screenshots and videos in the config, video size, recording in plain scripts, and screenshots vs videos vs traces.


📸 Why Screenshots and Videos Matter

When a test fails in CI at 2 a.m., the error message alone rarely tells the whole story. A screenshot shows what the page looked like at the moment of failure, and a video shows every step leading up to it. Playwright can capture both automatically, with one line in the config.


🖼️ Take a Screenshot of the Page

import { test } from '@playwright/test';

test('capture the login page', async ({ page }) => {
  await page.goto('https://www.saucedemo.com/');

  await page.screenshot({ path: 'screenshots/login.png' });                  // visible area
  await page.screenshot({ path: 'screenshots/login-full.png', fullPage: true }); // whole scrollable page
});

The folder is created automatically. Paths are relative to where you run the command (usually the project root).

Useful screenshot options

OptionWhat it does
pathWhere to save the file (.png or .jpeg)
fullPage: trueCapture the entire scrollable page
type: 'jpeg' with quality: 80Smaller files
clip: { x, y, width, height }Capture only an area of the page
mask: [locator]Cover sensitive or changing elements with a box
animations: 'disabled'Stop CSS animations for a stable image
omitBackground: trueTransparent background (PNG only)
await page.screenshot({
  path: 'screenshots/masked.png',
  fullPage: true,
  mask: [page.locator('[data-test="username"]'), page.locator('[data-test="password"]')],
  animations: 'disabled',
});

🎯 Screenshot a Single Element

Call screenshot() on a locator to capture just that element:

test('capture the login form only', async ({ page }) => {
  await page.goto('https://www.saucedemo.com/');
  await page.locator('.login-box').screenshot({ path: 'screenshots/login-form.png' });
});

Element screenshots are ideal for bug reports and for visual regression tests of components.


📎 Attach Screenshots to the HTML Report

Saving files to a folder is fine locally, but in a team you want screenshots inside the report. Use testInfo.attach():

import { test, expect } from '@playwright/test';

test('cart badge after adding a product', async ({ page }, testInfo) => {
  await page.goto('https://www.saucedemo.com/');
  await page.getByPlaceholder('Username').fill('standard_user');
  await page.getByPlaceholder('Password').fill('secret_sauce');
  await page.getByRole('button', { name: 'Login' }).click();
  await page.locator('[data-test="add-to-cart-sauce-labs-backpack"]').click();

  const image = await page.screenshot();               // returns a Buffer when no path is given
  await testInfo.attach('cart-after-add', { body: image, contentType: 'image/png' });

  await expect(page.locator('.shopping_cart_badge')).toHaveText('1');
});

Open the HTML report (npx playwright show-report) and the image appears under Attachments for that test.


⚙️ Automatic Screenshots on Failure (Config)

You do not need to write screenshot code in every test. Set it once in playwright.config.ts:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    screenshot: 'only-on-failure', // 'off' | 'on' | 'only-on-failure'
  },
});
ValueBehaviourGood for
'off'No automatic screenshots (default)Fast local runs
'on'Screenshot after every testAudits, demos
'only-on-failure'Screenshot only when a test failsRecommended for most projects

Screenshots are saved in test-results/ and embedded in the HTML report.


🎬 Record Videos of Test Runs

Videos are also configured with one option:

use: {
  video: 'retain-on-failure', // 'off' | 'on' | 'retain-on-failure' | 'on-first-retry'
},
ValueBehaviour
'off'No video (default)
'on'Record every test
'retain-on-failure'Record every test, keep only failures
'on-first-retry'Record only when a failed test is retried

To control the resolution:

use: {
  video: { mode: 'retain-on-failure', size: { width: 1280, height: 720 } },
},

Videos are saved as .webm files in test-results/ and can be played directly in the HTML report.

📝 Note: A video is finished only when the browser context closes, which Playwright does at the end of each test. If you need the file path inside a test, use await page.video()?.path().

Recording video outside the test runner

When you use the Playwright library in a plain script, enable recording on the context:

import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext({ recordVideo: { dir: 'videos/' } });
  const page = await context.newPage();
  await page.goto('https://www.saucedemo.com/');
  await context.close(); // the video is written now
  await browser.close();
})();

🧭 Screenshots, Videos or Traces?

ArtifactShowsCost
ScreenshotOne moment, usually the failureVery small
VideoEvery step as a recordingLarger files, slight slowdown
TraceEvery action, DOM snapshot, network call and console log, step by stepMedium; the most useful for debugging

A balanced setup for most teams:

use: {
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
  trace: 'on-first-retry',
},

Traces are the most powerful debugging tool of the three. They get their own lesson, Trace Viewer step by step, in Module 11.


✅ Best Practices

  • Use 'only-on-failure' and 'retain-on-failure' to keep CI artifacts small.
  • Mask passwords, personal data and changing content (dates, ads) in screenshots.
  • Do not commit test-results/ or screenshot folders to Git; the default .gitignore already excludes them.
  • In CI, upload playwright-report/ as an artifact so the team can open screenshots and videos (covered in the GitHub Actions lesson).
  • Attach screenshots with testInfo.attach() when a step is important, so they appear in the report next to the test.

📝 Assignment

  1. Take a full-page screenshot of https://www.saucedemo.com and an element screenshot of the login form.
  2. Take a screenshot with the username and password fields masked, and compare it with an unmasked one.
  3. Log in, add two products, and attach a screenshot of the cart page to the HTML report with testInfo.attach().
  4. Configure screenshot: 'only-on-failure' and video: 'retain-on-failure'. Make one test fail on purpose and find both artifacts in the HTML report.
  5. Set the video size to 1280 x 720 and confirm the new resolution.
  6. Bonus: write a plain Node script (no test runner) that records a video of opening three different pages.

❓ FAQ

🤔 How do I take a screenshot in Playwright?

await page.screenshot({ path: 'file.png' }) for the page, add fullPage: true for the whole page, or call locator.screenshot() for one element.

🤔 How do I take a screenshot only when a test fails?

Set use: { screenshot: 'only-on-failure' } in playwright.config.ts. The screenshot is saved in test-results/ and shown in the HTML report.

🤔 How do I record a video in Playwright?

Set use: { video: 'on' } (or 'retain-on-failure') in the config. In a plain script, create the context with recordVideo: { dir: 'videos/' }.

🤔 Where are Playwright screenshots and videos saved?

Automatic ones go to the test-results/ folder (configurable with outputDir) and are linked in the HTML report. Manual screenshots go to the path you provide.

🤔 How do I hide sensitive data in a screenshot?

Pass locators to the mask option: page.screenshot({ mask: [page.locator('#password')] }).


🎯 Next Steps

🎬 Watch the full Playwright tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in

3 thoughts on “Playwright Screenshots and Video Recording: Complete Guide”

Leave a Comment