tldr: Chromatic, built by the Storybook team, captures pixel-perfect snapshots of every component story and flags visual changes before they reach production. It's the fastest way to add visual regression testing to a component-driven codebase.
The problem with testing UIs after they're assembled
Most visual regression testing happens at the page level. You render a full page in a browser, take a screenshot, compare it against a baseline. Tools like Playwright and Cypress handle this well.
But page-level visual tests have a blind spot. By the time a component is rendered inside a page, it's influenced by layout, global CSS, data from APIs, and the state of every sibling component. If a button's padding is off by 4 pixels, you might catch it. Or you might not, because the surrounding content shifts attention away from the change.
Component-level visual regression testing solves this. You isolate each component, render it in every meaningful state, and snapshot it. A padding change on a button is immediately visible when the button is the only thing in the frame.
This is what Storybook was built for. And Chromatic is the visual testing layer that sits on top of it.
What Chromatic actually does
Chromatic is a cloud service made by the same team behind Storybook. This matters. It's not a third-party integration bolted onto Storybook's API. It's a first-party tool built with full knowledge of Storybook internals.
Here's what happens when you run Chromatic:
- It builds your Storybook.
- It uploads the build to Chromatic's cloud infrastructure.
- It renders every story in a real browser (Chrome by default, with Firefox and Safari available).
- It captures pixel-perfect snapshots of each story.
- It compares those snapshots against the accepted baseline.
- It flags any visual differences and opens them for review.
The key word is "pixel-perfect." Chromatic doesn't approximate rendering. It captures the actual pixels your component produces, including fonts, images, SVGs, CSS transitions (paused at the right frame), and any other visual asset.
Why Chromatic over generic screenshot tools
You could take screenshots of Storybook stories with Playwright and compare them yourself. Teams have built internal tools to do exactly this. It works, but you end up reinventing a lot.
Chromatic handles the infrastructure you'd otherwise build: cloud rendering across real browsers, smart baselining per branch, a review UI for accepting or rejecting changes, PR status checks, and TurboSnap to avoid re-testing unchanged stories. You also get parallelized rendering. Chromatic captures hundreds of stories concurrently in their cloud, which is significantly faster than running a local headless browser sequentially.
The alternative is maintaining your own screenshot infrastructure: screenshot capture scripts, baseline storage, diffing algorithms, a review interface, and CI integration. Most teams that try this eventually move to Chromatic or a similar service once the maintenance burden becomes clear.
Setting up Chromatic in 5 minutes
If you already have Storybook in your project, adding Chromatic is fast.
Install and run
npm install --save-dev chromatic
Then run it with your project token:
npx chromatic --project-token=chpt_xxxxxxxxxxxx
That's it for your first run. Chromatic builds your Storybook, uploads it, captures every story, and establishes your baselines.
You get your project token from chromatic.com after creating a project. Free tier is available for open source projects with unlimited snapshots.
CI integration
Running Chromatic locally works for testing. For real workflows, you want it in CI. Here's a GitHub Actions example:
# .github/workflows/chromatic.yml
name: Chromatic
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
The fetch-depth: 0 is important. Chromatic uses git history to determine which stories changed and only snapshots those. This keeps snapshot usage efficient. On a project with 500 stories, a typical PR might only trigger 20-30 snapshots instead of the full set.
Configuration with chromatic.config.json
For more control, add a config file to your project root:
{
"projectToken": "chpt_xxxxxxxxxxxx",
"buildScriptName": "build-storybook",
"onlyChanged": true,
"externals": ["public/fonts/**"],
"skip": "dependabot/**"
}
The onlyChanged flag is enabled by default. It tells Chromatic to use git diffing and dependency tracking to only snapshot stories affected by your changes. externals tells it to also watch for changes in external files like fonts or images that might affect rendering.
The review workflow
Chromatic isn't just a snapshot tool. It's built around a review workflow that fits into your PR process.
Here's how it works in practice:
- Developer pushes code. CI triggers a Chromatic build.
- Chromatic detects changes. It compares new snapshots against the baselines for the branch.
- Team reviews changes. Chromatic posts a status check on the PR with a link to the visual review dashboard.
- Accept or reject. Reviewers inspect each changed component side-by-side (baseline vs. new) and either accept the change as intentional or reject it as a bug.
- Baselines update. Accepted changes become the new baselines.
The review dashboard shows a diff overlay. You can toggle between side-by-side view, overlay view, and a highlight view that marks changed pixels in green. For subtle changes (a 1-pixel border shift, a font-weight difference), the highlight view is invaluable.
Notifications go out when unexpected changes are detected. You can route these to Slack, email, or your project management tool. If someone merges a dependency update that accidentally changes the rendering of 40 components, the team knows immediately.
Writing stories for visual testing
Not all Storybook stories make good visual tests. Visual testing works best when stories are deterministic. That means: same input, same output, every time.
Good stories for VRT
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Click me',
},
};
export const Disabled: Story = {
args: {
variant: 'primary',
children: 'Click me',
disabled: true,
},
};
export const Loading: Story = {
args: {
variant: 'primary',
children: 'Click me',
loading: true,
},
};
Each story represents one visual state. The component receives static props. No randomness. No external data fetching.
Handling dynamic content
If a component depends on API data, mock it:
// UserProfile.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { UserProfile } from './UserProfile';
const meta: Meta<typeof UserProfile> = {
component: UserProfile,
};
export default meta;
type Story = StoryObj<typeof UserProfile>;
export const Default: Story = {
args: {
user: {
name: 'Jane Doe',
email: 'jane@example.com',
avatar: '/test-fixtures/avatar.png',
},
},
};
export const LongName: Story = {
args: {
user: {
name: 'Bartholomew Christopherson-Williamsworth III',
email: 'bart@example.com',
avatar: '/test-fixtures/avatar.png',
},
},
};
The LongName story is the kind of edge case visual testing catches. Does the name overflow? Does it truncate with an ellipsis? Does it wrap to a second line? You'll see it in the snapshot.
Handling animations
Chromatic automatically pauses CSS animations and waits for them to settle before capturing. For JavaScript-driven animations (Framer Motion, GSAP), you might need to disable them in your Storybook test configuration:
// .storybook/preview.ts
import { Preview } from '@storybook/react';
const preview: Preview = {
parameters: {
chromatic: {
pauseAnimationAtEnd: true,
},
},
};
export default preview;
You can also set delay on a per-story basis if a component needs time to reach its final visual state:
export const WithTransition: Story = {
args: { open: true },
parameters: {
chromatic: { delay: 500 },
},
};
Cross-browser and multi-viewport testing
Chromatic supports Chrome, Firefox, and Safari rendering. You can enable these at the project level or per-story.
// .storybook/preview.ts
const preview: Preview = {
parameters: {
chromatic: {
viewports: [375, 768, 1280],
forcedColors: 'active', // test Windows High Contrast mode
},
},
};
This means every story gets captured at three viewport widths across up to three browsers. A project with 200 stories, 3 viewports, and 2 browsers generates 1,200 snapshots per build. That sounds like a lot, but Chromatic's onlyChanged feature means most builds only process a fraction of that.
For responsive components, multi-viewport snapshots are critical. A navigation bar that looks perfect at 1280px might collapse incorrectly at 375px. Without multi-viewport VRT, you'd only catch this during manual testing or after a user reports it.
Theme testing
If your component library supports light and dark themes, you can capture both:
// .storybook/preview.ts
import { withTheme } from './decorators';
const preview: Preview = {
decorators: [withTheme],
parameters: {
chromatic: {
modes: {
light: { theme: 'light' },
dark: { theme: 'dark' },
},
},
},
};
Now every story is captured in both themes. Dark mode regressions are notoriously hard to catch in code review. A text color that has sufficient contrast on a white background might become invisible on a dark background. Chromatic catches this automatically.
Applitools Eyes for Storybook: the alternative
Chromatic isn't the only option for Storybook visual regression testing. In January 2026, Applitools released Eyes 10.22 with a dedicated Storybook Addon. It's a direct competitor.
Here's how they compare:
| Feature | Chromatic | Applitools Eyes 10.22 |
|---|---|---|
| Integration | First-party (Storybook team) | Third-party addon |
| Comparison method | Pixel-perfect diffing | AI-powered visual AI (ignores anti-aliasing, minor rendering differences) |
| Cross-browser | Chrome, Firefox, Safari | Chrome, Firefox, Safari, Edge, IE11 |
| Review workflow | Built-in accept/reject with PR integration | Applitools Dashboard with batch grouping |
| Pricing model | Per snapshot | Per checkpoint |
| Free tier | Open source projects (unlimited) | Limited free tier |
| Setup | npx chromatic | npx eyes-storybook |
The biggest difference is the comparison algorithm. Chromatic does pixel-level diffing. If a single pixel changes, it flags it. This is precise but can produce false positives from font rendering differences across environments.
Applitools uses Visual AI, which understands the structure of the page and ignores rendering noise (sub-pixel shifts, anti-aliasing differences). This reduces false positives but adds a layer of abstraction between you and the actual pixels.
For design systems where pixel-perfection matters, Chromatic's approach is better. For applications where you care about "does this look right" rather than "is every pixel identical," Applitools may produce fewer noisy diffs.
Setting up Applitools Eyes for Storybook
npm install --save-dev @applitools/eyes-storybook
Then run:
npx eyes-storybook
Configuration goes in applitools.config.js:
// applitools.config.js
module.exports = {
concurrency: 10,
browser: [
{ width: 1280, height: 720, name: 'chrome' },
{ width: 1280, height: 720, name: 'firefox' },
{ width: 375, height: 812, name: 'chrome', deviceName: 'iPhone X' },
],
batchName: 'Storybook Components',
};
The workflow is similar. Push code, CI runs eyes-storybook, Applitools captures and compares, team reviews in the Applitools dashboard. The main difference is that review happens in Applitools' platform rather than being tightly integrated with your PR workflow.
One advantage Applitools has: batch grouping. When a design token change affects 100 components, Applitools groups them into a single batch for review. You can accept or reject the entire batch. Chromatic also supports batch accepting, but Applitools' grouping by root cause is more intelligent in this scenario.
The trade-off is ecosystem lock-in. Chromatic is tightly integrated with Storybook, which means better story-level features. Applitools is framework-agnostic, which means you can use the same platform for Storybook components, Playwright page tests, and Cypress integration tests. If you're already using Applitools for page-level testing, adding the Storybook addon keeps everything in one dashboard.
Component VRT vs. page-level VRT
This is the question that comes up most often. Do you need component-level visual testing, page-level visual testing, or both?
Component VRT (Storybook + Chromatic)
Tests components in isolation. Each component is rendered with controlled props in a clean environment. No interference from layout, global state, or other components.
Catches: Styling regressions in individual components. Broken states (hover, disabled, loading, error). Responsive issues at the component level. Theme inconsistencies. Typography and spacing bugs.
Misses: Integration issues. How components interact when composed together. Layout shifts caused by data from real APIs. Full-page visual regressions that only appear in context.
Page-level VRT (Playwright, Cypress, Percy)
Tests full pages in a real application. The page is loaded with actual routing, data, and component composition.
Catches: Layout regressions. Spacing issues between components. Data-driven visual changes. Full-page responsive behavior. Header/footer/sidebar integration issues.
Misses: Subtle component-level changes that get lost in the noise of a full page. Edge case component states that don't appear in normal page flows.
The right approach: use both
The best teams run both layers. Component VRT catches issues early, at the point of authoring. Page-level VRT catches integration issues that only appear in the assembled application.
Here's a practical split:
- Component VRT with Chromatic: Run on every PR. Covers your design system and shared components. Catches regressions before code is merged. Fast feedback loop.
- Page-level VRT with Playwright or Percy: Run on staging or after merge. Covers critical user-facing pages. Catches integration issues.
- E2E functional testing: Covers user flows that go beyond visuals. Login, checkout, data submission. This is where tools like Bug0 Studio complement visual testing. Visual tests confirm the UI looks right. E2E tests confirm it works right.
If your team is choosing only one layer, start with component VRT. It's easier to set up (you already have Storybook), provides faster feedback, and catches the most common class of visual bugs.
When Storybook VRT is the wrong choice
Storybook visual regression testing works best for component libraries and design systems. It's less useful in some situations.
No Storybook in the project. If your team doesn't use Storybook, adding it purely for visual testing is a lot of overhead. You need to write stories for every component. That's a significant upfront investment. Consider page-level VRT with Playwright instead.
Mostly page-level concerns. If your visual bugs tend to be layout issues (sidebar overlapping content, footer in the wrong place, hero image not loading), component VRT won't catch them. Page-level tools are the right fit.
Highly dynamic content. If components render user-generated content, real-time data, or randomized elements, making deterministic stories is painful. You'll spend more time mocking data than writing actual tests.
Small team, limited bandwidth. If your team has no dedicated QA and limited engineering bandwidth for test infrastructure, a managed QA service might be more practical than maintaining both Storybook stories and visual testing infrastructure.
Optimizing Chromatic for large projects
As your component library grows, snapshot costs and build times increase. Here are practical ways to keep both under control.
Use TurboSnap
TurboSnap is Chromatic's intelligent diffing feature. It traces the dependency graph of your stories and only captures snapshots for stories affected by the current change. On large projects, this reduces snapshot usage by 60-90%.
It's enabled by default when you use onlyChanged: true in your config. Make sure your CI step includes fetch-depth: 0 so Chromatic has full git history to work with.
Skip stories that don't need VRT
Not every story needs visual testing. Documentation stories, playground stories, and stories that exist for developer convenience can be excluded:
export const Playground: Story = {
parameters: {
chromatic: { disableSnapshot: true },
},
};
Batch related changes
If you're doing a large refactor (updating a design token, changing a font), expect hundreds of changes in a single build. Review these in batch. Chromatic's dashboard lets you accept all changes at once when the change is intentional and global.
Set sensible thresholds
For components where minor rendering differences are acceptable (user avatars, images with slight compression variations), you can set a diff threshold:
export const Avatar: Story = {
parameters: {
chromatic: { diffThreshold: 0.2 },
},
};
A diffThreshold of 0.2 means Chromatic ignores changes where less than 20% of pixels differ. Use this sparingly. The whole point of VRT is catching small changes.
Chromatic pricing and plans
Chromatic offers a tiered pricing model:
- Free: 5,000 snapshots per month. Unlimited collaborators. Good for small projects or proof-of-concept.
- Pro: Starts at $149/month for 35,000 snapshots. Cross-browser testing, UI Review, and UI Test features included.
- Enterprise: Custom pricing. SSO, SLA, dedicated support.
- Open Source: Free. Unlimited snapshots for qualifying open source projects.
Snapshots are the billing unit. One story captured in one browser at one viewport equals one snapshot. A story captured in 3 browsers at 3 viewports equals 9 snapshots. TurboSnap significantly reduces how many snapshots you use per build.
For context, a project with 300 stories running 10 builds per day with TurboSnap might use 3,000-5,000 snapshots per month. Well within the free tier for small projects.
Integrating with your existing visual regression testing tools
Chromatic doesn't have to replace your existing visual testing setup. It layers on top.
A common stack:
- Chromatic for component-level VRT in Storybook.
- Percy or Playwright screenshots for page-level VRT.
- Bug0 Studio or similar for E2E functional tests that verify user flows work correctly.
Each layer catches different categories of bugs. Component VRT is your first line of defense. Page-level VRT is your integration safety net. E2E testing confirms everything works together for the end user.
For teams working with React or Angular component libraries, the Storybook layer is particularly valuable. These frameworks encourage component-driven architecture, and Storybook is already the standard tool for developing and documenting components. Adding Chromatic is a natural extension.
What visual regression testing looks like in 2026
The visual regression testing space has matured significantly. A few trends worth noting:
AI-powered comparison is becoming standard. Chromatic still uses pixel-level diffing, but Applitools' Visual AI approach is influencing the industry. Expect Chromatic to add intelligent diffing in the future. The goal is fewer false positives without sacrificing accuracy.
Component testing and page testing are converging. Storybook's test runner already supports interaction testing inside stories. Chromatic can capture snapshots at specific interaction states. The line between "component test" and "integration test" is blurring.
AI is reshaping UI testing broadly. Visual regression testing is one piece. Agentic AI testing tools are emerging that can navigate full applications, detect visual anomalies, and adapt to UI changes without scripts. The combination of component VRT for precision and AI-driven E2E for coverage is where the industry is heading.
Design system adoption drives component VRT adoption. As more teams formalize their component libraries, the value of testing those components in isolation grows. A design system with 500 components and 2,000 stories needs automated visual testing. Manual review doesn't scale. Chromatic was built for exactly this use case.
FAQs
What is Storybook visual regression testing?
Storybook visual regression testing captures screenshots of your components in isolation (via Storybook stories) and compares them against approved baselines. When a component's appearance changes, the test flags the difference for review. This catches styling regressions, broken states, and unintended design changes before they ship to production.
How does Chromatic compare to Percy for visual regression testing?
Chromatic is purpose-built for Storybook. It understands stories natively and tests components in isolation. Percy is a general-purpose visual testing platform that works with any browser-based tool, including Storybook, Playwright, and Cypress. Use Chromatic for component-level VRT in Storybook. Use Percy when you need page-level VRT or work across multiple frameworks.
Is Chromatic free for open source projects?
Yes. Chromatic offers a free plan for qualifying open source projects with unlimited snapshots. For commercial projects, the free tier includes 5,000 snapshots per month. Paid plans start at $149/month for 35,000 snapshots.
Can I use Chromatic without Storybook?
No. Chromatic requires Storybook as its foundation. Your components must have stories to be tested. If you don't use Storybook and don't plan to, consider Playwright visual testing or Cypress visual testing for page-level visual regression testing instead.
How does the Applitools Storybook addon compare to Chromatic?
Applitools Eyes 10.22 (released January 2026) offers a Storybook addon that competes directly with Chromatic. The main difference is comparison approach: Chromatic uses pixel-perfect diffing while Applitools uses AI-powered Visual AI that ignores rendering noise. Chromatic has tighter Storybook integration (same team). Applitools has broader cross-browser support including Edge and IE11, and handles anti-aliasing differences more gracefully.
Do I need both component VRT and page-level VRT?
Ideally, yes. Component VRT (Storybook + Chromatic) catches regressions early in isolated components. Page-level VRT (Playwright, Percy) catches integration issues when components are composed into full pages. If you can only pick one, start with component VRT. It provides faster feedback and catches the most common visual bugs.
How many snapshots does a typical project use per month?
It depends on project size, build frequency, and TurboSnap effectiveness. A project with 300 stories running 10 CI builds per day with TurboSnap enabled typically uses 3,000-5,000 snapshots per month. Without TurboSnap, the same project might use 30,000-50,000 snapshots. TurboSnap reduces usage by 60-90% by only snapshotting stories affected by each change.
How do I reduce false positives in Storybook visual regression testing?
Three strategies. First, make stories deterministic: mock API data, use fixed dates, disable animations, and use consistent test fixtures for images. Second, use Chromatic's diffThreshold parameter for components that legitimately vary (user avatars, dynamic images). Third, consider Applitools if anti-aliasing and font rendering differences across environments create persistent noise in pixel-level diffing.