Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Playwright’s screenshot assertions against deterministic Storybook stories, commit the reference images, and run the same browser setup in CI. The essential assertion is await expect(page).toHaveScreenshot() (or the locator equivalent): the first run creates a reference image, and later runs fail when the rendered story differs beyond your configured tolerance.

This guide shows a native Playwright implementation, the storybook-addon-playwright route, stability controls, CI setup, troubleshooting, and how the local approach compares with Chromatic. It also explains where ScreenshotNeo can remove browser-capture plumbing when you need a clean screenshot of a reachable page rather than repository-managed visual baselines.

What Storybook screenshot tests actually verify

A Storybook story is a reusable description of one component state: its props, decorators, theme, and supplied data. Treat that story as the test case. The screenshot assertion answers one narrow question: does this rendered state still look the same? It can expose shifted layout, changed colors, incorrect dimensions, missing fonts, contrast-related appearance changes, and other visual regressions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

That scope matters. A pixel comparison does not prove that a button submits a form, that keyboard focus works, that an API response is correct, or that all accessibility rules pass. Keep interaction tests, accessibility checks, markup assertions, and full end-to-end tests alongside visual tests rather than replacing them.

Choose a local implementation

Native Playwright Test

Playwright Test gives you direct control over browser projects, URLs, fixtures, snapshot paths, and assertions. It is the most flexible choice when your team already runs Playwright or needs custom setup such as authentication, request interception, or several viewport projects.

storybook-addon-playwright

The addon is designed to run visual checks for stories in multiple browsers, wait for Storybook to render, capture images, and keep them in a __screenshots__ folder beside the story. Its current compatibility page lists Storybook ^10, Playwright ~1.59, and Node.js >=24.15.0; verify those constraints against the package version you install because they can change.

The addon targets Component Story Format (CSF). It does not provide its addon UI in a static Storybook build, and framework compatibility has caveats, so check those conditions before adopting it. You can use its toMatchScreenshots, runImageDiff, and getScreenshots helpers from Vitest, Jest, or custom assertions.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build a native Playwright test step by step

1. Install Playwright and a browser

From the repository containing Storybook:

npm install --save-dev @playwright/test
npx playwright install

In a Linux CI runner, install the operating-system dependencies as well:

npx playwright install --with-deps chromium

Keep the browser version, operating system, and fonts consistent between the machine that creates references and the machine that reviews them.

2. Configure the Storybook server and snapshots

Create playwright.config.ts. The configuration below starts Storybook for the test run, fixes the viewport and color scheme, and separates snapshots by browser project.

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests/visual',
  snapshotPathTemplate: '{testDir}/__screenshots__/{projectName}/{arg}{ext}',
  use: {
    baseURL: 'http://127.0.0.1:6006',
    viewport: { width: 1280, height: 800 },
    colorScheme: 'light',
    deviceScaleFactor: 1
  },
  webServer: {
    command: 'npm run storybook -- --ci --port 6006',
    url: 'http://127.0.0.1:6006',
    reuseExistingServer: !process.env.CI
  },
  projects: [
    { name: 'chromium', use: { browserName: 'chromium' } }
  ]
});

The snapshotPathTemplate keeps references in a predictable, reviewable directory. Add Firefox or WebKit as separate projects only when you intend to maintain separate baselines; a browser change should not silently overwrite another browser’s images.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Write a story-level screenshot test

Storybook’s iframe URL identifies a story by its component and story IDs. For a story exported as Primary from Button.stories.tsx, the URL commonly looks like this:

import { test, expect } from '@playwright/test';

test('Button primary story', async ({ page }) => {
  await page.goto('/iframe.html?id=button--primary&viewMode=story');
  await page.locator('#storybook-root').waitFor();

  await expect(page).toHaveScreenshot('button-primary.png', {
    animations: 'disabled',
    maxDiffPixels: 100
  });
});

