Sign inSign up

Troubleshooting Snapshots

Did you encounter inconsistent, blank, or other rendering issues in your snapshots? This guide helps you identify common causes and improve snapshot consistency.

Rerun build to identify inconsistencies

Double-check whether a visual change is real or caused by inconsistencies in your app code by retaking snapshots. Click the “rerun” button to kick off a new build that uses identical settings and configuration as your original build. Only snapshots for denied, unreviewed, or errored changes will be captured. Any changes you accepted in the original build will not be snapshotted again in a rerun build.

Rerun button

Debug inconsistent snapshots by looking at the set of changes between the original build and the rerun build. You might encounter these common scenarios:

  • Identical changes between builds: This means the snapshots are accurately showing bonafide UI changes that need your verification. Continue the UI Tests workflow as usual.

Different changes between builds: This means inconsistent snapshots are introducing false positives to your visual tests. Learn how to use the Snapshot Tracer Viewer to identify the root cause and check out our recommendations for improving snapshot consistency.

When there are potential rendering inconsistencies in a rerun build, Chromatic will call them out in a message. Inconsistent snapshot detection

Debug snapshots with Trace Viewer (beta)

The Snapshot Trace Viewer lets you explore recorded traces of tests rendered and snapshotted in the Chromatic Capture Cloud. It captures network requests, console logs, and other debugging information, helping you identify the root cause of rendering issues.

Once you rerun a build, the subsequent build will feature a “Traces” column. This column links to the Trace Viewer for each snapshot in the build, with one link per enabled browser. Click on one of the browser buttons to open the Trace Viewer.

Build 2 was a rerun build so it has an additional "traces" column

Why does the Trace Viewer indicate that Chromatic captured multiple screenshots for a test?

During the capture process, Chromatic continually takes screenshots until it either reaches the maximum allowed timeout or it captures two matching screenshots, indicating that the page has settled. This ensures the snapshot is consistent and that UI is in its final state.

How to use the snapshot trace?

Chromatic uses Playwright to render and capture snapshots in its Capture Cloud, even if your tests are written using Cypress or Storybook. Therefore, it’s able to leverage Playwright’s built-in capability to generate these traces. These traces capture network activity, console logs, DOM snapshots, and other debugging information.

Example of a Playwright trace capturing network requests and displaying the final DOM structure

Below are some common scenarios where the Trace Viewer can help you debug snapshot issues:

Network tab analysis

The network tab displays the resources loaded during capture, including fonts, stylesheets, scripts, and other assets. Check for resources that failed to load or took a long time. For example, if fonts aren’t incorrect or styles are missing, ensure that the font or CSS files have loaded successfully with the correct MIME type. Consider loading slow assets statically.

For a detailed list of trace viewer features, see the Playwright documentation.

Inspect the DOM

The Trace archives the DOM for each step or action executed, allowing you to inspect the DOM at the time of capture. Use this tab to verify the DOM structure is as expected.

Check for missing elements, incorrect styles, or unexpected layout changes. If styles are missing but the CSS file has loaded, ensure the styles are applied correctly.

Use browser devtools to inspecting the DOM archived by the trace

Screenshot metadata

When Chromatic captures a screenshot, it includes metadata like viewport information and clip rectangle dimensions, providing context for the capture. Use this data to identify issues such as:

  • Responsive design issues: Viewport information reveals the screen size used for the capture. Compare this with your breakpoints to ensure that the correct styles are applied.
  • Element positioning problems: The clip rectangle shows precisely what was captured. If an element is missing from the snapshot, verify if it falls within the expected clip area. For instance, Chromatic only captures DOM elements within the #storybook-root element for stories. Modal and dropdown components might not be captured if they fall outside this root element’s “natural” dimensions. Use fixed-height wrappers to capture these portal components.

Example of screenshot metadata for a story of a dropdown component

Common snapshot rendering issues

Where are my images and fonts?

Image and font rendering can be tricky. Resources that load from unpredictable or flaky sources may not load in time (15s) to capture. Work around this by:

