ScreenshotNeo

BlogComparisons

Playwright Screenshot vs Selenium Screenshot for Visual Testing

Compare Playwright and Selenium screenshot capture for visual testing, with runnable examples, baseline workflows, stability guidance, and a clear tool choice.

By the ScreenshotNeo team4 October 20269 min read

Both Playwright and Selenium can capture browser screenshots. For visual regression testing, Playwright Test has a documented built-in baseline assertion: expect(page).toHaveScreenshot() creates a reference image on the first run and compares later captures against it. Selenium provides driver and element screenshot capture; the Selenium documentation reviewed here does not describe an equivalent built-in baseline assertion. With Selenium, choose and maintain the image comparison and baseline workflow separately.

The key distinction is capture versus comparison. A screenshot is only the image input. Visual testing also needs a reference image, comparison rules, a review process for differences, and a controlled environment. Use Playwright when its integrated assertion fits your test runner; an existing Selenium suite can do visual testing too, with those additional pieces supplied by your chosen tooling.

1. What each tool gives you

Workflow Playwright Selenium
Capture Page, full-page, and locator or element screenshots; screenshot bytes can be returned for processing. Driver and element screenshots are available in the documented language bindings. WebDriver returns screenshot data encoded as Base64.
Baseline comparison Playwright Test provides toHaveScreenshot(). The first run creates a baseline; subsequent runs compare with it. The reviewed Selenium capture documentation describes screenshots, not a first-party baseline assertion equivalent. Add a comparator and baseline process.
Stability behavior The assertion waits for two consecutive screenshots to match before comparing. Options include masking volatile areas and applying a stylesheet. Stability and comparison policy depend on the test setup and chosen comparison layer.
Baseline ownership Review and commit expected images with test assets; keep their generation and comparison environment consistent. Decide where images live, how differences are reviewed, and how approved changes update the baseline.

These are workflow differences, not a claim that Selenium cannot support visual testing. Selenium can capture the image; your suite or an added visual comparison tool can provide the remaining workflow.

2. Playwright: capture and compare with a baseline

Install Playwright Test and its browser binaries in your project according to the official installation guide. The following is a minimal JavaScript test. Save it as tests/home.visual.spec.js in a project configured for Playwright Test:

const { test, expect } = require('@playwright/test');

test('home page matches its visual baseline', async ({ page }) => {
  await page.setViewportSize({ width: 1280, height: 800 });
  await page.goto('https://example.com', { waitUntil: 'networkidle' });
  await expect(page).toHaveScreenshot('home.png', { fullPage: true });
});

Run the test once to create the missing expected screenshot, then inspect and commit that image. On later runs, the assertion compares a new screenshot with the baseline. Use the same project configuration and environment for baseline generation and checks.

Page, full-page, and element captures

For a raw capture without a visual assertion, Playwright’s page screenshot API supports file output, full-page capture, and returning bytes:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
  await page.goto('https://example.com', { waitUntil: 'networkidle' });

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

  const imageBytes = await page.screenshot();
  console.log(`Captured ${imageBytes.length} bytes`);
  await browser.close();
})();

To capture a focused component, use a locator. The locator is resolved against the current page state, so wait for the relevant state before capturing:

const card = page.locator('[data-testid="pricing-card"]');
await expect(card).toBeVisible();
await expect(card).toHaveScreenshot('pricing-card.png');

The Playwright Screenshots guide documents page, full-page, element, and byte capture. For regression assertions, see the Visual comparisons guide.

Control volatile content carefully

Dynamic timestamps, rotating ads, avatars, and animated content can make captures differ even when the UI change under test is correct. Prefer deterministic test data or freeze the state where possible. Playwright’s assertion options support masking selected locators and applying a stylesheet during capture. A larger accepted pixel difference may reduce noise, but excessive tolerance can hide real regressions. Review the image diff before accepting a change.

await expect(page).toHaveScreenshot('account.png', {
  fullPage: true,
  mask: [page.locator('[data-testid="current-time"]')],
  stylePath: 'tests/visual-overrides.css',
});

Use only options supported by the Playwright version installed in your project; the visual comparison documentation describes assertion options and baseline behavior.

3. Selenium: capture and add a comparison workflow

This Python example uses Selenium WebDriver to capture a page and a focused element. Install Selenium and a compatible browser driver using the Selenium getting started guide. The capture code is complete; comparison is deliberately a separate step because Selenium’s screenshot API supplies the image rather than a built-in baseline assertion.

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

out = Path('screenshots')
out.mkdir(exist_ok=True)

options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--window-size=1280,800')

driver = webdriver.Chrome(options=options)
try:
    driver.get('https://example.com')
    WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.TAG_NAME, 'body'))
    )
    driver.save_screenshot(str(out / 'home.png'))

    card = WebDriverWait(driver, 15).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, '[data-testid="pricing-card"]'))
    )
    card.screenshot(str(out / 'pricing-card.png'))
finally:
    driver.quit()

save_screenshot writes the current window image as PNG and returns whether the save succeeded. The Python WebDriver API also provides screenshot bytes and Base64 methods. See the Selenium Python WebDriver API and Selenium’s screenshot examples.

Build the missing baseline step

  1. Save a screenshot for a known test state and location.
  2. On the first approved run, store it as the expected baseline.
  3. On later runs, compare the new image with that baseline using your chosen image library, test extension, or visual testing service.
  4. Produce a diff or other reviewable output when images differ.
  5. Update the baseline only after reviewing the visual change and confirming it is intended.

