ScreenshotNeo

BlogHow-to

Playwright Screenshot Testing Tutorial for Indian Developers

Add visual screenshot checks to Playwright, review and update baselines, and keep local and CI runs consistent. Includes runnable setup and troubleshooting.

By the ScreenshotNeo team4 October 20268 min read

Playwright Test can capture a page and compare it with a reference image using await expect(page).toHaveScreenshot(). The first run creates the reference image; later runs compare against it. Commit and review those images, and generate and compare them in a consistent browser and operating-system environment. That applies to developers in India just as it does elsewhere: the important factors are the rendering environment and browser version, not a country-specific setting.

This tutorial uses JavaScript, Playwright Test, and Chromium. It covers baseline creation and updates, stable test design, CI setup, comparison options, common failures, and an API option for capturing screenshots outside a test.

1. Install Playwright and its browser

Start in a Node.js project. Install Playwright Test as a development dependency and install Chromium and its operating-system dependencies:

npm init -y
npm install --save-dev @playwright/test
npx playwright install --with-deps chromium

Each Playwright release expects specific browser binaries. Use the CLI installation command for the version installed in the project, and keep the lockfile under version control so local and CI installations resolve the same package version. See the official Playwright browser installation documentation.

2. Write a screenshot test

Create tests/homepage.spec.js. Replace the example URL with a page your test environment can reach:

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

test('homepage matches its visual baseline', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000', {
    waitUntil: 'networkidle',
  });

  await expect(page).toHaveScreenshot('homepage.png');
});

Add a test script to package.json if the project does not already have one:

{
  "scripts": {
    "test:e2e": "playwright test"
  }
}

Run the test:

npm run test:e2e

On its first run, Playwright writes the expected screenshot in a snapshot directory associated with the test file. On subsequent runs, it captures the page again and compares the result to that image. Review and commit the generated baseline along with the test. The snapshot is a reviewed test artifact, not disposable output.

3. Review and update the baseline

When a comparison fails, inspect the actual image, the expected image, and the diff produced by Playwright. Decide whether the change is an unintended regression or an intentional design update. If the design change is intended, update snapshots explicitly:

npx playwright test --update-snapshots

Review the changed image files before committing them. Updating every baseline without inspecting the diffs can turn a real regression into the new expected result. If only one area should change, make the review focused: run the relevant test, inspect its diff, and check the other changed snapshots too.

4. Make captures more repeatable

Screenshot output can vary with the host operating system, browser version, browser settings, hardware, power source, and headless mode. Playwright does not promise pixel-identical rendering across arbitrary machines. Generate baselines and compare them in the same environment where practical. The visual comparison documentation explains these sources of rendering variation.

Control the page before capturing

  • Use a deterministic test URL and seed or reset test data so content does not change between runs.
  • Wait for the page state the test is meant to check. Prefer waiting for a meaningful locator when a page uses ongoing network activity; networkidle can be unsuitable for pages with persistent requests.
  • Disable or control animations, rotating banners, timestamps, randomized content, and other volatile elements when they are outside the test’s purpose.
  • Keep viewport, browser engine, browser version, fonts, locale, and other relevant project settings consistent between baseline generation and comparison.
  • Use the same operating system image for CI and baseline updates when possible. If developers update snapshots on another OS, review platform-specific differences carefully.

For example, a fixed viewport and a locator-based readiness check make the intended capture conditions explicit:

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

test.use({ viewport: { width: 1280, height: 800 } });

test('pricing page visual baseline', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000/pricing');
  await page.getByRole('heading', { name: 'Pricing' }).waitFor();
  await expect(page).toHaveScreenshot('pricing.png');
});

Use a readiness condition that matches the application. A visible heading confirms that one element appeared; it does not prove every image or asynchronous section is ready.

Hide only genuinely volatile regions

The screenshot assertion accepts stylePath, which applies a stylesheet during screenshot capture. Use it to hide known dynamic elements when their content is not what the test is checking. For example, create tests/visual.css:

.live-clock,
.randomized-recommendations {
  visibility: hidden !important;
}

Then pass the stylesheet with the screenshot options:

await expect(page).toHaveScreenshot('homepage.png', {
  stylePath: 'tests/visual.css',
});

Keep the filter narrow. Hiding a large area can conceal layout regressions along with harmless variability.

5. Configure comparison tolerance carefully

By default, visual assertions expect the screenshot to match its baseline. If environment alignment still leaves a small, understood difference, maxDiffPixels sets the maximum number of pixels allowed to differ:

await expect(page).toHaveScreenshot('homepage.png', {
  maxDiffPixels: 25,
});

