ScreenshotNeo

BlogComparisons

Playwright Screenshot Testing vs Percy: Which Should You Use?

Playwright can compare screenshots with committed baselines; Percy adds hosted visual review. Compare setup, CI behavior, and tradeoffs to choose the right workflow.

By the ScreenshotNeo team4 October 202612 min read

Short answer: If your team already uses Playwright Test and local, repository-managed baselines with direct test failures meet your needs, start with Playwright’s built-in toHaveScreenshot(). Choose Percy when you need a hosted visual review workflow and managed baselines. Percy can route existing Playwright screenshot assertions into its review flow, so you can evaluate it without rewriting every assertion. The key decision is who owns baselines, how changes get reviewed, and what a green CI run means.

Playwright and Percy are complementary in one important way: Playwright Test can capture and compare screenshots locally; Percy can accept those screenshots and provide hosted comparisons and review. Neither is a universal best choice.

1. What Playwright and Percy each do

Playwright Test: local screenshot assertions

Playwright Test’s visual comparison API is await expect(page).toHaveScreenshot(). On the first run, it writes a reference image (often called a baseline or golden file). On later runs, it compares the new capture with that reference. Snapshot files are associated with test files in a snapshots directory and are typically committed to version control and reviewed when they change. This is part of Playwright Test; the snapshot assertion APIs work with the Playwright test runner.

Playwright can tune image comparisons with options such as pixel-difference thresholds, masks, clipping, and custom stylesheets to hide or normalize volatile page content. Its visual-comparison documentation explains that browser rendering can vary with the host OS, browser version, settings, hardware, power source, headless mode, and other factors. For reliable comparisons, generate and compare baselines in the same environment. Playwright visual comparisons · Snapshot assertion API

Percy: hosted comparisons and review

Percy is a hosted visual-testing and review service. Its Playwright integration can route existing toHaveScreenshot() calls to Percy through a drop-in configuration. Percy maintains a hosted base build and presents changes for review. With this integration, the assertion passes locally and the visual verdict appears in Percy’s review workflow; that changes what a passing test command means. Percy’s Playwright toHaveScreenshot() integration

2. Compare the workflows

Decision Playwright native screenshots Percy with Playwright
Baseline ownership Reference images are local files associated with tests; teams usually commit and review them in the repository. Percy maintains a hosted base build and visual review workflow. In supported new-project configurations, committed snapshots can seed the base.
Environment consistency Comparisons can vary across operating systems, browsers, fonts, hardware, settings, and headless mode. Keep baseline generation and comparison environments consistent. Percy describes its hosted comparisons as consistent across test machines. Setup and behavior depend on project type and configuration.
Review process A mismatch fails the assertion; a developer inspects and updates the local snapshot when the change is intentional. Differences are reviewed and approved or rejected in Percy. With the drop-in integration, local assertions pass and visual review takes place in Percy.
CI gate A mismatch fails the Playwright check by default. A Percy build can await review while the test command passes. Add a build wait/failure gate if unapproved changes must block CI.
Setup and dependency Use Playwright Test, choose a stable environment, and manage snapshot updates in version control. Set up a Percy project and token, install the CLI and Playwright integration, configure the drop-in, and decide how builds are reviewed and gated.
Best fit Teams that want a direct, code-adjacent workflow and are comfortable owning image files and environment consistency. Teams that value hosted review and managed baselines and accept a service dependency and an explicit approval/gating workflow.

3. Set up native Playwright screenshot testing

The following minimal JavaScript example uses Playwright Test. It visits a page, waits for a page-specific readiness signal, and captures a named screenshot. Replace the sample URL and selector with your application’s stable route and readiness condition.

// tests/home.spec.js
const { test, expect } = require('@playwright/test');

test('home page visual baseline', async ({ page }) => {
  await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
  await page.locator('main').waitFor({ state: 'visible' });
  await expect(page).toHaveScreenshot('home.png', {
    fullPage: true,
    animations: 'disabled',
    maxDiffPixelRatio: 0.01,
  });
});

Install Playwright Test and its browser, then run the test once to generate the initial reference image:

npm install --save-dev @playwright/test
npx playwright install chromium
npx playwright test tests/home.spec.js --project=chromium

Review and commit the generated snapshot alongside the test. Later runs compare against that committed file. When a visual change is intentional, inspect the diff and update the baseline deliberately:

npx playwright test tests/home.spec.js --project=chromium --update-snapshots

Keep the machine image, browser version, fonts, viewport, device scale factor, and headless setting consistent between baseline generation and CI. A representative configuration is:

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

module.exports = defineConfig({
  testDir: './tests',
  use: {
    baseURL: 'http://127.0.0.1:3000',
    browserName: 'chromium',
    viewport: { width: 1280, height: 800 },
    deviceScaleFactor: 1,
  },
  expect: {
    toHaveScreenshot: {
      animations: 'disabled',
      maxDiffPixelRatio: 0.01,
    },
  },
});

