ScreenshotNeo

BlogHow-to

How to Take a Screenshot in Playwright Using TypeScript

Capture viewport, full-page, and element screenshots in Playwright with TypeScript, then make visual tests stable and repeatable.

By the ScreenshotNeo team1 October 20264 min read

Use Playwright’s page.screenshot() method. Navigate to a page, call await page.screenshot({ path: 'screenshot.png' }), and close the browser. The file extension selects PNG, JPEG, or WebP output.

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();

If you omit path, the call returns image bytes. Relative paths are resolved from the current working directory.

1. Set up a TypeScript screenshot script

  1. Install Playwright with npm install playwright.
  2. Save the script as screenshot.ts.
  3. Run it with your TypeScript workflow.
import { chromium } from 'playwright';

async function main() {
  const browser = await chromium.launch();
  try {
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({ path: 'artifacts/example.png' });
  } finally {
    await browser.close();
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

2. Choose what to capture

Viewport screenshot

page.screenshot() captures the current viewport by default.

await page.screenshot({ path: 'viewport.png' });

Full-page screenshot

Set fullPage: true to capture the entire scrollable page.

await page.screenshot({ path: 'full-page.png', fullPage: true });

One element

Use a Locator’s screenshot method to capture one element.

await page.locator('.header').screenshot({ path: 'header.png' });

Rectangular clipping

Use clip for a rectangle in page coordinates.

await page.screenshot({ path: 'crop.png', clip: { x: 0, y: 0, width: 800, height: 400 } });

3. Control output format and pixels

Option What it does Example
path Writes a file; the extension determines the type. path: 'shot.webp'
type Chooses png, jpeg, or webp. type: 'jpeg'
quality Controls JPEG/WebP quality. quality: 80
scale 'css' uses CSS pixels; 'device' uses device pixels. scale: 'css'
omitBackground Hides the default white background for transparency; not for JPEG. omitBackground: true
await page.screenshot({ path: 'card.webp', type: 'webp', quality: 82, scale: 'css' });
await page.screenshot({ path: 'transparent.png', omitBackground: true });

4. Make screenshots stable

Use animations: 'disabled' to stop CSS animations, CSS transitions, and Web Animations during capture. Finite animations are fast-forwarded and infinite animations are canceled.

await page.screenshot({ path: 'stable.png', animations: 'disabled' });

Mask dynamic regions with locators. The default mask color is pink #FF00FF; use maskColor to change it.

await page.screenshot({
  path: 'stable-dashboard.png',
  animations: 'disabled',
  mask: [page.locator('[data-testid="clock"]'), page.locator('.avatar')],
  maskColor: '#808080',
});

Use scale: 'css' for consistent baseline dimensions. Use 'device' when you intentionally need high-DPI output.

5. Use Playwright Test for visual regression

Playwright Test provides screenshot assertions. They only work with the Playwright test runner.

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

test('homepage matches the baseline', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveScreenshot('homepage.png');
});

The assertion takes two consecutive screenshots and waits for them to match before comparing. It supports fullPage, mask, animation control, thresholds, and maximum diff pixels.

await expect(page).toHaveScreenshot('dashboard.png', {
  fullPage: true,
  animations: 'disabled',
  mask: [page.locator('.live-value')],
  maxDiffPixels: 50,
});

Keep viewport, scale, fonts, and data state consistent when creating and checking baselines. Mask only intentionally variable regions.

6. A reusable capture function

import { chromium, type Page, type ScreenshotOptions } from 'playwright';

export async function capture(url: string, options: ScreenshotOptions = {}): Promise<Buffer> {
  const browser = await chromium.launch();
  try {
    const page: Page = await browser.newPage();
    await page.goto(url);
    return await page.screenshot(options);
  } finally {
    await browser.close();
  }
}

const bytes = await capture('https://example.com', { fullPage: true, type: 'png' });
console.log(`captured ${bytes.length} bytes`);

7. Troubleshooting

Symptom Cause Fix
Only the visible area appears Viewport capture is the default. Set fullPage: true.
File is missing The call was not awaited or the directory does not exist. Await capture and create the directory first.
Output is too large Device scale, full-page capture, or PNG. Use CSS scale, a smaller scope, or JPEG/WebP.
Transparency is white JPEG cannot represent transparency. Use PNG or WebP with omitBackground: true.
Visual diffs vary Animations or live regions change pixels. Disable animations and mask dynamic locators.
Locator capture fails The selector does not resolve as expected. Check the selector and page state.
Assertion API unavailable toHaveScreenshot requires Playwright Test. Run with @playwright/test.

8. Performance, reliability, and cost

  • Viewport captures are smaller; full-page and device-scale captures use more memory.
  • PNG is lossless; JPEG and WebP reduce size with compression.
  • Always await navigation and capture, and close the browser in cleanup code.
  • Keep capture options and page state deterministic for reliable baselines.
  • Playwright is self-hosted; your cost comes from the machines and runtime you provide.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. It removes cookie and consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses identify the result with X-Page-Verdict and X-Billed headers. MCP tools include take_screenshot, get_page_info, and capture_pdf.

See the ScreenshotNeo API documentation for all 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}`);

1,000 screenshots a month are free with no card. Paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

10. FAQ

Does Playwright save a screenshot automatically?

Only when you provide path. Without it, image bytes are returned.

How do I capture one component?

Call screenshot on a Locator.

Should visual tests use PNG?

PNG is lossless; JPEG and WebP are alternatives when smaller compressed files are preferred.

Why do screenshots differ on CI?

Different fonts, viewport or device scale, animations, and live data can change pixels. Standardize those inputs and mask intentional dynamic regions.