Run Storybook Visual Tests with GitHub Actions
Set up Storybook visual regression checks in GitHub Actions with Chromatic, review changes safely, and understand when Vitest or the test-runner is a better fit.
To compare Storybook stories visually in GitHub Actions, use Storybook’s @chromatic-com/storybook integration and run Chromatic in CI with a project token stored as a GitHub Actions secret. It renders stories, compares their pixels with saved baselines, and reports changes for review in the pull request. Use Storybook’s Vitest addon or test-runner for render, interaction, and accessibility assertions; those tests complement visual regression rather than replacing it. Storybook visual testing docs
1. Choose the test that matches the regression
A visual test answers, “Did the rendered appearance change?” It compares pixels from a story render with a baseline. A markup snapshot instead compares HTML output, which can change without changing what a user sees. Choose the check based on what you need to catch.
| Need | Use | Checks |
|---|---|---|
| Detect visual changes across stories | Chromatic visual testing | Rendered pixels against visual baselines |
| Check story rendering, interactions, or accessibility | Storybook Vitest addon | Story tests executed through Vitest |
| Run custom tests against a built Storybook | Storybook test-runner | Tests against a running or published Storybook |
| Test full application journeys | A separate end-to-end tool such as Playwright or Cypress | User flows across the application |
A project can run more than one of these. For example, use Vitest for interaction assertions and Chromatic to review appearance changes. Storybook documents @chromatic-com/storybook for visual testing and requires Storybook 7.6 or later for that addon. Visual testing setup · Storybook testing overview
2. Add Chromatic to Storybook
- Confirm the repository’s Storybook version and package manager. The visual testing addon requires Storybook 7.6 or higher.
- Create or select a Chromatic project during setup so Storybook can associate builds with the right project.
- From the repository root, run Storybook’s documented setup command:
npx storybook@latest add @chromatic-com/storybook - Review the generated configuration and commit it. Depending on setup, configuration can be stored in
chromatic.config.json, including a project ID and optional build script name, debug setting, or zip option. - Run the configured visual test locally or through the generated package script, following the setup output. Confirm that stories render before relying on the CI check.
Chromatic is a cloud service. The project setup and CI token are part of this approach; choose a local testing route if cloud-based visual review does not fit your requirements. Storybook’s docs describe the setup and baseline review loop. Storybook visual testing
3. Run the visual check in GitHub Actions
Create a project token in the Chromatic project settings and save it in the GitHub repository or organization’s Actions secrets, for example as CHROMATIC_PROJECT_TOKEN. Do not commit the token to the workflow, source code, or a checked-in environment file.
Add the Chromatic step to the repository’s existing workflow after checkout and dependency installation. The following shows the required secret handoff and the action step; check the current Chromatic action documentation for the exact supported action version and inputs before pinning it in your repository. Node and action versions vary by project and change over time.
name: Storybook visual tests
on:
pull_request:
push:
branches: [main]
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Run Chromatic visual tests
uses: chromaui/action@v1
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
This is a starting workflow, not a universal runtime or permissions policy. Match the package manager, lockfile, Node runtime, action versions, and workflow permissions to the repository. The Chromatic integration documentation lists supported runtime environments and versions; verify its current requirements when adopting or updating the workflow. Chromatic integration requirements
Protect secrets in pull request workflows
Repository secrets are generally unavailable to workflows triggered from forks. A missing token in a forked pull request may therefore be a workflow security boundary, not a Chromatic configuration error. Avoid exposing a project token to untrusted code merely to make fork checks run. Decide whether to skip the check for forked contributions or use a carefully reviewed trusted workflow design.
Require the check before merging
Once the action reports a UI Tests check in the pull request, configure the repository’s branch protection or ruleset to require that check if visual review is part of the merge policy. Storybook recommends running visual tests in CI as changes approach merge, then inspecting changes before accepting new baselines. Visual tests in CI
4. Review visual changes and update baselines
- Open the visual test result linked from the pull request check.
- Inspect the changed stories and highlighted pixel differences. Check whether the difference is an expected design change, a rendering issue, or unrelated instability.
- For an intentional change, accept the new appearance as the baseline through the review flow.
- For an unintended change, fix the component or test conditions and rerun the workflow.
- Confirm the updated baseline is reflected in later CI runs before merging.
Do not treat every diff as a failure to suppress automatically. The review step is how the team distinguishes intended UI changes from regressions. Accepted baselines are synchronized for CI according to Storybook’s documented workflow. Baseline review guidance
5. Add Vitest story tests in GitHub Actions
If you need component story tests for rendering, interactions, or accessibility rather than pixel comparison, use the Storybook Vitest addon. A common script for the default Storybook project is:
{
"scripts": {
"test-storybook": "vitest --project=storybook"
}
}
Set up the addon and project according to the repository’s Storybook version and configuration. The project name may differ if the default project has been renamed. A corresponding workflow shape is:
name: Story tests
on:
pull_request:
push:
branches: [main]
jobs:
story-tests:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Run Storybook tests
run: npm run test-storybook
Storybook’s CI documentation includes a Playwright container/image example. Browser dependencies and resource needs depend on the selected framework and CI image, so follow the project’s addon setup rather than assuming this minimal job supplies every browser prerequisite. Storybook testing in CI
6. Use the test-runner when Vitest is not suitable
The Storybook test-runner is an alternative for custom tests or cases where a prebuilt Storybook is the target. The local-built pattern is to check out source, set up Node, install dependencies and Playwright, build Storybook, serve the static output, wait for the server, and run test-storybook. This involves more setup because the workflow must manage the build and server lifecycle.
Another documented pattern runs after a deployment-status event and targets a published Storybook URL. The cited Storybook 8 example requires the published Storybook to be publicly available. Do not expose a private Storybook solely to make that pattern work without considering access controls. Test-runner guide
7. Reliability, runtime, and cost considerations
- Visual stability: Keep story data and rendering conditions predictable. Investigate intermittent diffs before accepting a baseline; repeated noise makes meaningful regressions harder to spot.
- CI resources: Browser rendering uses CPU and memory. Large story sets or constrained runners can run slowly or time out. Start with the required checks and increase resources or split work only after observing the repository’s needs.
- Service dependency: Chromatic visual testing uses a cloud service and project token. The Vitest addon and test-runner are separate paths with their own runtime and browser setup.
- Cost: The supplied official documentation establishes the service and setup, but does not provide pricing details. Check the service’s current plan and terms before adopting it; do not infer cost from the workflow YAML.
- Version drift: Storybook docs cited here span versions, and supported action syntax and runtime requirements can change. Verify current documentation before pinning versions or upgrading.
- Merge policy: A required check prevents merging until its result is satisfied, so document the baseline review process and ensure maintainers can resolve intentional changes.
8. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Chromatic reports a missing or invalid token | The secret name does not match, the token is not configured for the repository, or the workflow context cannot access secrets. | Check the repository secret and workflow reference. For fork pull requests, keep in mind that secrets are not normally passed to untrusted workflows. |
| The addon setup command fails or the integration is incompatible | The project’s Storybook version or package setup does not match the addon requirements. | Check the installed Storybook version and use the documented 7.6+ requirement for the visual testing addon. Resolve package-manager or framework setup issues before rerunning. |
| A pull request has no visual test result | The workflow did not trigger, the job was skipped, or the action step failed before reporting. | Inspect the Actions run, event filters, secret availability, and action logs. Confirm the workflow runs for the relevant branch and pull request events. |
| Visual diffs appear on every run | Rendering inputs or environment conditions may vary, or the change is real and the baseline is outdated. | Inspect the highlighted stories and stabilize their inputs. Accept only intentional visual changes; fix unintended changes and rerun. |
| Vitest failure links point to localhost | A localhost URL from the runner is not reachable in CI or by reviewers. | Publish the Storybook and provide its URL through SB_URL when useful for debugging, as described in Storybook’s CI guidance. |
| Test-runner job times out or runs out of memory | A large story count or low-memory runner can exceed available resources. | Measure the workload and try lower parallelism, such as --maxWorkers=2, as a diagnostic. Increase resources or split the work if needed. |
| Markup snapshot passes but a visible regression is missed | Markup snapshots do not compare the rendered pixels. | Use visual testing for appearance changes; keep markup assertions for the structural output they are designed to check. |
For exact current setup and compatibility details, consult Storybook’s CI guide, test-runner guide, and Chromatic integration page.
Or skip the browser setup
Storybook visual regression checks compare component stories in CI. If your workflow also needs screenshots of live websites, ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. It does not replace story-baseline testing, but it can return a website capture from one request:
ScreenshotNeo API documentation
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo removes cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. 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 and get 1,000 screenshots a month free, with no card.
FAQ
Does a visual test replace component interaction tests?
No. Pixel comparison catches rendered appearance changes; use story tests for interaction, rendering assertions, and accessibility checks.
Can I use Chromatic only on pull requests?
Yes. Configure the workflow events to match your review process, and ensure the check runs before merge if your repository requires it.
Do all Storybook test approaches need a project token?
The Chromatic cloud visual workflow uses a project token. The Vitest addon and test-runner have different setup and do not use that Chromatic token as their test invocation.
Should every visual difference be accepted?
No. Review each difference, accept intentional UI changes as baselines, and correct unintended changes before merging.