This is a pixel-count allowance, not a reason to skip inspecting diffs. Pick a value only after examining the mismatch and understanding its cause. A broad tolerance can hide meaningful changes. First align the OS, browser version, and capture conditions; then use a small, justified allowance if needed. The option and stylesheet behavior are documented in Playwright’s visual comparisons guide.

Playwright also supports snapshot assertions for text and arbitrary binary data through toMatchSnapshot(). Use toHaveScreenshot() for page or element screenshot comparisons; the other assertion is a separate snapshot use case.

6. Run screenshot tests in CI

Install project dependencies and the browsers before running tests. A typical Linux CI job uses:

npm ci
npx playwright install --with-deps
npx playwright test

Commit package-lock.json so npm ci installs the locked dependency versions. For a stability-first starting point, Playwright recommends one worker in CI. Add this to playwright.config.js:

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

module.exports = defineConfig({
  testDir: './tests',
  workers: process.env.CI ? 1 : undefined,
});

One worker can reduce contention and variability on constrained CI machines. If the CI environment can support more parallel work, increase workers deliberately or distribute tests with sharding. Compare results in the same environment used to produce the baselines. Read the official Playwright CI guide for the current installation and execution guidance.

Browser caching is not automatically a speed improvement: restore time can be comparable to downloading, and Linux system dependencies still need to be installed. Measure your own pipeline before adding a cache. CI actions and browser installation commands can change; consult the official documentation when maintaining the workflow.

7. Troubleshooting

Symptom Likely cause What to do
The first run reports that no expected screenshot exists This test has no baseline yet. Run the test, inspect the generated image, then commit the reviewed snapshot.
The test fails after a visual change The actual page differs from the committed baseline, intentionally or otherwise. Inspect actual, expected, and diff images. If the change is intended, run npx playwright test --update-snapshots and review the resulting files.
The same commit passes locally but fails in CI OS, browser binary, fonts, headless mode, hardware, or capture timing differs. Align baseline and CI environments, pin dependencies with the lockfile, install the matching browser, and control dynamic content.
Browser executable is missing The required browser binary was not installed or does not match the installed Playwright version. Run npx playwright install chromium, or install all configured browsers with npx playwright install.
Browser launches locally but not on Linux CI Required operating-system libraries may be missing. On supported Linux CI, install browsers and dependencies with npx playwright install --with-deps. The browser guide also documents npx playwright install-deps.
The capture is blank or incomplete The test may navigate to the wrong URL, capture before the page is ready, or run without the application server. Check the URL and server startup, then wait for a meaningful page element before capturing. Review the test output and captured image.
Images or fonts differ intermittently Resources may load at different times, or the test may use different fonts or environments. Wait for the relevant content, make test data stable, and align installed fonts and OS. Avoid masking the whole page with a large tolerance.
Snapshot updates change many unrelated files Many pages may be affected by a shared change, or snapshots may be regenerated in a different environment. Inspect all diffs, verify the environment, and separate intended visual changes from platform drift before committing.

8. Performance, reliability, and cost

Screenshot assertions add browser rendering and image comparison work to a test suite. Keep visual tests focused on pages and states where visual regressions matter; use ordinary assertions for behavior that does not need image comparison. A single CI worker is a reasonable stability-first setting, while additional workers or sharding can improve throughput when the environment supports them. More parallelism can also increase resource contention, so check whether it makes captures less stable.

Playwright itself is an open-source test framework; this workflow’s operational costs come from the machine time, CI capacity, and storage used for test artifacts and baselines. The research sources do not establish a universal runtime or cost figure. Browser binaries must be installed for the Playwright version in use, and Linux system dependencies may need installation as well.

Or skip the browser setup

If you need a screenshot as an output rather than a visual assertion inside a test suite, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. It does not replace Playwright’s baseline review workflow; it provides a hosted capture option when you do not want to install and manage a browser for that capture.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

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)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

See the ScreenshotNeo API documentation for request options and response details. Cookie banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots.

Sign up for 1,000 free screenshots a month with no card.

FAQ

Should I commit Playwright screenshot baselines?

Yes. They are the expected visual state used by later comparisons, so keep reviewed baselines with the test in version control.

Can I use screenshot assertions with browsers other than Chromium?

Playwright supports Chromium, Firefox, and WebKit, as well as branded Chrome and Edge configurations. Keep the chosen browser and its version consistent when creating and comparing baselines.

Does a passing screenshot test prove the page works?

No. It checks visual similarity to a reference image. Add separate assertions for interactions, accessibility, and application behavior that matter to the test.

Is there a special setup for developers in India?

The cited Playwright guidance is general platform and CI guidance; it does not establish India-specific browser or CI requirements. Use portable commands and keep the baseline and comparison environments aligned.