For repeatable CI captures, pin your dependencies and run the same browser and operating-system image used to create the baselines. Avoid regenerating snapshots automatically as a routine response to failures: first determine whether the page changed intentionally or the capture became unstable.

4. Tune comparisons and reduce screenshot noise

Start by making the page state deterministic. Wait for a meaningful element, fixture, or application-ready signal; use controlled test data; and disable or normalize content that changes on every run. Avoid relying on a fixed delay unless the page has no better readiness signal.

  • Animation: Use animations: 'disabled' when animation frames create unstable images. Check the API for the exact behavior and supported options.
  • Dynamic regions: Use screenshot assertion masks for areas such as rotating ads, timestamps, or avatars that cannot be made deterministic. A mask makes those pixels less informative, so keep it limited to known volatile regions.
  • Thresholds: Use maxDiffPixels or maxDiffPixelRatio to define how much pixel variation is acceptable. A higher threshold can conceal real regressions; start strict and widen it only to address known rendering noise.
  • Scope: Use a named full-page screenshot when the whole page matters. For a focused component, capture a locator or use clipping where supported by the assertion API, so unrelated page content does not cause failures.
  • Styles: Use the supported style-injection option to hide or normalize volatile content when appropriate. Keep the stylesheet in the test suite so the normalization is reviewable.
  • Snapshot names and paths: Give snapshots stable names. Playwright allows configuring the snapshot path template; array path segments must remain inside the test file’s snapshots directory.

Playwright also supports toMatchSnapshot() for text and arbitrary binary snapshots. Use the screenshot assertion for visual page comparisons. Consult the visual comparison documentation and API reference for the complete current option list and behavior.

5. Add Percy to existing Playwright screenshot assertions

Percy’s documented drop-in route sends existing toHaveScreenshot() captures to Percy, without changing test files. The current integration documentation lists prerequisites for its Web Percy route: Node.js 18 or later, @playwright/test 1.60 or later, @percy/cli 1.32.6 or later, and @percy/playwright 1.1.2 or later. Confirm the current integration documentation before installing because package requirements can change.

  1. Create a Percy Web project and obtain its project token. The documented first-run flow needs a full-access token to read build status while waiting for the base build; a write-only token cannot do that.
  2. Install the integration packages using the current versions required by Percy’s docs:
npm install --save-dev @playwright/test @percy/cli @percy/playwright
  1. Load Percy’s drop-in in the default Playwright config:
// playwright.config.js
require('@percy/playwright/dropin');
const { defineConfig } = require('@playwright/test');

module.exports = defineConfig({
  testDir: './tests',
  use: {
    baseURL: 'http://127.0.0.1:3000',
    browserName: 'chromium',
    viewport: { width: 1280, height: 800 },
  },
});
  1. Run the suite through Percy. Keep the token in your CI secret store, not in source control:
PERCY_TOKEN=your-project-token npx percy exec -- npx playwright test

Open the Percy build URL printed when the run finishes and review the snapshots. In the documented drop-in behavior, the screenshot assertion passes locally and Percy holds the visual verdict for review. A green playwright test result alone therefore does not mean that the page matched its base image.

Gate CI on unapproved Percy changes

If an unapproved visual change must fail the pipeline, add Percy’s build wait step after the test run and pass the build ID printed by percy exec:

npx percy exec -- npx playwright test
npx percy build:wait --build YOUR_BUILD_ID --fail-on-changes

The wait step needs permission to read build status, so use a full-access token for this documented flow. Without the gate, Percy provides a review workflow, but your test command can pass while changes await approval. See Percy’s integration and CI guidance.

6. Baseline migration and configuration details

For eligible new Percy projects, committed Playwright snapshots can seed the hosted base build if the documented conditions are met. The integration docs specify the default playwright.config.js or playwright.config.ts file, project settings for use.browserName and use.viewport.width, no custom snapshotPathTemplate or expect.toHaveScreenshot.pathTemplate, and text snapshot names such as toHaveScreenshot('home page.png') rather than folder arrays.

An existing Percy project with builds does not automatically reset its established base. To intentionally establish a base from committed screenshots, the documented command is:

PERCY_TOKEN=your-project-token npx percy playwright:setup-baseline

This command sets up a baseline; it does not run your tests. The documentation also describes using it for parallel builds or an intentional reset. Read the project’s token permissions and baseline conditions before running it, since changing a base affects how subsequent changes are reviewed. Percy baseline setup