If your resources are behind a firewall, whitelist our domain so we can load your resources.

Why am I seeing inconsistent snapshots for a component using srcset?

The srcset attribute is a useful mechanism that provides the browser with a list of potential images to display, based on specified conditions such as media queries.

In most cases, Chromatic will capture the correct image from the srcset list. However, if multiple tests list the same image in their respective srcset lists, browser cache issues can result in inconsistent snapshots.

In situations like this, the best workaround is to make the srcset URLs unique for each test by adding a random query parameter value.

For instance, one test could have a srcset with a query parameter of ?cachebuster=1714593641616.

<picture>
  <source
    sizes="(max-width: 768px) 100vw, 50vw"
    type="image/webp"
    srcset="
​      https://placehold.co/384x384.webp?cachebuster=1714593641616 384w,
​      https://placehold.co/640x640.webp?cachebuster=1714593641616 640w,
​      https://placehold.co/750x750.webp?cachebuster=1714593641616 750w"
  />
  <img
    alt="Alt text"
    loading="eager"
    width="1500"
    height="1500"
    decoding="async"
    sizes="(max-width: 768px) 100vw, 50vw"
    src="https://placehold.co/3840x3840.jpeg"
    style="color: transparent;"
  />
</picture>

If another test uses the same images, they can alter the query parameter in the URL to ?currenttime=1714593641620.

<picture>
  <source
    sizes="(max-width: 768px) 100vw, 50vw"
    type="image/webp"
    srcset="
​      https://placehold.co/384x384.webp?currenttime=1714593641620 384w,
​      https://placehold.co/640x640.webp?currenttime=1714593641620 640w,
​      https://placehold.co/750x750.webp?currenttime=1714593641620 750w"
  />
  <img
    alt="Alt text"
    loading="eager"
    width="1500"
    height="1500"
    decoding="async"
    sizes="(max-width: 768px) 100vw, 50vw"
    src="https://placehold.co/3840x3840.jpeg"
    style="color: transparent;"
  />
</picture>

Any query parameter name can be used, just so long as the value is unique to each test.

Why do my emojis look different in the snapshot versus on my machine?

Emojis are handled by your operating system’s emoji font. Most OSs have a different emoji font and those fonts tend to change over time. For example, if you view a story on a Mac you’ll get Apple’s set of emojis.

Chromatic captures Chrome and Firefox snapshots in a Linux environment. It includes a common set of emojis used by most systems. Those emojis will likely look different from emojis on a consumer OS like Mac or Windows. Unfortunately, there’s no workaround available at this time.

Where are my videos?

Videos are interactive and time-based which introduces inconsistencies in snapshots. Chromatic hides videos by default to prevent false positives. You’ll see the poster image (if specified) or a blank space where the video is supposed to render.

Why am I getting cross-origin errors with my stories?

Most likely, you are calling into window.parent somewhere in your code. As we serve your test preview iframe inside our www.chromatic.com domain, this leads to an x-origin error as your code doesn’t have access to our frame (with good reason!).

Generally speaking it is a good idea to wrap calls like that in a try { } catch in case the code is running in a context where that’s not possible (e.g., Chromatic).

Why is my content being cut off vertically in my snapshots?

Make sure there are no elements inadvertently cutting off content through the use of overflow or height styles.

For elements that have relative height styles based on the size of the viewport (such as height: 100vh), all content nested under that element will show up in a screenshot unless either overflow: hidden or overflow: scroll is used to hide what is outside of that element (and therefore outside of the viewport).

When Chromatic takes a screenshot for an element that has a viewport-relative height as well as styling to hide/scroll the overflow, a default viewport height of 900px will be used. This default is only used when we can’t detect a “natural” height for the outermost DOM element (root ancestor), for instance, in the case of scrollable divs.

To set the height, you can add a decorator for stories that wraps them in a container with a fixed height:

// MyComponent.stories.js|jsx

import { MyComponent } from "./MyComponent";