Keep the comparison policy explicit: decide how to handle antialiasing, small pixel differences, masks, and image dimensions. The Selenium documentation does not prescribe these choices; they belong to your comparison layer and test policy.

4. Choose the right capture boundary

  • Whole page: Use full-page screenshots when page layout, content flow, or long-page sections are part of the contract. Full-page images can make diffs noisy when unrelated content changes.
  • Component or region: Capture an element or locator when the intended contract is a focused widget or component. This narrows the area that unrelated changes can affect.
  • Viewport: Capture the visible viewport for behavior tied to the fold, responsive layout, or a specific scroll position. Set viewport dimensions explicitly.

Both tools document page and element capture shapes. Match the scope to what the test is meant to protect rather than snapshotting everything by default.

5. Keep visual tests stable and useful

  • Pin the environment: Playwright warns that operating system, browser version, settings, hardware, power source, and headless mode can affect rendering. Generate and compare baselines in the same environment.
  • Separate browser and platform baselines when needed: Rendering can vary across browsers and platforms. Treat each intended browser/platform combination as its own baseline set.
  • Make page state deterministic: Control test data and wait for the specific state under test. Do not assume that a page load event means every animation or remote widget has settled.
  • Use masks and thresholds sparingly: Mask only genuinely volatile areas and inspect diffs. Broad masks or loose thresholds can conceal meaningful layout changes.
  • Review baseline changes: Baselines are test assets. A changed reference image is an assertion change and should be reviewed like other test changes.

Playwright’s screenshot assertion waits for two consecutive captures to produce the same result before comparing the last image with the expectation. This helps with capture stability but does not make external content or the overall test environment deterministic. The PageAssertions API documents the assertion behavior.

6. Decision guide

Your situation Practical choice
You are starting a visual regression suite and can choose the framework. Playwright Test is the more direct documented route when you want screenshot assertions integrated into the test runner.
Your existing browser suite is Selenium. Keep Selenium if it fits your language, browser coverage, and infrastructure. Add a comparator, baseline storage, review, and update process.
You need cross-browser or cross-platform coverage. Plan for separate baselines where rendering differs, and pin each baseline environment.
You are testing a single component state. Prefer a focused element or locator capture if that defines the UI contract clearly.

7. Troubleshooting

Symptom Likely cause Fix
Playwright reports a missing expected screenshot. This is the first assertion run for that snapshot, or the snapshot name/project path changed. Generate the baseline using the intended environment, inspect it, and commit it with the test assets.
Playwright produces recurring diffs on an unchanged page. Environment drift or volatile page content, such as timestamps or animations. Use a consistent OS/browser setup, stabilize test data, and selectively mask or style volatile regions.
A Selenium screenshot is missing or the save call fails. The output directory may not exist, the process may lack write access, or the capture ran before the page was ready. Create the directory, check the save result and permissions, and wait for the target state before capture.
Element capture fails because the element is not found or visible. The selector is wrong, the element has not rendered, or the expected UI state was not reached. Verify the selector and use an explicit wait for presence or visibility.
Images differ after a browser or OS update. Rendering output can depend on browser and host environment. Confirm the environment change was intended; regenerate and review baselines for that environment instead of silently accepting all diffs.
Full-page snapshots are noisy or unwieldy. The test includes unrelated content or a long page region that changes independently. Capture a viewport or focused element when that better matches the behavior under test.

8. Performance, reliability, and cost

The cited documentation does not provide a comparative speed benchmark, so do not choose between these tools based on an assumed screenshot speed advantage. Capture and comparison both add work to a test run; keep the scope to the page or element that expresses the test contract, and avoid repeatedly capturing unrelated regions.

Reliability depends on reproducibility: browser and operating system versions, viewport, data, page state, and handling of volatile content all matter. Playwright’s integrated assertion manages baseline comparison within Playwright Test, while a Selenium workflow has additional integration choices to operate and maintain. Neither capture API alone guarantees that a screenshot is a useful regression test.

Playwright Test’s screenshot assertion is part of that test runner. A Selenium visual-testing setup may involve your chosen comparator or a separate service; evaluate its licensing or service cost from that provider’s current terms. The sources here do not establish a universal cost or performance ranking between the frameworks.

9. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. For a one-call capture, see the ScreenshotNeo API documentation:

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}`);

ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are never billed, and response headers report the page verdict and billing status. Its MCP server lets AI agents use screenshot, page-info, and PDF capture tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. It can simplify website capture, while visual regression still requires a baseline and comparison process appropriate to your tests.

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

10. FAQ

Does Selenium have built-in visual regression testing?

Selenium documents screenshot capture APIs. The official pages reviewed here do not show a built-in baseline assertion like Playwright Test’s toHaveScreenshot(); add a comparison and baseline workflow to a Selenium suite.

Does Playwright compare screenshots on its first run?

The first toHaveScreenshot() run creates the expected image. Later runs compare against it, so inspect and commit the initial baseline.

Should a visual test use a page screenshot or an element screenshot?

Choose the smallest capture boundary that fully represents the behavior under test. Use a page or full-page capture for page-level layout and an element capture for a focused component.

Why can the same test produce different screenshot files on different machines?

Rendering can vary with the OS, browser version, settings, hardware, power source, and headless mode. Keep baseline creation and comparison in a consistent environment.

Primary documentation