Use the story’s actual ID from your Storybook URLs or index. Waiting for #storybook-root confirms that the canvas exists; it does not guarantee that a story’s asynchronous data has finished loading, so add a more specific readiness check when necessary.

4. Create and review the baseline

Run the test once:

npx playwright test tests/visual/button.spec.ts

On that first execution, Playwright writes the reference image. Commit the resulting snapshot directory to version control. On subsequent runs, Playwright waits for two consecutive screenshots to be identical before comparing them, which helps avoid capturing during layout movement.

Now make a deliberate visual change, such as changing the button’s background color, and run the test again. Playwright reports the mismatch and writes comparison artifacts for inspection. Review whether the difference is intentional. If it is, update the reference explicitly:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
npx playwright test --update-snapshots

Do not use that flag as an automatic repair step in CI. The code change and the approved baseline update should be reviewed together.

Cover responsive and themed variants without mixing baselines

A responsive component needs more than one viewport. Define each important viewport as a named project or as a separately named test so a desktop change cannot replace a mobile reference.

projects: [
  {
    name: 'chromium-desktop',
    use: {
      browserName: 'chromium',
      viewport: { width: 1280, height: 800 },
      colorScheme: 'light'
    }
  },
  {
    name: 'chromium-mobile',
    use: {
      browserName: 'chromium',
      viewport: { width: 390, height: 844 },
      colorScheme: 'light',
      deviceScaleFactor: 2
    }
  }
]

Apply the same principle to dark mode, locale, timezone, and reduced-motion settings. A changed environment is a new visual condition, not an interchangeable baseline. Hosted Storybook services can also model viewport, theme, locale, and media-feature variants; confirm the provider’s current matrix before depending on it.

Make captures deterministic

Control the rendering environment

  • Generate and compare images on the same operating-system family, browser build, font set, and device scale factor.
  • Pin browser versions in CI and avoid committing a developer-machine baseline that CI cannot reproduce.
  • Set viewport, color scheme, locale, timezone, and other media features deliberately.

Remove time and data noise

  • Freeze clocks where timestamps appear.
  • Replace random IDs and generated content with fixed values.
  • Intercept network calls or provide stable fixtures instead of live, changing responses.
  • Wait for a story-specific selector, not merely the initial document load, when data arrives asynchronously.

Handle motion and fonts

Playwright disables animations for screenshot assertions by default, but application-level transitions, video, canvas animation, and delayed font loading can still change pixels. Prefer a test stylesheet or a screenshot-only style injection that freezes motion. Wait for the fonts your component requires, and make sure the same font files are available in every environment.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the Storybook Playwright addon instead

Install the addon version that matches your Storybook and Playwright versions, then follow its framework-specific setup. It can start or connect to a Storybook development server, wait for the rendered story, and place images in __screenshots__ next to the story. Missing references are generated with:

npx storybook-addon-playwright generate stories/Button.stories.playwright.json

Existing references fail when they no longer match. The addon waits for #storybook-root by default; for a story that needs an additional readiness condition, use its beforeScreenshot hook to wait for an explicit selector. Because the addon is intended for CSF and its UI does not operate in a static Storybook build, treat those as setup checks rather than assumptions.

Run visual tests in CI

A pull-request job should install the exact dependencies, install the pinned browser, start Storybook through the Playwright web server configuration, and run the tests. A minimal GitHub Actions job is:

name: visual-tests

on: [pull_request]

jobs:
  screenshot:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test

Keep baseline updates in the same pull request as the UI change. Require a reviewer to inspect the diff, especially when many files change at once. A broad rewrite can indicate a missing font, an altered browser image, or a broken Storybook fixture rather than a legitimate redesign.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Local Playwright versus Chromatic

Chromatic is Storybook’s named hosted option. Its Storybook addon sends stories to Chromatic for snapshotting; changed stories are highlighted for review, and accepted changes become new baselines. Its Playwright integration extends Playwright’s test and expect utilities, uploads a page archive containing DOM, styles, and assets during an end-to-end test, and performs the pixel diff in its cloud environment.

