Authors and runs Chromatic visual tests on Storybook, Playwright, or Cypress projects via the `chromatic` CLI; configures baselines, TurboSnap, UI Review, and CI gating; reads exit codes for change-vs-error classification. Use when the project ships visual regression coverage to Chromatic Cloud.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Chromatic is a visual testing platform built by the team behind Storybook (chromatic-overview). It works in three modes:
--playwright flag.--cypress.The CLI shape: chromatic is one binary; everything (auth, framework
choice, TurboSnap) is a flag or env var.
chromatic in devDependencies or a
chromatic.config.json at the root.npm install --save-dev chromatic(Per the Chromatic quickstart.)
The first run uploads the Storybook build, captures a snapshot of each story, and establishes those snapshots as the project baseline (quickstart):
npx chromatic --project-token <your-project-token>Subsequent runs compare new snapshots to the baseline; visual changes must be explicitly accepted in the Chromatic UI before the build passes.
Chromatic snapshots whatever your Storybook indexes, so authoring is
"add a story." Per-story knobs that affect snapshots are passed in the
story's parameters.chromatic block (e.g. viewports, delay, pauseAnimationAtEnd).
When invoked with --playwright or --cypress, the CLI captures
snapshots from your existing Playwright / Cypress test runs
(cli); no per-test code changes are required beyond running the
matching framework's archive output through Chromatic.
The canonical invocation in CI, with the token sourced from an env var (cli):
export CHROMATIC_PROJECT_TOKEN=<token>
npx chromaticUseful flags (cli):
| Flag | Effect |
|---|---|
--project-token <t> | Override the token (env var preferred). |
--playwright | Capture from Playwright runs instead of Storybook. |
--cypress | Capture from Cypress runs instead of Storybook. |
--only-changed | Enable TurboSnap (snapshot only stories affected by changed files). |
--only-story-names | Run a build limited to specific story names. |
--auto-accept-changes | Auto-accept changes on the named branch (typically used on main for the first run after a planned UI overhaul). |
--exit-zero-on-changes | Exit 0 on visual changes (still uploads, but the CI step doesn't fail). |
--exit-once-uploaded | Return as soon as the upload completes; do not wait for the snapshot pass. |
--dry-run | Skip publishing; useful for local debugging. |
--no-interactive | CI-style logging when running locally. |
--trace-changed | Show the TurboSnap dependency tree (debug). |
--list | Print the indexed stories without running them. |
--debug | Verbose logging. |
--diagnostics-file <p> | Write a JSON diagnostics dump for support. |
chromatic.config.json at the project root - config keys mirror the CLI
flags converted to kebab-case (cli):
{
"$schema": "https://www.chromatic.com/config-file.schema.json",
"onlyChanged": true,
"exitZeroOnChanges": false,
"autoAcceptChanges": "main",
"externals": ["public/**", "tokens/**"]
}externals lists glob patterns of non-bundled files that should still
trigger a TurboSnap rebuild when changed (e.g. design tokens, static
assets) (turbosnap).
Per the Chromatic CLI docs, exit codes carry semantic meaning - the gate logic should treat visual changes (1) differently from system errors (3, 21 - 23, 101 - 105, 201 - 220):
| Code | Meaning |
|---|---|
0 | Success. |
1 | Build has visual changes (review required). |
2 | Build has component (Storybook) errors. |
3 | Build failed (system error). |
4 | No stories found. |
5 - 6 | Build limited / canceled. |
11 - 12 | Account quota / payment issues. |
21 - 23 | Storybook build / load failures. |
101 - 105 | Git or dependency issues. |
201 - 220 | Network / API errors. |
254 - 255 | Invalid options / unknown error. |
Use --exit-zero-on-changes only when changes are reviewed in the
Chromatic UI (not in CI) and you want CI to remain green pending
review.
TurboSnap analyzes git history and the bundler dependency graph to identify stories affected by a PR's changes; only those stories are snapshotted, and the rest copy their baseline forward (turbosnap).
Enable via --only-changed (CLI) or onlyChanged: true
(chromatic.config.json).
(Per turbosnap.)
TurboSnap conservatively snapshots everything when any of these change (turbosnap):
package.json changes without a valid lockfile.main.js, manager.js).preview.js imports.Merge commits also trigger conservative re-testing because TurboSnap cannot know ahead of time which baseline side to compare against (turbosnap).
The minimal pattern is: install chromatic, expose
CHROMATIC_PROJECT_TOKEN as a CI secret, run the CLI, fail the job on
exit != 0 (or != 0,1 if review happens in the Chromatic UI).
# .github/workflows/chromatic.yml
name: chromatic
on:
pull_request:
push:
branches: [main]
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # required by TurboSnap
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Build Storybook + run Chromatic
env:
CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
run: npx chromatic --only-changedfetch-depth: 0 is required so TurboSnap can resolve the
PR-vs-baseline commit ancestry (turbosnap).