Migrate from Chromatic
A step-by-step guide for teams switching from Chromatic to pxdiff. Most migrations take under 10 minutes — replace the CLI, swap one env var, and your existing Storybook parameters keep working.
1. Create a pxdiff project
Section titled “1. Create a pxdiff project”Sign up at pxdiff.com and create an organization and project. Then create an API key and set it as a repository secret named PXDIFF_API_KEY.
2. Install the CLI
Section titled “2. Install the CLI”Replace the chromatic package with @pxdiff/cli:
npm uninstall chromaticnpm install -D @pxdiff/cliOr install globally:
npm install -g @pxdiff/cli3. Update CI environment variables
Section titled “3. Update CI environment variables”Replace your Chromatic project token with a pxdiff API key:
env: CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} PXDIFF_API_KEY: ${{ secrets.PXDIFF_API_KEY }}4. Update your CI workflow
Section titled “4. Update your CI workflow”Option A: GitHub Action (recommended)
Section titled “Option A: GitHub Action (recommended)”Replace the Chromatic action with pxdiff/storybook:
- name: Build Storybook run: npm run build-storybook
- name: Chromatic uses: chromaui/action@latest with: projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}- name: pxdiff uses: pxdiff/storybook@v1 with: api-key: ${{ secrets.PXDIFF_API_KEY }} source: ./storybook-staticSee Storybook Action reference for all inputs and outputs.
Option B: CLI
Section titled “Option B: CLI”Replace the npx chromatic command:
- run: npm run build-storybook- run: npx chromatic --storybook-build-dir ./storybook-static- run: | pxdiff storybook ./storybook-static pxdiff diff env: PXDIFF_API_KEY: ${{ secrets.PXDIFF_API_KEY }}5. Keep your Storybook parameters
Section titled “5. Keep your Storybook parameters”pxdiff reads chromatic.* parameters as a fallback, so your existing story configuration keeps working without changes:
| Chromatic parameter | pxdiff equivalent | Fallback? |
|---|---|---|
chromatic.delay | pxdiff.delay | Yes |
chromatic.viewports | pxdiff.viewports | Yes |
chromatic.modes | pxdiff.modes | Yes |
chromatic.disableSnapshot | pxdiff.disable | Yes |
chromatic.cropToViewport | pxdiff.cropToViewport | Yes |
chromatic.cssSelector | pxdiff.selector | Yes |
chromatic.ignoreSelectors | pxdiff.ignoreSelectors | Yes |
chromatic.diffThreshold | --threshold flag | Extracted, applied per-job |
You can migrate parameters to the pxdiff namespace at your own pace, or leave them as-is.
// These both work:parameters: { chromatic: { delay: 500 },}
parameters: { pxdiff: { delay: 500 },}If both namespaces are present, pxdiff takes precedence.
6. Replace isChromatic()
Section titled “6. Replace isChromatic()”If you use Chromatic’s isChromatic() helper to hide dynamic content during captures, replace the import with pxdiff’s isCapturing():
import { isChromatic } from "chromatic/isChromatic";import { isCapturing } from "@pxdiff/cli/storybook";
const showClock = !isChromatic();const showClock = !isCapturing();isCapturing() checks for the same chromatic=true URL parameter that pxdiff appends to story URLs during capture. It’s SSR-safe and has no dependencies.
7. data-chromatic="ignore" still works
Section titled “7. data-chromatic="ignore" still works”Elements marked with data-chromatic="ignore" are hidden during captures, just like data-pxdiff="ignore":
<!-- Both attributes work --><div data-chromatic="ignore">dynamic content</div><div data-pxdiff="ignore">dynamic content</div>Concept mapping
Section titled “Concept mapping”| Chromatic | pxdiff | Description |
|---|---|---|
| Build | Capture | A set of screenshots taken at a point in time |
| Test | Diff | Comparing a capture against baselines |
| Accept | Approve | Promoting a screenshot to become the new baseline |
| Baseline | Baseline | The expected screenshot for comparison |
CHROMATIC_PROJECT_TOKEN | PXDIFF_API_KEY | CI authentication |
chromatic.config.json | (none) | pxdiff uses CLI flags and env vars only |
npx chromatic | pxdiff storybook + pxdiff diff | CLI entry points |
chromaui/action | pxdiff/storybook | GitHub Action |
What works the same
Section titled “What works the same”- Approvals and baselines — approve snapshots in the review UI, and they become baselines for future diffs. Carry-forward works automatically for snapshots not captured in the current run.
- GitHub check runs — pxdiff creates status checks on your pull requests, just like Chromatic.
- Pixel-level diffing — pxdiff uses the same diffing library (pixelmatch) at the same threshold (0.063) as Chromatic. Your diffs will look identical.
- Managed browser fleet — screenshots are captured in cloud Chromium browsers, not on your CI runner. Results are deterministic across environments. Captures take a few minutes regardless of snapshot count — same as Chromatic.
- Interaction testing — Storybook play functions run to completion before capture.
What’s different
Section titled “What’s different”- One workflow, not two — Chromatic splits visual testing into “Tests” (per-snapshot approvals that update baselines) and “Reviews” (all-or-nothing approvals that don’t update baselines). pxdiff has one workflow: every diff lets you approve snapshots individually, and approvals always update baselines. No mode to choose, no confusion.
- Stacked PRs and flexible baselines — Chromatic can’t resolve baselines when an intermediate branch is missing a capture, making stacked PRs painful — you’d need to run Chromatic on every commit in the stack to keep baselines connected. pxdiff resolves baselines from the merge-base of any ref, so stacked branches work naturally without extra captures.
- Credit-based pricing — pxdiff charges per screenshot rather than monthly tiers with overage fees. You buy credits and spend them as you go. No surprise bills.
- No TurboSnap — pxdiff captures all stories on every run. TurboSnap-style dependency analysis is on the roadmap.
- First-class local mode — run
pxdiff storybook ./storybook-static --localto capture and diff locally without affecting team baselines. Chromatic only supports local development through a Storybook plugin — pxdiff supports it from the CLI for any integration. - No config file — pxdiff doesn’t use a config file. All configuration is via CLI flags and environment variables.
- Framework-agnostic — pxdiff isn’t limited to Storybook. You can test any URL, upload any PNG, or use native Playwright and Vitest plugins.
CLI flag mapping
Section titled “CLI flag mapping”Common Chromatic CLI flags and their pxdiff equivalents:
| Chromatic | pxdiff | Notes |
|---|---|---|
--project-token | PXDIFF_API_KEY env var | pxdiff uses an env var, not a flag |
--storybook-build-dir | first positional arg | pxdiff storybook ./storybook-static |
--auto-accept-changes | --auto-baseline | Set baselines from captured screenshots (no diff) |
--only-changed | (not yet available) | TurboSnap equivalent, on the roadmap |
--skip | --filter (inverted) | Filter stories by glob pattern |
--exit-zero-on-changes | (check exit code) | pxdiff exits 0 on pass, 1 on changes |
--branch-name | --branch | Override detected branch |
--patch-build | --base | Compare against a specific ref |