UI Verify
All docs
Getting started5 min readUpdated

Visual regression testing with custom screenshots

Bring custom screenshots from any tool - native, mobile, or React Native - and diff them on every pull request. No Storybook, no browser, no SDK.

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 Screenshot project.

Follow https://uiverify.ai/docs/quickstart-screenshot 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 triage-visual-changes \
  --skill check-visual-changes

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.

Some surfaces cannot be rendered in a browser: a native iOS or Android screen, a React Native app, a desktop or GPU app. For these, your own test harness already produces the pixels. A custom-screenshots project takes those finished PNGs, diffs each one against its baseline, and runs the same AI review and pull-request check as every other UI Verify project. UI Verify renders nothing here - you create the screenshots with whatever tool you like, we manage the baselines, the diff, and the review.

Prefer a complete, runnable example? The React Native example is a small Expo app that produces a screenshot per screen with Maestro and uploads them with this exact command.

1. Get a project API key

Sign up at uiverify.ai, create a project of type Custom screenshots, and store its API key in CI as UIVERIFY_API_KEY.

2. Produce your screenshots and upload the directory

Run whatever already writes your screenshots (an XCUITest run, an Espresso run, a React Native snapshot step, or any script that saves PNGs) into one directory, then upload it. Each image's id is its path under that directory with the extension dropped, so checkout/mobile/cart.png becomes the stable key checkout/mobile/cart. Keep those paths steady across runs and a screen always diffs against its own baseline.

bash
# your own harness writes PNGs to ./screenshots
UIVERIFY_API_KEY=your_key npx -y uiverify@1.7.0 upload --screenshots ./screenshots
Your first upload becomes the baseline. Determinism is on your side of the line here: because UI Verify replays nothing, whatever your harness captured is exactly what gets diffed, so pin the device, the locale, and any live data at capture time.

3. Catch a change locally

You do not need CI or a pull request to see a diff. Change something visible in a screen - a color, a label - then regenerate your screenshots 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.

bash
# regenerate the PNGs with your own harness, then upload again
UIVERIFY_API_KEY=your_key npx -y uiverify@1.7.0 upload --screenshots ./screenshots

Open the build page it prints: the changed screen is waiting in the review queue, where you accept or reject it. Accepting promotes the new screenshot to the baseline for that branch.

4. Wire it into CI

.github/workflows/visual.yml
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: <your own step that writes finished PNGs to ./screenshots>
      - run: npx -y uiverify@1.7.0 upload --screenshots ./screenshots
        env:
          UIVERIFY_API_KEY: ${{ secrets.UIVERIFY_API_KEY }}
The 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.
Keep fetch-depth: 0 so the baseline resolves against your real branch history.
Close the accept loop before you call setup done. The upload job exits non-zero on an unreviewed build, so after you accept the changes UI Verify flips its own check green but the failed Actions job stays red until it re-runs, and every accepted PR looks broken. Always set up one of the two: make 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.

5. 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.

bash
npx skills add uiverify/uiverify \
  --skill making-ui-changes \
  --skill triage-visual-changes \
  --skill check-visual-changes

6. 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. Your project setup page has this command with the key already filled in; the header is your UIVERIFY_API_KEY. See Triage visual changes from your coding agent.

bash
claude mcp add --scope project --transport http uiverify https://uiverify.ai/api/mcp \
  --header 'Authorization: Bearer ${UIVERIFY_API_KEY}'

Project scope writes it to your committed .mcp.json, so the whole team gets it. The key is referenced as the UIVERIFY_API_KEY env var (single-quoted so your shell does not expand it at add time), not baked in, so the committed file never holds the secret: each teammate sets UIVERIFY_API_KEY in their environment and Claude Code expands it at runtime.

7. 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.

Upload everything, or only the screens you changed

You decide which screens to send. Upload the whole set every run and every screen is diffed. Upload only the screens a change actually touched and the rest keep their existing baselines untouched - a partial upload is its own skip. UI Verify does not second-guess that choice, so a screen you leave out is treated as unchanged. That is the same trade a graph-based skip makes: it saves work, and it puts the decision of what changed in your hands.

When to use custom screenshots instead of a rendered project

If your UI runs in a browser, a Storybook, Playwright, or Vitest project is the better fit: UI Verify renders it in a pinned browser, so determinism is handled for you. Reach for custom screenshots when there is no browser to render - native mobile, React Native, or a custom runtime - or when a tool you already run produces the screenshots and you just want them diffed and reviewed.

Visual testing for agents

UI Verify captures your UI on every pull request and an AI judge tells an intended change from a real regression. See how it works.

Get started