export default {
  component: MyComponent,
  title: "Example Story",
  decorators: [
    (Story) => (
      <div style={{ margin: "3em" }}>
        <Story />
      </div>
    ),
  ],
};
How do I capture content inside scrollable divs?

Scrollable divs constrain the height of their children. Change the height of the scrollable div to ensure all content fits. It’s not possible for Chromatic to infer how tall scrollable divs are intended to be.

Why isn’t my modal or dialog captured?

If you use an “animateIn” effect set delay to ensure we snapshot when the animation completes.

If your component infers its dimensions from the layout of the surrounding DOM elements (e.g., it’s a modal that uses position:fixed), you’ll need to set the height of that component’s stories using a decorator.

// MyComponent.stories.js|jsx

import { MyComponent } from "./MyComponent";

export default {
  component: MyComponent,
  title: "Example Story",
  decorators: [
    (storyFn) => (
      <div style={{ width: "1200px", height: "800px" }}>
        This is a decorator for modals and such {storyFn()}
      </div>
    ),
  ],
};

/*
 *👇 Render functions are a framework-specific feature to allow you control over how the component renders.
 * See https://storybook.js.org/docs/api/csf#custom-render-functions
 * to learn how to use render functions.
 */
export const StoryWithDimensions = {
  render: () => <MyComponent />,
};
What if I have a modal component that doesn't define a width or height?

If your component infers its dimensions from the layout of the surrounding DOM elements (e.g., it’s a modal that uses position:fixed), you can set the height of that component’s stories using a decorator.

// MyComponent.stories.js|jsx

import { MyComponent } from "./MyComponent";

export default {
  component: MyComponent,
  title: "Example Story",
  decorators: [
    (storyFn) => (
      <div style={{ width: "1200px", height: "800px" }}>
        This is a decorator for modals and such {storyFn()}
      </div>
    ),
  ],
};

/*
 *👇 Render functions are a framework-specific feature to allow you control over how the component renders.
 * See https://storybook.js.org/docs/api/csf#custom-render-functions
 * to learn how to use render functions.
 */
export const StoryWithDimensions = {
  render: () => <MyComponent />,
  args: {},
};
Do you support taking snapshots of a component with multiple themes?

Yes, check out the Chromatic’s modes feature is simplifies the process of visually testing your stories with different global configs such as themes. Check out the Themes in modes guide to get started.

Why am I seeing a blank snapshot?

Blank snapshots are often caused by:

  • An “animateIn” effect—If your component use an “animateIn” effect set delay to ensure we snapshot when the animation completes.

  • Position:fixed—Fixed position elements may depend on viewport size but do not have dimensions themselves. Wrap your component in an element whose height and width are defined.

Learn more about debugging snapshots.

Why are ignored elements still causing diffs?

By default, Chromatic’s diffing algorithm skips the DOM elements marked with either a .chromatic-ignore CSS class or data-chromatic="ignore" attribute.

However, if you’re using this functionality but notice the incoming changes are still being captured. In that case, you’ll need to ensure that both the baseline and new snapshots retain the same dimensions (e.g., width, height, and relative positioning).

Why is my tab component's width rendering inconsistently in snapshots?

Certain UI libraries like Material calculate the dimensions of each tab by measuring the rendered width of the tab’s children using JavaScript (for example, via getBoundingClientRect()).

However, this can lead to inconsistent snapshots in cases where you load a custom font. Fonts affect the dimensions of text within tabs. Since custom fonts can load before, during, or after the tab component itself loads, the dimensions calculated by the tab component can also vary.

The solution we recommend is to use a <link rel="preload"> in your .storybook/preview-head.html to preload the font before the story renders. This ensures that the dimensions of the contents inside of the tab component remain consistent when measured.

Why are fonts in my graph component rendering inconsistently?

Certain charting libraries like Highcharts measure the available space to determine where elements should be laid out.

But this can lead to inconsistent snapshots in cases where you load a custom font. Fonts can load before, during, or after the component itself loads. And different fonts have different dimensions when rendered.

The solution we recommend is to use a <link rel="preload"> in your .storybook/preview-head.html to preload the font before the story renders. This ensures that the dimensions and position of the fonts inside of the graph component remain consistent.

