Set up visual testing with Playwright
Swap your Playwright import for @uiverify/playwright, upload the archive your tests write, and wire CI so every pull request gets a screenshot diff. No Storybook.
Set it up with your coding agent
Paste this into Claude Code, Cursor, or any coding agent and it wires up UI Verify from these docs.
Set up UI Verify visual regression testing for my Playwright project. Follow https://uiverify.ai/docs/quickstart-playwright to install the packages and add the config. https://uiverify.ai/llms-full.txt has the same docs as one plain-text reference if you want to read them without fetching each page. Then run one build and upload it right now, locally - no CI or GitHub App needed for this - so my first build lands in the dashboard and we can confirm the setup works before wiring anything else. Use the upload command from the quickstart. Open the build page it prints in my browser so I can see the captured stories. Ask me for my UIVERIFY_API_KEY when you need it for the upload. Install the UI Verify skills for this project - the making-ui-changes playbook, the economical-visual-tests, triage, and check-visual-changes playbooks, plus the deterministic-capture guide for this framework - so you can change UI safely, author cheap stable stories, preview an edit's visual impact before pushing, and review builds yourself: npx skills add uiverify/uiverify \ --skill making-ui-changes \ --skill economical-visual-tests \ --skill triage-visual-changes \ --skill check-visual-changes \ --skill playwright-visual-testing Then add a short rule to my AGENTS.md and CLAUDE.md so you read the making-ui-changes skill before any UI change from now on: `Before changing any component, page, or styles, read the making-ui-changes skill and follow it - reuse before you create, add/update the story or capture in the same change, check the blast radius on shared components, and prove the change with a visual test.` After installing, restart this session (or reload the window) so the new skills load - you will not have them until I do. Once that first build is in and looks right, wire the GitHub Actions workflow from the quickstart so every push is checked (add UIVERIFY_API_KEY as a repository secret), and remind me to install the UI Verify GitHub App from my setup page so the check and PR comment post - that's the one step only I can do, and it isn't needed for the first upload. If this repo is public and takes pull requests from forks, use the two-workflow setup from https://uiverify.ai/docs/open-source-and-forks instead, so fork pull requests get the check too without exposing the key.
You do not need Storybook to do visual testing. If you already drive real pages with Playwright, @uiverify/playwright records an archive of what each page actually rendered, and UI Verify replays and screenshots that archive deterministically. This is how you visually test a Next.js app, a marketing site, or a live staging URL.
toHaveScreenshot(), Chromatic and Argos, see Playwright visual regression testing.1. Get a project API key
Sign up at uiverify.ai, create a project, and store its API key in CI as UIVERIFY_API_KEY.
2. Add the capture SDK and swap your import
Install the capture SDK, then swap your Playwright import so every test archives its final UI state. This import swap is the step that actually records the archive - installing the package alone does nothing. To capture specific states instead, call uiVerify.snapshot(); a test that does is not also archived at its end.
npm i -D @uiverify/playwright@1.4.0import { test, expect } from "@playwright/test";
import { test, expect } from "@uiverify/playwright";
test("checkout", async ({ page, uiVerify }) => {
await page.goto("/cart");
await page.click("#checkout");
// optional: a test that calls snapshot() is not also auto-archived
await uiVerify.snapshot("checkout");
});3. Run your tests and upload the archive
Run your Playwright suite as usual. Each test writes what it rendered into ./uiverify-archive; then upload that directory. playwright install downloads the browsers once.
npx playwright install # one-time: download the browsers
npx playwright test # writes ./uiverify-archive
UIVERIFY_API_KEY=your_key npx -y uiverify@1.8.0 upload --static-dir ./uiverify-archive4. Catch a change locally
You do not need CI or a pull request to see a diff. Change something visible on a page - a color, a label - then re-run your Playwright tests and upload again on the same commit. UI Verify diffs the new build against your first one and flags what moved, so you see the review flow before wiring anything up.
npx playwright test
UIVERIFY_API_KEY=your_key npx -y uiverify@1.8.0 upload --static-dir ./uiverify-archiveOpen the build page it prints: the changed story is waiting in the review queue, where you accept or reject it. Accepting promotes the new screenshot to the baseline for that branch.
5. Wire it into CI
name: UI Verify
on:
push:
branches: [main] # your default branch, so the first build seeds the baseline
pull_request:
jobs:
visual:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # full history so the baseline can be resolved
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- run: npx -y uiverify@1.8.0 upload --static-dir ./uiverify-archive
env:
UIVERIFY_API_KEY: ${{ secrets.UIVERIFY_API_KEY }}push trigger on your default branch matters as much as pull_request: it runs the job once on your default branch so the first build becomes the baseline every PR diffs against. Change [main] to whatever your default branch is (master, develop), or a repo whose default is not main gets a trigger that never fires. Accept that first build once, or add --auto-accept-changes to the upload on your default branch to seed it automatically. Without it, every PR shows all-new until a merge happens.npx playwright install --with-deps is required on a clean runner - without the browsers, playwright test fails before it captures anything. And keep fetch-depth: 0 so the baseline resolves against your real branch history.@playwright/test new enough for your CI machine's OS. Each Playwright release installs browsers only on the OS versions it knows, so when your runner image moves to a newer OS, an older Playwright fails at the install step with Playwright does not support chromium on <os> (Ubuntu 26.04, for example, needs 1.61 or newer). Upgrade Playwright, or pin the runner to an OS version it supports. See Troubleshooting.UI Verify: <slug> a required status check, or add the auto-rerun workflow that clears the job the moment you accept. Both are in Require the check and auto-clear the CI job.6. Install the visual-testing skills
Give your coding agent the visual-testing playbooks so it can do the work in your repo: triage a build's changes, write economical visual tests, check an edit's visual impact before pushing, and keep captures deterministic. This installs just these skills, not the whole bundle. Restart the agent session afterward so they load.
npx skills add uiverify/uiverify \
--skill making-ui-changes \
--skill economical-visual-tests \
--skill triage-visual-changes \
--skill check-visual-changes \
--skill playwright-visual-testing7. Review changes from your coding agent
Connect the UI Verify MCP and your agent can pull a build's changes into the conversation, look at each diff, read the AI judge's verdict, and accept the intended ones. See Triage visual changes from your coding agent.
claude mcp add --scope project --transport http uiverify \
https://uiverify.ai/mcpThen log in once: restart Claude Code, run /mcp, pick uiverify, and log in to UI Verify in your browser. After that the agent can reach every project in every team you are a member of. Project scope writes the server to your committed .mcp.json, so the whole team gets it, and the file holds no secret: each teammate logs in with their own account. Using Cursor, Codex, or another client? See UI Verify MCP server for coding agents for its setup.
8. Install the GitHub App
Install the UI Verify GitHub App from your project's setup page and point it at your repo, so it can post a check and a comment on each pull request. This is the one step your coding agent cannot do for you. It does not block getting started: your first upload and baselines work without it, so add it when you want the results to show up on GitHub.
Capture every test, or only some
By default every Playwright test archives its final state, so playwright test captures your whole suite. @uiverify/playwright has no file filter of its own: you scope capture with Playwright itself. To capture only a subset, name those specs (for example *.visual.spec.ts) and select them with testMatch, a project, or a --grep tag.
npx playwright test --grep @visual # only tests tagged @visual
npx playwright test tests/visual # only specs under one directoryTo keep the suite running but exclude one test from capture, request the uiVerify fixture and call uiVerify.disableAutoSnapshot(). A test that already called uiVerify.snapshot() isn't captured a second time. A test that fails is still captured, so its page shows up in the build as a change instead of dropping out of it.
test("smoke check, no screenshot", async ({ page, uiVerify }) => {
uiVerify.disableAutoSnapshot(); // opt this one test out of capture
await page.goto("/health");
});How is this different from Playwright's built-in toHaveScreenshot?
Playwright's toHaveScreenshot screenshots on the machine that runs the test and diffs against PNGs committed next to it, one set per operating system and browser. UI Verify replays an archive of each test in one pinned browser, keeps baselines off your repo, and puts the diff on the pull request for you or your coding agent to review. The full comparison, including Chromatic and Argos for Playwright, is on Playwright visual regression testing.
Deterministic Playwright captures
Stop real-page diffs that flake without a real change.
Visual testing for agents
UI Verify is visual regression testing for Playwright, Storybook and Vitest. Your coding agent sees what its UI change did and fixes it before users see it. See how it works.
Get started