How to Fix Chromatic Snapshots That Differ Between Local and CI
Find why Chromatic snapshots differ between local and CI with trace-led checks for resources, fonts, data, timing, browser, viewport, and CI metadata.
When Chromatic snapshots differ between local and CI, treat the snapshot as the result of Chromatic’s cloud capture environment, not as a screenshot of the local Storybook Canvas. Start with the affected build’s trace: inspect network requests, console logs, archived DOM, viewport, and clip metadata. Then make fonts, data, dates, randomness, and animation state deterministic; confirm the browser, viewport, and device pixel ratio (DPR); and verify CI token and build metadata. Chromatic compares a new snapshot with the previous baseline for that test, so first establish which capture and baseline you are comparing. Chromatic snapshots documentation
1. Establish exactly what differs
- Open the affected test or story and its build. Record the test name, build, browser, viewport, and whether the difference is repeatable or intermittent.
- Compare the Chromatic Snapshot image with Canvas, but do not assume they are equivalent artifacts: Canvas is interactive and live-rendered, while the snapshot is captured in Chromatic’s cloud browser.
- Identify the shape of the difference: missing content, shifted text, different styles, a responsive layout change, a different animation frame, or a broad pixel diff.
- Note any build or browser infrastructure change that coincides with the first changed snapshot.
A snapshot can differ because JavaScript execution is blocked during capture or because the component renders differently when isChromatic() is true. These are possible causes to investigate, not proof of what happened in a particular build. Chromatic snapshots documentation
2. Use the trace to find evidence
Open the trace attached to the affected build or unstable test before changing component code. It provides network requests, console logs, archived DOM, and capture metadata including viewport and clip rectangle. Chromatic trace viewer documentation
- Network: Find failed, blocked, or slow font, stylesheet, script, and image requests. Check response status, content, and MIME type. A request that succeeds locally may be blocked in the capture environment or by access controls.
- Console: Look for runtime errors that prevent rendering or leave the story in a partial state.
- Archived DOM and styles: Determine whether an element never appeared or appeared with different computed styles.
- Viewport and clip: Check the actual capture dimensions and clip rectangle when elements are missing, cut off, or positioned unexpectedly.
Keep a short record of the observations: test/story, build, browser, viewport, DPR, failed or late resources, console errors, and relevant DOM or style differences. This makes each fix traceable to evidence.
3. Stabilize fonts and other resources
Font fallback is a common explanation for text alignment differences: another font changes glyph widths, line wrapping, baselines, and therefore layout. Check the trace to confirm the intended web font loaded before adjusting spacing or alignment.
- Prefer stable local or static assets over an unpredictable remote source where feasible.
- Serve web fonts reliably and preload them when appropriate. Verify that Chromatic can reach protected assets through any firewall or access rules.
- Confirm the response is the expected font or asset, not an HTML error page returned with an unexpected status or MIME type.
- For unwrapped text inside a flex parent, consider wrapping the text in an element. Anonymous flex items have sizing and baseline behavior affected by font metrics, and a wrapper gives CSS a consistent target.
Do not add arbitrary spacing to compensate for a missing font: it can hide the symptom locally while leaving the cloud capture dependent on fallback behavior. Chromatic’s unstable-test guide discusses font and text alignment diagnostics. Unstable tests debugging
4. Make inputs and rendered state deterministic
A visual test is repeatable only when its inputs and state are repeatable. Fix or seed random values, control the current date and time when they affect the UI, and make mocked API data available before capture.
- Use fixed fixtures or seeded randomness for generated IDs, charts, avatars, and sample records.
- Mock time for relative labels, calendars, countdowns, and time-sensitive status.
- For MSW, verify Storybook initialization, handlers, and versions. Check warnings in a locally built Storybook as well as the CI run.
- Use interaction assertions to establish that the expected state has been reached before capture.
- If content is asynchronously rendered, wait for a meaningful selector or interaction state instead of guessing with a long sleep.
A delay is reasonable only when a known, deterministic render needs a settling interval. It should not conceal a race or a state that never becomes stable. See the unstable tests guide for the documented debugging approach.
5. Handle animation according to how it runs
Chromatic says it pauses CSS animations and transitions, videos, and GIFs during snapshots, but it cannot automatically stop JavaScript-driven animations. As Chromatic’s Snapshots documentation puts it: “Chromatic proactively pauses CSS animations/transitions, videos and GIFs to prevent false positives.” The same documentation says teams are responsible for pausing JavaScript-driven animations.
- For JavaScript-driven motion, make the story render a stable state or pause the animation in the test.
- If the desired image is a particular completed state, wait for an interaction or state assertion that proves it has arrived.
- Use a documented delay only when the animation duration and final state are known and repeatable.
- For intentionally captured animation behavior, consult Chromatic’s animations documentation and define which frame or state is expected.
6. Compare the same browser, viewport, and DPR
Check the browser and viewport associated with the snapshot, and read any DPR notice in the comparison. Chromatic keeps browser-specific baselines; a baseline from one browser should not be treated as an identical rendering target for another. Browser infrastructure upgrades can also produce subtle appearance changes. Chromatic browser documentation
- Confirm local and cloud views use the intended viewport and responsive mode.
- Use the trace’s viewport and clip metadata to diagnose capture dimensions rather than inferring them from Canvas.
- Chromatic’s Snapshots documentation accessed in 2026 describes Capture 9 as using DPR 2.0. A DPR 2.0 versus DPR 1.0 comparison is flagged as changed, even if layout is otherwise identical.
- The documentation notes that some unusually tall or wide Firefox and Safari snapshots can fall back to DPR 1.0 due to image-dimension limits. Check the notice before treating a broad diff as a CSS regression.
- Chromatic’s unstable-test guide documents a 900px default viewport height in the case where it cannot detect a natural height for the outermost DOM element.
Capture behavior and infrastructure can evolve, so use the metadata and notices for the specific build rather than assuming a value from another run. Snapshots · Unstable tests
7. Verify CI configuration and commit identity
Once the trace suggests the rendering itself is healthy, check the CI wiring independently. Chromatic’s CI guide calls for a configured CHROMATIC_PROJECT_TOKEN, the CLI installed in development dependencies, and a command suited to the integration in use. Chromatic CI documentation
- Confirm the project token is stored as a CI secret and is available to the job that runs Chromatic.
- Confirm the project installs its Chromatic CLI dependency and runs the command appropriate to the Storybook, Vitest, Playwright, or Cypress integration.
- If a provider check attaches to the wrong commit or branch, inspect
CHROMATIC_SHA,CHROMATIC_BRANCH, andCHROMATIC_SLUG. Chromatic documents all three for the described Git-provider linking fix. - When the trace and configuration do not explain the mismatch, collect the build- and test-specific evidence before contacting Chromatic support.
Keep tokens secret; do not paste them into logs or public issue reports. For exact setup steps, use the official CI guide.
8. Troubleshooting by symptom
| Symptom | Likely evidence to check | Next fix |
|---|---|---|
| Text shifts or wraps differently | Font request failed or arrived late; computed font differs; text is an anonymous flex item | Make the font reachable and loaded, verify its response, and wrap flex text in a targetable element when appropriate. |
| Image, icon, or stylesheet is missing | Failed, blocked, slow, or malformed network response; access restriction | Fix the asset URL or response, allow capture access, and use stable assets. |
| Story is blank or partially rendered | Console exception, missing script/data, or archived DOM lacks expected elements | Fix the runtime error and ensure data or mocks are ready before capture. |
| Difference appears intermittently | Unseeded randomness, current time, async race, or JavaScript animation frame | Fix the input and state, then wait on an assertion tied to the expected state. |
| Whole image differs after browser or capture change | Browser-specific baseline, infrastructure change, or DPR notice | Compare like browser and DPR; review metadata and intentional baseline changes before editing CSS. |
| Content is clipped or absent at an edge | Trace viewport or clip rectangle; inferred height differs | Set the intended dimensions and ensure content is within the captured area. |
| CI status points to an unexpected commit or branch | Token, provider integration, or missing SHA/branch/slug metadata | Verify CI secret and CLI setup; inspect the three documented CHROMATIC_* values. |
9. Keep the capture process reliable and economical
For Chromatic debugging, use the trace to distinguish slow or failed resources from an actual rendering difference. Stabilize inputs and wait for observable readiness rather than increasing timeouts indiscriminately; longer waits can make a CI job slower while preserving the underlying race. Avoid repeated baseline acceptance until you understand whether the diff came from an intended design change, a changed capture context, or unstable inputs.
Do not infer a failure rate or accuracy figure from an individual build. The practical cost of a nondeterministic test is repeated investigation and noisy review, so fix the source of variation and keep the trace evidence with the change.
Or skip the browser setup
For a separate website capture you need in a script, ScreenshotNeo is a website screenshot API and MCP server from Yorker Media. One GET request returns a PNG, JPEG, WebP, or PDF. This does not replace Chromatic’s component snapshot baseline workflow; it is an option when you need a clean capture of a URL. See the 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}`);
- Cookie banners are accepted or removed, and newsletter popups and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed. Responses include
X-Page-VerdictandX-Billedheaders. - An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for Claude, Cursor, and other MCP clients. - The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Why does text alignment differ from my development environment?
First check that the intended font loaded in the capture trace. Font fallback changes text metrics; flex text without a wrapper can also have baseline and sizing behavior that is difficult to target consistently. Chromatic’s unstable-test guidance
Does a passing Canvas view prove the Chromatic snapshot is correct?
No. Canvas is a live interactive rendering context; the snapshot is produced by Chromatic’s capture environment and may follow different execution behavior. Use the build trace and snapshot metadata to compare them.
Should I accept a large diff after changing the browser or DPR?
First verify the browser, DPR notice, viewport, and clip metadata. Browser-specific baselines and DPR differences can explain broad changes, but the trace is needed to establish what changed for your build.
Can I use a wait delay to fix a flaky snapshot?
Only when the render is deterministic and needs a known settling interval. Prefer waiting for an asserted state or selector so the capture begins when the expected content is ready.
Is ScreenshotNeo a replacement for Chromatic?
No. Chromatic’s snapshot workflow compares component captures with test baselines. ScreenshotNeo captures URLs as images or PDFs and can be called through an API or MCP server.


