Authors Percy visual snapshot tests via the @percy/cli + framework SDK (Playwright, Cypress, Selenium, Storybook), runs them with `percy exec -- {test command}`, configures viewports / masking / ignored regions, and reviews diffs in the Percy build UI. Use when the project ships visual regression coverage to BrowserStack Percy.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Percy is BrowserStack's visual testing platform. The integration shape is
two-layered: the CLI (@percy/cli) plus a framework SDK
(@percy/playwright, @percy/cypress, @percy/selenium,
@percy/storybook, etc. - the Percy CLI README lists the
available SDKs as Playwright, Cypress, Selenium, Storybook, Puppeteer,
Appium, plus framework-specific wrappers like Ember, Gatsby, Jekyll, and
a custom SDK option).
The CLI starts a local snapshot server, the SDK calls
percySnapshot(page, name) from inside your tests, and the build appears
in the Percy UI for baseline review.
@percy/* packages, .percy.yml,
or PERCY_TOKEN in CI secrets).If the project does not already use BrowserStack, evaluate
chromatic-visual-regression-testing
(Storybook-first) or playwright-snapshots
(self-hosted) before adopting Percy.
npm install --save-dev @percy/cli @percy/playwrightBoth packages are required: @percy/cli runs the local snapshot server,
@percy/playwright exposes the percySnapshot function (percy-playwright).
const { chromium } = require('playwright');
const percySnapshot = require('@percy/playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://example.com/', { waitUntil: 'networkidle2' });
await percySnapshot(page, 'Example Site');
await browser.close();
})();(Adapted from percy-playwright.)
percySnapshot(page, name, options)Per the percy-playwright README:
| Option | Effect |
|---|---|
percyCSS | CSS injected immediately before the screenshot. Use this to neutralize timestamps, ad slots, or animations. |
fullPage | Capture the entire scrollable page rather than the viewport. |
freezeAnimatedImage | Freeze animated images (GIF / APNG) so the diff is deterministic. |
ignoreRegionSelectors | CSS selectors whose bounding boxes are excluded from the diff. |
customIgnoreRegions | Coordinate-based exclusion zones for ad-hoc cases. |
Other SDKs (@percy/cypress, @percy/selenium, @percy/storybook)
expose the same shape with framework-specific calling conventions -
check the matching SDK README on github.com/percy.
The Percy CLI looks for config in this order (percy-config):
"percy" block in package.json.percyrc (YAML or JSON).percy.json.percy.yaml / .percy.yml.percy.js / percy.config.jsThe first found wins, searched from CWD up to the home directory. Use this file to set project-wide defaults (viewports, percyCSS, network idle timeout). For the current schema of the snapshot block (widths array, minimum height, etc.), check the latest percy-cli release - the schema evolves with major versions and reproducing it from memory risks drift.
The canonical invocation is percy exec -- <test command>
(percy-exec):
export PERCY_TOKEN=<your project token>
percy exec -- npx playwright test
percy exec -- yarn cypress run
percy exec -- npx jestpercy exec starts a local snapshot server on port 5338 (configurable),
proxies snapshot requests from the SDK during the test run, and finalizes
the build when the wrapped command exits (percy-exec).
percy exec flagsPer percy-exec:
| Flag | Purpose |
|---|---|
--parallel | Mark the build as part of a parallel CI matrix. |
--partial | Allow the build to be marked partial (e.g. early exit). |
-P, --port <n> | Override the local server port (default 5338). |
-d, --dry-run | Capture snapshots locally without uploading. |
-h, --allowed-hostname | Restrict asset discovery to specific hostnames. |
--disallowed-hostname | Inverse of allowed; useful for blocking analytics URLs. |
-t, --network-idle-timeout <ms> | Tune asset-discovery timing for slow apps. |
--debug | Verbose logging for troubleshooting. |
PERCY_TOKEN is the only required env var (percy-cli); the
SDK no-ops when the token is absent (so tests stay green locally without
a token).
A successful Percy build appears in the Percy UI grouped by snapshot
name; visual changes between commits appear as side-by-side diffs that
require explicit approval before the build is marked passed. Percy
also integrates with PR statuses so a build with unapproved changes
shows as pending on the PR until a reviewer approves
(percy-overview).
The newer "AI Agents" mode generates natural-language summaries of visual changes and reduces noise on cosmetically-irrelevant diffs (percy-overview); this is opt-in per project.
The minimal pattern: install @percy/cli + the SDK, expose
PERCY_TOKEN as a CI secret, wrap the test command in percy exec.
# .github/workflows/visual.yml
name: visual
on:
pull_request:
push:
branches: [main]
jobs:
percy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Percy + Playwright
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
run: npx percy exec -- npx playwright testFor a parallel CI matrix (e.g. sharded Playwright tests), add --parallel
to percy exec and use Percy's parallel-build coordinator
(percy-exec).
percySnapshot options.percy exec flags and behavior.