7. Which should you choose?

  • Choose native Playwright first if the team wants image files next to code, can review snapshot diffs in its normal code review, and can keep the capture environment stable.
  • Choose Percy if a hosted review surface and managed base build address a real workflow need, and the team is ready to review builds and configure an explicit CI gate if needed.
  • Try the Percy drop-in if you already have many Playwright screenshot assertions and want to evaluate hosted review without immediately rewriting the assertions.
  • Keep native comparison if local mismatch failures are the desired merge gate and repository-owned baselines are manageable.

Make the decision with a representative page and CI workflow. Compare review effort, baseline ownership, how intentional changes are approved, and whether a passing command should mean pixel comparison passed or only that snapshots were submitted for review. The research available for this comparison does not establish a reliable price or performance advantage; check Percy’s current commercial information if cost is decisive.

8. Or skip the browser setup

If your job is to capture a website image or PDF rather than compare versioned UI states inside a Playwright test suite, ScreenshotNeo is a website screenshot API and MCP server for developers. Make one GET request to capture a page. See the ScreenshotNeo API documentation for request 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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Cookie banners, popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.

9. Troubleshooting

Symptom Likely cause What to do
Native screenshot fails on CI but passes locally The rendering environment or page state differs, or dynamic content is changing. Use the same OS/browser image, viewport, fonts, and headless configuration as baseline generation. Wait for a stable readiness signal and normalize only known volatile regions.
First Playwright run reports a missing snapshot No reference image exists yet. Run the test to generate the baseline, inspect the image, then commit it. A fresh clone without committed baselines will also fail until they are present.
Many tiny diffs appear on every run Animations, rotating content, timestamps, or changing data can make captures unstable. Disable animations, use deterministic fixtures, and mask or style away only regions that must vary. Check that page fonts and browser versions match.
Percy creates no build The command may not be running through percy exec, or the project token may be absent or invalid. Set a valid PERCY_TOKEN in the environment and run the Playwright command through npx percy exec --.
Percy says token cannot read build status or returns 403 The token is write-only but the flow is trying to read status or wait for a base build. Use a full-access token for the documented wait/base-build flow, or approve the base build in Percy as directed by its docs.
Every snapshot appears new on the second Percy build The base build may still need approval or baseline setup may not have completed. Approve the base build, then run again. Check Percy’s build output and baseline setup guidance.
Percy says the project already has builds Committed baseline images are not automatically substituted for an existing hosted base. If an intentional reset is desired, review and use npx percy playwright:setup-baseline.
Playwright passes even though Percy shows visual differences The drop-in routes the visual verdict to Percy review; the local assertion passes. Review the Percy build, and add percy build:wait --fail-on-changes with the correct build ID if CI must block on unapproved differences.

Percy’s integration page documents additional cases, including unsupported token/project types, failed baseline uploads, and using verbose output to diagnose baseline discovery. Consult its current troubleshooting guidance for the exact error text you encounter.

10. Performance, reliability, and cost

Both workflows add capture and image-comparison work to a test run. The available primary documentation here does not provide a directly comparable runtime benchmark, so measure with your own suite before drawing speed conclusions. Full-page images and large suites increase the number and size of artifacts to inspect or upload.

Native Playwright comparisons rely on the browser environment that creates and checks the baseline. Pinning that environment and controlling the page state improves repeatability. Percy adds a hosted service and network path to the visual workflow; its review and gating steps also become part of how CI reports a result. Keep functional assertions separate from visual approval so a hosted review status is not mistaken for a passing local pixel comparison.

No verified comparative pricing was established in the research dossier. Check Percy’s current commercial pages for your project and usage before making a cost decision. Playwright’s native workflow avoids adding a hosted visual review service, while still requiring engineering time to maintain deterministic captures and review baseline changes.

11. Frequently asked questions

Does Playwright have built-in visual regression testing?

Yes. Playwright Test provides expect(page).toHaveScreenshot(), which creates a reference screenshot on first run and compares future captures against it.

Does Percy require rewriting toHaveScreenshot() tests?

The documented drop-in integration can route existing assertions to Percy without changing test files. It does require Percy project setup, dependencies, configuration, and execution through Percy’s CLI.

Can a Percy-integrated Playwright test pass while a screenshot changed?

Yes. In the documented drop-in workflow, the assertion passes locally and Percy displays the visual change for review. Add and configure a Percy build wait/failure gate if unapproved changes should fail CI.

Can I use Playwright screenshot assertions without Percy?

Yes. Playwright Test creates and compares repository-managed screenshots locally. Keep baseline generation and comparison environments consistent to reduce rendering noise.

Can ScreenshotNeo replace visual regression testing?

ScreenshotNeo captures website screenshots and PDFs through an API or MCP server. The product facts provided here do not describe a baseline comparison or visual approval workflow, so use it for capture rather than treating it as a replacement for Playwright or Percy visual testing.