What Is Percy? A Guide to Visual Testing
Percy compares page snapshots with approved visual baselines so teams can review interface changes in pull requests. Learn how its workflow, integrations, browsers, and baselines fit together.
Percy is BrowserStack’s visual testing and review platform. It captures snapshots of pages or application states during a test run, compares them with approved baselines, and highlights visual differences for people to review. It complements functional tests: functional tests check behavior, while visual comparisons can reveal unintended changes to layout, styling, fonts, colors, and other visible details.
A Percy difference is a review signal, not automatically a bug. A developer or reviewer decides whether the change is intentional, fixes it, or approves the new appearance. Percy connects this review to builds and, when source-control integration is configured, to pull requests and commits. Percy’s visual testing overview describes snapshots, build review, and approvals.
This guide explains the workflow and how to get a first Playwright snapshot into Percy. For raw website screenshots outside a baseline review workflow, ScreenshotNeo is an alternative to try first: it removes known consent banners, popups, and chat widgets before capture, and bills only clean shots.
1. What visual testing checks
Visual regression testing checks whether a rendered page looks different from a reference image or snapshot. It can catch problems that a test asserting only text, URL, or element presence will miss: a button moved off-screen, a heading wrapped unexpectedly, a font failed to load, a modal obscured content, or a layout broke at a viewport size.
| Test type | Question it answers | Example |
|---|---|---|
| Functional | Does the feature behave as expected? | Clicking Save persists a profile. |
| Visual | Does the rendered interface match the accepted appearance? | The Save button remains visible and aligned. |
Neither replaces the other. A page can look correct while a control is broken, and a functional test can pass while the page is visually damaged.
2. How Percy works
- Create a Percy project. Use a project to organize visual builds for an application or component library.
- Run a build. Trigger it from a test, CLI command, or supported workflow. The build groups snapshots and can include commit or pull-request metadata when repository integration is present.
- Capture snapshots. A supported SDK or workflow sends page state and related assets to Percy. Percy renders the snapshot for comparison.
- Compare against a baseline. Percy shows changed regions against the selected approved reference.
- Review and decide. Approve intended changes or request changes for regressions. With source-control integration, build status can participate in pull-request review and can be configured to block a merge.
Baseline behavior matters. Approved snapshots can carry forward on a branch, and the main branch is auto-approved by default unless project settings change that behavior. Branch strategy and the selected baseline determine whether a diff represents a new change or an older divergence. See the current baseline management guide and build review documentation when setting up a repository.
3. Run a minimal Percy build with Playwright
This Node.js example opens a page with Playwright and submits a named snapshot to Percy. It assumes you have created a Percy project and can set that project’s token as an environment variable. The setup follows BrowserStack’s Playwright integration guide.
Install dependencies
npm init -y
npm install playwright @percy/cli @percy/playwright
Save this as visual.js:
const { chromium } = require('playwright');
const percySnapshot = require('@percy/playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto('https://example.com/', { waitUntil: 'networkidle' });
await percySnapshot(page, 'Example page');
} finally {
await browser.close();
}
})();
Set PERCY_TOKEN to the project token in your shell or CI secret store, then run the script through Percy:
export PERCY_TOKEN="YOUR_PERCY_PROJECT_TOKEN"
npx percy exec -- node visual.js
On Windows PowerShell, set the variable with $Env:PERCY_TOKEN="YOUR_PERCY_PROJECT_TOKEN" before running the command. The CLI starts a build, runs the script, submits snapshots, and finalizes the build. Open the build URL in the command output to inspect the comparison. Keep the token in a secret store; do not commit it to the repository.
Snapshot names should be stable and meaningful, such as a page name plus a state. Capture after the application has reached the state you want to protect. For an authenticated or interactive view, complete the login or actions in the test first, then call the snapshot function.
4. Integrations, browser coverage, and project scope
Percy’s documented integration ecosystem includes Selenium, Playwright, Cypress, Puppeteer, Ember, Storybook, React Styleguidist, Gatsby, Jekyll, Appium, Tricentis Tosca, Maestro, and a build-your-own SDK path. Available details and capabilities can vary by integration; consult the relevant setup guide in the Percy documentation rather than assuming every framework has identical behavior.
Percy documents cross-browser testing for Chrome, Firefox, Edge, and Safari. Browser selection may be managed through Percy project settings or through BrowserStack Automate configuration. Percy-managed rendering uses Percy infrastructure and fixed operating systems; Automate configuration can specify operating-system and browser details when OS-level rendering differences matter. Each browser snapshot counts separately toward monthly screenshot usage. See the current cross-browser documentation for configuration and current browser availability.
Choose scope deliberately: a small set of critical page states gives a focused signal, while broad browser and viewport matrices multiply snapshot volume and review work. Include the states users rely on most: for example, default page, validation error, empty state, and a key responsive width.
5. Baselines and approvals in practice
First build
Your first build establishes or connects the reference snapshots for the project. Review it carefully: a baseline that already contains a broken layout makes later comparisons less useful. If the project has existing builds or repository history, follow Percy’s setup instructions for the selected baseline strategy.
Feature branches
When a branch changes a component, its next build should compare against the intended base branch or latest approved snapshots according to the project’s baseline strategy. Approve deliberate changes so they become the accepted reference for subsequent work. Resolve outdated branch baselines when the base branch has changed; otherwise a review may include differences that are unrelated to the current pull request.
Approval and merge policy
Decide who can approve snapshots and whether visual status blocks merging. A useful policy keeps human review for visible changes while preventing an unreviewed build from quietly becoming the new reference. Percy can report status through source-control integrations, but repository settings and team policy determine how that status affects merges.
Plan history retention as part of the workflow. The research checked for this guide reported that free-plan builds expire after 30 days and other plans have one year of history; plan terms can change, so verify the current Percy plan details before relying on those periods.
6. Reduce noisy differences
Visual comparisons become more useful when a repeat run renders the same state. Common sources of noise include rotating content, timestamps, random identifiers, animation, asynchronous data, font loading, and third-party widgets. Prefer deterministic test data and stable page state. Wait for the content that matters and avoid snapshotting while layout is still shifting.
- Use fixed test data and predictable accounts.
- Wait for the relevant page or component to finish loading before capture.
- Use consistent viewport dimensions and browser configuration.
- Disable or stabilize animation and time-dependent content where appropriate.
- Keep snapshot names and test state consistent across runs.
- Use the integration’s documented region or CSS controls for genuinely dynamic areas, and keep those exclusions narrow so real regressions remain visible.
Do not silence a noisy region broadly without understanding why it changes. An exclusion can hide an actual layout failure in that area.
7. Performance, reliability, and cost considerations
Build duration depends on the number of snapshots, browser configurations, test execution, and rendering. Cross-browser coverage increases the number of snapshots because each browser produces a separate comparison. Start with high-value pages and expand coverage based on risk and review capacity.
Reliability depends on repeatable test state and a clear baseline strategy. If CI runs do not have consistent data, fonts, viewport sizes, or environment behavior, Percy may correctly show differences that are environmental rather than product changes. Keep the capture environment and browser settings deliberate, and inspect the build metadata when a comparison looks unexpected.
For cost planning, count snapshots across pages, states, and browsers rather than counting only test cases. BrowserStack’s product page stated a Percy free allowance of 5,000 screenshots per month when the research was checked; this is a changeable plan claim, so verify current limits and pricing on the official product page before publication or adoption. Do not assume that allowance or retention terms will remain unchanged.
8. Troubleshooting
| Symptom | Likely cause | What to check |
|---|---|---|
| No Percy build starts | Token missing, invalid, or unavailable in the process environment | Confirm the project token is set in the same shell or CI job that runs percy exec; check that the secret is mapped correctly. |
| Build runs but has no snapshots | The test never called Percy, the test failed before capture, or the command did not wrap the test process | Check script output and ensure the snapshot call runs after navigation and state setup. |
| Navigation times out or capture is blank | The target is unreachable from the runner, navigation is still pending, or the page requires authentication | Check URL access, login setup, and readiness conditions. Wait for the needed content rather than relying on an arbitrary short delay. |
| Every run shows large diffs | Baseline mismatch, changing data, viewport drift, or unstable rendering | Confirm branch/base selection, test data, viewport, and loaded fonts; compare build metadata and establish a correct baseline if needed. |
| Only one browser appears | Cross-browser selection is not configured for the project or Automate session | Check the project’s browser settings and the integration-specific browser capabilities. |
| Snapshots differ between local and CI runs | Different browser, operating system, viewport, fonts, or environment data | Align configuration and test state; use the intended Percy-managed or Automate rendering setup. |
| Build is not blocking a pull request | Source-control status checks or branch protection are not configured to require it | Check repository integration, required status checks, and Percy project settings. |
9. Or skip the browser setup
If your goal is to capture a clean screenshot of a public page rather than compare test snapshots against a baseline, ScreenshotNeo provides a one-call screenshot API. Its API documentation covers 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}`);
- Cookie banners, popups, and chat widgets are removed before the shot.
- Bot checks, blank pages, and failed loads are never billed.
- An MCP server lets AI agents use screenshot, page-info, and PDF tools.
- 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.
Sign up free for 1,000 screenshots a month, with no card required.
10. Frequently asked questions
Does Percy replace functional tests?
No. Percy evaluates appearance against visual baselines. Keep functional tests for behavior and use visual comparisons to catch presentation changes.
Does Percy work with Playwright?
Yes. BrowserStack documents a Playwright integration for Node.js and Python, among other options. Follow the integration-specific documentation because setup differs by language and workflow.
Can Percy test across browsers?
Yes. Its documentation lists Chrome, Firefox, Edge, and Safari. The available selection and configuration depend on whether you use Percy-managed rendering or BrowserStack Automate.
Does a visual difference mean the test failed?
A difference indicates that the rendered result changed relative to the baseline. A reviewer determines whether it is expected or needs a fix.
Is Percy a website screenshot API?
Percy’s central workflow is snapshot comparison and review integrated with tests and builds. For a direct screenshot API that returns an image or PDF from a URL, ScreenshotNeo is designed for that use case.
Plan limits, supported integrations, browser versions, and retention details can change. Check the linked official documentation for current terms.


