How to Set Up Percy with Playwright in a React Project
Add Percy visual snapshots to a React project's Playwright tests, run them through Percy CLI, and keep visual reviews useful alongside behavioral assertions.
To add Percy to a React project that already uses Playwright Test, install @percy/cli and @percy/playwright, add percySnapshot(page, 'descriptive state') after the page reaches the state you want to review, and run the existing tests through Percy CLI:
npm install --save-dev @percy/cli @percy/playwright
npx percy exec -- npx playwright test
Make the Percy project token available to the command through your local or CI environment, following the current Percy project instructions. Do not commit the token. Keep Playwright assertions for behavior; Percy snapshots provide visual comparisons for the states you choose to capture.
1. Check the existing Playwright setup
This guide assumes the React app already has a Playwright Test suite. Keep its current configuration, scripts, and test layout; Percy works with the Playwright page object and does not require a separate React-specific Percy SDK in this browser-test workflow.
If you still need to initialize Playwright, its official installation guide uses npm init playwright@latest to initialize a project or add Playwright to an existing one. The setup can scaffold configuration and starter tests and install the needed browsers. Run the suite with npx playwright test.
2. Install Percy
From the React project directory, install the two development dependencies:
npm install --save-dev @percy/cli @percy/playwright
The CLI wraps the test command and handles the Percy run. The Playwright package provides the snapshot helper used inside tests. The package command shown here follows Percy’s vendor setup example; consult current Percy documentation when you need to confirm version-specific API or package details.
3. Add snapshots to meaningful page states
Import percySnapshot in a Playwright test and call it after navigation and any interactions needed to reach the state under review. For example:
import { test, expect } from '@playwright/test';
import { percySnapshot } from '@percy/playwright';
test('shows the login error state', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('invalid@example.com');
await page.getByLabel('Password').fill('incorrect-password');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByRole('alert')).toBeVisible();
await percySnapshot(page, 'Login - Error State');
});
This is a complete test shape; adapt the URL, accessible labels, button name, and expected alert to the app. The assertion checks a behavioral outcome, while the snapshot records the rendered state for visual comparison.
Choose snapshot points deliberately
- Capture states users need to recognize, such as a page’s initial view, a completed form submission, or a meaningful post-interaction state.
- Give snapshots descriptive names so reviewers can identify the state they are looking at.
- Wait for the app’s actual readiness condition: for example, a specific result, alert, or loaded component. Avoid treating an arbitrary delay as proof that the page is ready.
- Let relevant network work, animations, and lazy-loaded content settle before capture. Minimize or stabilize dynamic content that would cause unrelated visual noise.
Snapshot placement is a coverage choice. A snapshot after navigation will not show a later menu, error, or dialog unless the test reaches that state before capturing it.
4. Run Playwright through Percy CLI
Wrap the same test command you already use with percy exec:
npx percy exec -- npx playwright test
The part after -- is the Playwright command. If your project has a test script or passes Playwright options, put that existing command after the separator. For example, a project using an npm script can wrap that script instead:
npx percy exec -- npm test
Use the command that actually runs Playwright in your project. Percy needs the project token to authenticate snapshot uploads. Supply it to the process through your local or CI environment according to the current Percy project instructions, and store it as a secret in CI. Do not hard-code it in test source or commit it to the repository. The setup source does not establish current account-screen steps or a universal token configuration command, so use the instructions for your Percy project.
5. Keep visual review and behavior checks distinct
Playwright assertions answer whether a tested outcome occurred. Percy differences show how selected rendered states differ from an approved visual baseline. Use both where appropriate: fix failing behavior in the test or app, and inspect visual changes before accepting a new baseline. Approve a baseline only when the appearance change is expected.
| Check | What it tells you | Typical response |
|---|---|---|
| Playwright assertion | Whether an interaction or user-visible outcome meets the test expectation | Investigate the failing behavior or update an assertion when requirements changed |
| Percy visual comparison | Whether a captured page state looks different from its approved baseline | Review the difference, then fix an unintended change or intentionally approve the expected appearance |
A visual change is evidence to review, not by itself proof that behavior is broken. Conversely, passing behavioral assertions do not establish that the page still looks right.
6. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| No Percy snapshots appear | The tests were run directly, outside the Percy CLI wrapper, or the snapshot call was not reached | Run the Playwright command after npx percy exec --; confirm the test reaches percySnapshot |
| Authentication or upload fails | The process cannot access a valid Percy project token | Check the current Percy project instructions and confirm the token is available to the local or CI process as a secret |
| The snapshot shows a loading or incomplete state | The capture happened before the page’s real readiness condition, async work, or lazy content finished | Wait for the relevant user-visible condition and ensure required content has loaded before calling the helper |
| Visual differences change between runs | Dynamic content, unfinished animation, or timing-sensitive state is changing the captured pixels | Stabilize the state, wait for relevant work to settle, and reduce unrelated dynamic content |
| A visual diff appears despite passing tests | Behavior can remain correct while styling, layout, or rendered content changes | Inspect the diff and determine whether the appearance change is expected before updating the baseline |
| A test passes but an important screen has no visual comparison | No snapshot was added for that state | Drive the test to the state and add a clearly named snapshot there |
7. Performance, reliability, and cost considerations
Each Percy snapshot adds visual capture and comparison work to the test run. Capture states that give useful review coverage rather than adding a snapshot after every small interaction. Avoid arbitrary waits: they can slow a suite and still fail to guarantee readiness. Waiting on the user-visible condition makes the capture point clearer and reduces timing uncertainty.
Visual review is most reliable when the same test consistently reaches the same meaningful state. Dynamic content and unsettled animations can create differences unrelated to a code change, so stabilize those inputs where possible. Keep the test assertions as a separate signal and review visual differences before changing baselines.
The research sources establish the setup pattern but do not establish current Percy plan limits, per-snapshot pricing, or a compatibility matrix. Check current Percy account and product documentation for those details before estimating a rollout’s cost or supported versions.
Or skip the browser setup
If you need a screenshot from a URL without adding a browser capture step to your project, ScreenshotNeo provides a screenshot API and MCP server. Its one-call API can return a PNG, JPEG, WebP, or PDF; see the 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}`);
- Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status.
- An MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
- The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
FAQ
Does a React app need a special Percy integration?
For the documented Playwright browser workflow, use the Playwright page and Percy helper. The setup described here does not require a React-specific Percy SDK.
Should Percy replace Playwright assertions?
No. Keep assertions for behavior and use visual comparisons to review the appearance of selected states.
Can I capture more than the initial page?
Yes. Navigate or interact until the test reaches the state you want to inspect, then call percySnapshot with a descriptive name.
Where can I find current token and version details?
Use the current Percy project instructions for token setup and current package documentation for version-specific details; the available setup source does not establish exact account steps or a compatibility matrix.