Decision point Local Playwright or addon Chromatic
Execution Your workstation or CI browser, started and maintained by your team Hosted browser execution and rendering
Baseline ownership Image files committed with the repository Cloud-indexed snapshots associated with commits
Browser coverage Browsers you install, pin, and update Provider’s available browser matrix; verify current coverage
Review and debugging Git diffs, local artifacts, and your existing tooling Hosted visual diffs, archives, and collaboration features
Determinism You control OS, fonts, browser, data, and power-state variables A standardized service environment reduces local variation
Cost and governance Your CI minutes, storage, maintenance, and retention policy Service usage, retention, account controls, and vendor terms

Choose local testing when repository-owned images, offline debugging, or custom browser control matter most. Choose Chromatic when hosted review, cloud baselines, and provider-managed execution justify the service dependency. Browser matrices and billing are service details that can change, so verify them before committing to a plan.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common failures

The test captures a blank or incomplete canvas

Confirm that the Storybook server is reachable at the configured URL and that the story ID is correct. Wait for a story-specific element after #storybook-root, and ensure mocked data is available before taking the screenshot.

Every pixel changes in CI

Compare browser versions, operating-system images, fonts, viewport, device scale factor, and color scheme. Regenerate references inside the same pinned CI image you will use for comparison; do not mix host and CI baselines.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The test is flaky around transitions

Disable CSS and JavaScript-driven motion for the test, replace animated media with a fixed frame, and wait for fonts and asynchronous content. Playwright’s animation handling cannot stabilize application data that changes between renders.

Only one browser’s images are overwritten

Give projects distinct names and include the project in the snapshot path. Keep desktop, mobile, dark, and light variants in separate namespaces.

The addon command cannot find a baseline file

Check that the path points to a CSF story and that the addon version supports your Storybook and Playwright versions. A static build or unsupported framework integration can prevent the addon UI or hooks from working as expected.

A large diff appears after a harmless dependency update

Inspect the first changed pixels for font substitution, browser rendering changes, or altered default styles. Review the dependency update and its references together; do not approve a blanket snapshot refresh without identifying the cause.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance, reliability, and cost decisions

Screenshot suites scale with the number of stories, browser projects, viewports, and retries. Start with one representative, deterministic story, then add states that protect real visual risk. Reuse a single Storybook server per test run, avoid unnecessary full-page captures, and parallelize only when the environment and snapshot paths are isolated.

Reference images are code-review artifacts: they consume repository storage and require deliberate updates. Hosted services move storage and review out of Git but add service usage, retention, and governance considerations. Neither model removes the need to control fonts, data, and browser versions.

Or skip the browser setup

ScreenshotNeo is useful when you need a clean screenshot or PDF of a reachable Storybook deployment, documentation page, or other URL without maintaining a capture browser. It accepts the consent banner like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It is a capture service, not a replacement for repository-managed Playwright baseline assertions.

See the ScreenshotNeo API documentation for all options. A one-call image request is:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The same request in Python:

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)

And in Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots, and every feature is available on every plan. Create a free ScreenshotNeo account to try it.

Frequently Asked Questions

Can visual tests use authenticated Storybook stories?

Yes. Configure Playwright’s context with a storage state, cookie, custom header, or request fixture before navigating to the story. Keep that state deterministic and avoid using a live account whose data changes between runs.

How can a team review a redesign without losing the old reference?

Open the redesign as a normal pull request, inspect the changed images, and update references only in that pull request after approval. The commit history then records both the implementation and the accepted visual state.

Is it safe to run screenshot projects in parallel?

It is safe when each project has isolated browser settings, stable fixtures, and a snapshot path containing the project name. Parallel workers should not mutate shared test data or write the same reference file.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.