Improve snapshot consistency

It’s essential that your components and stories render in a consistent fashion to prevent false positives. Below are common reasons stories render inconsistently and ways to improve consistency:

  • Randomness in tests: Components sometimes use random number generators to generate data for complex inputs. To avoid this, you can hard-code the input data, but often a more convenient solution is to use a tool like seedrandom which you can use to make your “random” number generator consistent.

  • Animations: Chromatic will attempt to pause all animations. However, you may need to configure Chromatic’s exact behavior.

  • Unpredictable resource hosts: Resources that load from unpredictable or flaky sources may not load in time (15s) to capture. To work around this, serve resources as static files or use a placeholder service. Learn more about how we load resources.

  • Image CDNs & compression algorithms: Image CDNs optimize for image weight and size, which affect how it renders. Since this happens upstream of Chromatic, any changes to those images in your components will be caught as visual changes. Work around this by ensuring the served images are identical every time and using consistent compression settings. Also consider serving images as static files or use a placeholder service

  • Web font loading: Web fonts can load at different times impacting snapshot consistency, especially when combined with interactions. Serve web fonts as static files and make sure to preload them.

  • Iframes rendering out of the viewport: Some browsers only visually render iframes when they are inside of the viewport, despite the fact that they have loaded with all of their resources. For this reason, if you have an iframe that is placed below the viewport of a tall story, it will appear blank. You may want to ignore that element and also test it in isolation so that it fits inside of the viewport.

  • Use of the current date/time: Dates and times are a testers bane! To get consistency in components or tests that use the current time, you can use a tool to also “seed” the time, like mockdate for the Date object.

  • UI takes time to render: UI can take extra time to “settle” into it’s final orientation. Add a delay to take a snapshot after waiting a period of time. Note that this technique can make the UI rendering inconsistency less obvious in snapshots, but it won’t eliminate the underlying issue in how UI renders.

  • Intentional randomness: Some stories may render unpredictably intentionally. If this is the case you may want to ignore the story from UI Tests and move on. If you still need inconsistent elements for local development purposes inside Storybook, you can use isChromatic() exported from our package to apply the solutions above only when in the Chromatic environment.

Serve static files

When using Playwright or Cypress, you can serve static files like fonts, images, and videos through your app server. This ensures that resources load consistently across all snapshots.

For Storybook, use the staticDirs option to load static files for your stories.

Use fixed-height wrappers for portal components

Portals allow components to render arbitrary elements outside the parent component’s initial DOM hierarchy. For example, tooltips, modals, popovers, and menus can be triggered by a nested button, but render close to the top of the DOM hierarchy using portals.

With Playwright and Cypress, Chromatic snapshots the entire page, including modals, dialogs, and other portaled elements. However, with Storybook, portals render outside of Storybook’s DOM tree which can lead to cut-off snapshots.

Why are snapshots of portal components (tooltip, modal, popover, menu) cut off?

For stories, Chromatic relies on the “natural” height of your component’s outermost DOM element (using Storybook’s #storybook-root element in version 7 or higher or the #root element for previous versions) to determine snapshot dimensions. As portals render outside of Storybook’s DOM tree, Chromatic cannot auto-detect their dimensions, which can lead to cut-off snapshots.

To capture snapshots of portaled elements, you can use a decorator that wraps your stories in a fixed-height container. You can adjust the container’s height to account for the total dimensions of your component and portal.

MyComponent.stories.js|jsx
import { MyComponent } from "./MyComponent";

export default {
  component: MyComponent,
  title: "Example Story",
  decorators: [
    (Story) => (
      <div style={{ height: "300px" }}>
        <Story />
      </div>
    ),
  ],
};

Browser differences between snapshots

Chromatic attempts to render as consistently as possible across our supported browsers. But all browsers have different capabilities and built-in APIs. In practice, this means your snapshots may appear or behave differently depending on which browser you’re looking at. This is ideal for customers because it mirrors what the end users who use different browsers would also encounter.