ScreenshotNeo

BlogHow-to

How to Add Chromatic Visual Tests to a React Project

Set up Chromatic visual tests for a React project with Storybook, Vitest, Playwright, or Cypress, then automate builds safely in GitHub Actions.

By the ScreenshotNeo team4 October 20268 min read

To add Chromatic visual tests to a React project, create a Chromatic project and project token, install the chromatic development dependency, and publish your Storybook with the Chromatic CLI. For a project that already uses Vitest, Playwright, or Cypress, use Chromatic’s corresponding runner integration instead. In CI, keep the project token in a secret and choose deliberately whether visual changes should fail the job.

Choose the source of your visual tests

Chromatic can use Storybook by default or integrate with Vitest, Playwright, and Cypress. Choose the path that matches the UI states your team already maintains.

Source Choose it when What to check
Storybook Your components and visual states are represented by stories, or you want a focused component catalog. The documented quickstart requires Storybook 6.5 or later. Check Chromatic’s current Node guidance before setup.
Vitest Your visual states are already exercised by Vitest tests. The current Chromatic setup page lists Vitest 4.0.0 or later and the @vitest/browser-playwright provider.
Playwright Your existing browser tests exercise the pages and states you want to capture. Use Chromatic’s Playwright mode and follow the runner-specific setup for archive capture and upload.
Cypress Your existing UI tests are in Cypress. Use Chromatic’s Cypress mode and its runner-specific setup.

These are integration choices, not a universal ranking. Chromatic’s CLI defaults to Storybook; the other runners require their explicit mode and setup. In each case, Chromatic captures the UI archive during execution and uploads it for visual testing. See the Chromatic documentation for the runner-specific requirements.

Set up the Storybook route

  1. Create the project. Sign in to Chromatic, create a project for your React app, and copy its project token. The token identifies the Chromatic project used by the CLI and CI.
  2. Install the CLI. From the directory containing your app’s package manifest, install Chromatic as a development dependency:
npm install --save-dev chromatic

For Yarn or pnpm, use the package manager commands documented in Chromatic’s CLI guide so the dependency is recorded in the project.

  1. Publish the first build. Replace the placeholder with the project token:
npx chromatic --project-token <your-project-token>

The CLI uses the Storybook build by default, uploads it to Chromatic, and starts publishing and visual testing. The first run establishes the baseline snapshots. Later builds compare their snapshots with those baselines.

  1. Review the build. Open the build results in Chromatic and review changes. Treat the first baseline as the reference for later comparisons; it is not a review of changes against an earlier Chromatic build.

Chromatic’s Storybook quickstart documents this path for Storybook 6.5 or later. Confirm the current quickstart requirements against your Storybook and Node versions before adopting the commands in a long-lived setup.

Use Vitest, Playwright, or Cypress instead

If your React project already maintains UI tests in another runner, you can connect that runner to Chromatic rather than moving those states into Storybook solely for this integration. The CLI modes are selected with --vitest, --playwright, or --cypress.

For example, the mode selection has this shape after installing Chromatic and completing the runner-specific setup:

npx chromatic --project-token <your-project-token> --vitest
npx chromatic --project-token <your-project-token> --playwright
npx chromatic --project-token <your-project-token> --cypress

These lines illustrate which mode flag to use; they do not replace the necessary setup for each test runner. In particular, follow the current Vitest setup guide for its listed version and browser provider requirements, and the Chromatic runner documentation for Playwright and Cypress configuration. For those integrations, Chromatic captures an archive during test execution and uploads it.

Automate Chromatic with GitHub Actions

Store the project token as a GitHub Actions repository secret named CHROMATIC_PROJECT_TOKEN. Add it under the repository’s Settings → Secrets and variables → Actions. The following workflow follows Chromatic’s documented structure. Its action and Node versions reflect the cited documentation and may change; check the current guide before publishing or adopting version tags.

name: "Chromatic"
on: push

jobs:
  chromatic:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v7
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v7
        with:
          node-version: 24.20.0
      - name: Install dependencies
        run: npm ci
      - name: Run Chromatic
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

Full Git history is part of the documented checkout example. Keep the dependency installation consistent with the lockfile and package manager used by your repository. Chromatic documents using @latest, a major-version tag, or a full version tag for the Action: choose an update policy intentionally and confirm the available tags in the current GitHub Actions guide.

Choose what a visual difference does to the job

Chromatic’s CI behavior depends on the selected UI Test or UI Review setup. Its CI guide says these can return a nonzero exit code when changes are present. If your team wants the job to report changes without failing, the guide’s package script example uses --exit-zero-on-changes:

{
  "scripts": {
    "chromatic": "chromatic --exit-zero-on-changes"
  }
}

Use this only if it matches your merge policy. If a detected change must be reviewed before a job passes, keep the failure behavior and make the review step part of the normal pull request process. Chromatic can also publish pull request status checks for projects connected to a Git provider.

Protect the token on pull requests from forks

GitHub does not expose repository secrets to workflows triggered by forked repositories by default. Do not casually place the Chromatic token in workflow source to work around this: anyone able to read that file could run builds on the project, potentially consuming snapshots. Chromatic notes that a compromised token can be reset. Decide explicitly how fork contributions should be handled and keep the token in secret storage wherever it is available.

Monorepos, build directories, and large uploads

  • Separate projects: Chromatic’s Actions documentation says each Chromatic subproject needs its own token. Point each job at the correct package directory.
  • Storybook build command: Ensure the project has a build-storybook script, or specify the build script for the action. If Storybook is already built, the action can use storybookBuildDir to locate it.
  • Large Storybooks: The cited Actions guide gives a 5,000-file limit for stories and assets and recommends the zip option if the project exceeds it. Check the current guide for exact option syntax and limits.
  • Runner archive: For Vitest, Playwright, or Cypress, follow the relevant action example for retaining the captured archive as an artifact and passing it to the Chromatic action.

Or skip the browser setup

If you need a screenshot of a page rather than visual tests attached to component stories or an existing test runner, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. The API supports full-page capture, CSS selector element capture, custom viewports and device presets, and more; its API documentation lists the 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 are accepted and removed before capture; more than 60 known consent platforms, newsletter popups, and chat widgets can be removed, and each step can be turned off.
  • Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing. Responses identify the page verdict and billing status in headers.
  • An MCP server gives AI agents tools for taking screenshots, getting page information, and capturing PDFs.
  • The Free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

Troubleshooting

Symptom Likely cause What to do
The CLI cannot publish the build. The project token is missing, mistyped, or belongs to a different Chromatic project. Copy the token from the intended project and pass it to the CLI. In CI, verify the secret name and repository settings.
The Storybook route does not build. Storybook or Node may not meet the currently documented requirements, or the build command is not configured. Check the current quickstart requirements and confirm the repository can build Storybook locally.
A Vitest integration does not capture UI. The Vitest version or browser provider may not meet Chromatic’s setup requirements. Check the current Vitest guide; it lists Vitest 4.0.0 or later and @vitest/browser-playwright.
A fork pull request cannot access the token. GitHub withholds repository secrets from fork workflows by default. Keep the secret protected and choose a deliberate process for fork builds. Avoid committing the token into a workflow file.
The action runs from the wrong app in a monorepo. The working directory or token is associated with another subproject. Configure the job for the intended package, use that project’s token, and point to the correct build script or prebuilt directory.
Upload exceeds the file limit. The Storybook has more stories and assets than the documented limit. Check the current limit and configure the documented zip option for large projects.
A changed snapshot makes CI fail. The selected UI Test or UI Review behavior returns a nonzero exit for changes. Decide whether changes should block the job. Keep the default review gate or use --exit-zero-on-changes when a non-blocking result is intended.

Performance, reliability, and cost

Chromatic builds require the UI states to be rendered by Storybook or the selected test runner, then uploaded for visual testing. Reuse the project’s existing stories or tests where they cover the states you care about; avoid adding duplicate states without a review need. In CI, install from the lockfile and use a deliberate Action update policy so dependency or Action changes are visible.

The research reviewed here does not establish Chromatic pricing, build duration, or a benchmark for any runner, so this guide makes no cost or speed comparison. Check Chromatic’s current plan and usage details when estimating ongoing snapshot and CI costs. A visual test adds review work when a snapshot changes; decide whether that work should block merges and configure exit behavior accordingly.

FAQ

Does Chromatic require Storybook?

No. Storybook is the default CLI route, and Chromatic also documents Vitest, Playwright, and Cypress integrations. Each non-Storybook route has runner-specific setup.

Does the first build detect regressions?

The first build establishes the baseline. Later builds are compared against those snapshots, so review the initial reference before relying on subsequent comparisons.

Can a forked pull request run the workflow with the secret?

Repository secrets are not available to fork workflows by default. Follow a protected process for fork contributions rather than exposing the token in source.

Can a visual change pass CI?

Yes, depending on the configured UI Test or UI Review behavior. The CI guide documents nonzero exits for changes and shows --exit-zero-on-changes for teams that want changes not to fail the command.

Sources