Self-hosted service
reg-viz/storycap avatar
reg-viz/storycap

Storycap: turning a Storybook into screenshots for visual testing

A Storybook Addon, Save the screenshot image of your stories :camera: via puppeteer.

755 stars96 forksTypeScriptMIT

At a glance

What is it?
Storycap crawls a Storybook with Puppeteer and writes an image for every story, which is what visual regression suites such as reg-suit consume. It runs in a simple mode against any Storybook URL, or in a managed mode where each story declares its own viewport, timing and interaction, and it is MIT licensed with a monorepo that still ships two packages.
Who is it for?
Use Storycap if you already run a Storybook and want image snapshots of its stories for a visual regression suite, since it knows the Storybook story index and iframe structure and saves you from writing that crawl yourself.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A crawler that photographs every story

Storycap is a Storybook addon that saves the screenshot image of your stories via Puppeteer, and the one-line description is accurate: it crawls your Storybook and takes screenshot images.

The stated purpose is image generation for visual testing, and the README names reg-suit as the tool that consumes the output. That framing matters, because it sets expectations correctly. Storycap is not a visual testing suite and it does not compare images. It produces the artefacts, one image per story, and hands them to something that knows how to diff them against a baseline.

The feature list adds the properties that matter for a build step. It is described as extremely fast, zero configuration, and independent of any UI framework, with React, Angular and Vue all named as examples. That last point is the important one. A Storybook can be built with any framework, and a screenshot tool that had to understand React's rendering would be useless for the Vue or Angular stories in the same book. Storycap works at the level of the rendered page instead, which is why it is called a Storybook addon and not a framework integration.

The project is written in TypeScript, licensed MIT, and published to npm as storycap. The repository topics are addon, puppeteer, screenshot, screenshot-image, storybook and visual-testing.

The version numbering tells you the maturity. Releases run v4.3.1, then v5.0.0 in March 2024 and v5.0.1 in September 2024, so the major bump was recent enough that the API may still be settling.

Simple mode: point it at a URL

Storycap runs in two modes, and the simple one is genuinely zero configuration. You give it the URL of a Storybook and it does the rest.

sh
$ npx storycap http://localhost:9001

If you do not want to start the Storybook yourself, the --serverCmd option launches it as part of the run:

sh
$ storycap --serverCmd "start-storybook -p 9001" http://localhost:9001

A pre-built Storybook works the same way, served by any static server:

sh
$ build-storybook -o dist-storybook
$ storycap --serverCmd "npx http-server dist-storybook -p 9001" http://localhost:9001

And because it is just an HTTP crawler, it works against a hosted Storybook as well:

sh
$ storycap https://next--storybookjs.netlify.app/vue-kitchen-sink/

That last form is more useful than it first appears. It means you can run the tool against a Storybook deployed to a preview environment, which is how many teams test a pull request's Storybook before merging, and it means the tool itself has no opinion about where the stories are served from.

The trade of the simple mode is control. You get whatever the default capture produces, and the README is clear that if you want to control how stories are captured, in terms of timing or size, you should use managed mode instead.

Managed mode: registering the addon and the decorator

Managed mode exists so that each story can say how it should be captured, and it works by adding storycap to the Storybook configuration as an addon.

js
/* .storybook/main.js */

module.exports = {
  stories: ['../src/**/*.stories.@(js|mdx)'],
  addons: [
    '@storybook/addon-actions',
    '@storybook/addon-links',
    'storycap', // <-- Add storycap
  ],
};

Then the withScreenshot decorator goes into the preview file, and registering the decorator is required:

js
/* .storybook/preview.js */

import { withScreenshot } from 'storycap';

export const decorators = [
  withScreenshot, // Registration the decorator is required
];

export const parameters = {
  // Global parameter is optional.
  screenshot: {
    // Put global screenshot parameters(e.g. viewport)
  },
};

The screenshot options object is available as the value of the screenshot key of the addParameters argument, or as the argument to withScreenshot. The global parameters block is optional, which means the whole managed configuration can start empty and be filled in per story.

Individual stories override the global settings through parameters, and the README's example sets a delay of 200 milliseconds on one story and a viewport of iPhone 5 on another.

Once the addon is registered, the run itself is the same command as before:

sh
$ npx start-storybook -p 9009
$ npx storycap http://localhost:9009

or in one line with --serverCmd, which is the form most useful in a CI job.

The ScreenshotOptions surface and what each switch does

The options interface is where most of the behaviour lives, and the README documents it in full with defaults included.

ts
interface ScreenshotOptions {
  delay?: number;                           // default 0 msec
  waitAssets?: boolean;                     // default true
  waitFor?: string | () => Promise<void>;   // default ""
  fullPage?: boolean;                       // default true
  hover?: string;                           // default ""
  focus?: string;                           // default ""
  click?: string;                           // default ""
  skip?: boolean;                           // default false

Timing is handled by three options. delay waits a fixed number of milliseconds before capturing. waitAssets, on by default, waits until all resources requested by the story, such as img elements or CSS background images, have finished loading. waitFor accepts either a function returning a promise or the name of a global function that returns one, and Storycap waits for it to resolve. The README has a section on taking full control of the screenshot timing with two examples.

Interaction is handled by hover, focus and click, each of which takes a CSS selector string. If the selector is valid, the capture happens after that element has been hovered, focused or clicked, which is how you screenshot a dropdown that only exists after an interaction.

Two options control what is captured. fullPage, on by default, captures the entire page rather than the viewport. omitBackground removes the background, and captureBeyondViewport and clip let you take a region of the page.

One option is deprecated, and the README says so explicitly: waitImages is deprecated in favour of waitAssets.

And skip, on by default false, cancels the capture of the corresponding stories, which is how you exclude the ones that are deliberately broken.

Variants, viewports and one story producing many images

The viewport options are what let a single story produce several images. The viewport field takes a single Viewport, while viewports takes either an array of strings or an object mapping variant names to viewports, and the variants option composes them.

The README has a section on getting multiple PNGs from one story, with a basic usage example, a variants composition example, and a third case that is worth reading on its own: parallelisation across multiple computers. That last one matters for a large Storybook, because screenshotting hundreds of stories on one CI machine is slow, and the project documents a way to split the work.

The Viewport type is what makes a named preset possible. The example in the README uses the string iPhone 5 as a viewport value, so the tool understands a set of device presets rather than only raw pixel dimensions.

The variants mechanism is the conceptual step. Rather than duplicating a story to test it at three widths, one story declares three viewports and the tool emits one image per combination. That is what turns a Storybook into a matrix of screenshots, and it is why storycap sits naturally next to a visual regression suite rather than beside a screenshot service.

The types are also exported for use in your own code, and the README documents isScreenshot as a helper function for narrowing types, with ScreenshotOptions, Variants and Viewport all described as public types.

Chromium, the second package and the monorepo behind it

Installing the tool is one command:

sh
$ npm install storycap

Installing Puppeteer alongside it is optional, and the README points to the Chromium version section for the detail. The reason it is optional is worth understanding: Storycap can either use a Puppeteer installation you provide, which is what you want in a CI image where a specific browser build is already cached, or fall back to a browser it manages itself. Controlling which Chromium build runs is the difference between reproducible images and images that change because a browser updated.

The repository is a Lerna and Yarn monorepo, and it contains more than one package. The root scripts show two of them being handled explicitly: storycrawler and storycap, each with its own licence and README copied into the published directory by the copy:misc scripts. The crawler is the part that understands the Storybook story index and the iframe structure, and it is what separates Storycap from a generic screenshot script.

The build and release machinery is conventional for the era: lerna run build, typedoc for the API documentation, eslint and prettier, husky for git hooks, renovate for dependency updates, a wercker.yml for CI, and deploy scripts for publishing to npm and for the gh-pages documentation site. The e2e script and the regression script are the two that matter for a project that produces images: bash e2e.sh for the end-to-end checks, and reg-suit run for the image comparison.

The examples directory shows the supported matrix, with v7 and v8 directories for Storybook majors and simple, managed and vite5-prod variants, including a React 18 example.

Editorial conclusion

Use Storycap if you already run a Storybook and want image snapshots of its stories for a visual regression suite, since it knows the Storybook story index and iframe structure and saves you from writing that crawl yourself. Do not reach for it if you have no Storybook, since a generic screenshot tool is the better fit, and be aware that capturing a Storybook means capturing whatever the browser downloads, so a story that depends on live network data will produce a different image each run. Before you wire it into CI, check the Chromium version note, because installing puppeteer is optional and the bundled browser has to match, and pin the Storybook major version you test against, noting that the latest release is v5.0.1 from 2024-09-04 while the last push was on 2026-10-15.

Frequently asked questions

What does Storycap do and what is it used for?

Storycap is a Storybook addon that crawls your Storybook and takes a screenshot image of each story via Puppeteer. It is primarily responsible for the image generation needed for visual testing, such as with reg-suit.

How do I install and run Storycap?

Install it with npm install storycap, then point it at a running Storybook with npx storycap http://localhost:9001, or let it start the server with --serverCmd. Installing puppeteer as well is optional and relates to which Chromium build is used.

What is the difference between the simple and managed modes?

In simple mode you give Storycap a Storybook URL and it captures everything with default settings, with no configuration of your Storybook needed. In managed mode you register storycap as an addon and use the withScreenshot decorator, so each story can declare its own delay, viewport, interaction and skip settings.

How do I capture one story at several viewport sizes?

Use the viewport and viewports options together with variants. The viewports option accepts an array of strings or an object mapping variant names to viewports, and the README documents a section on getting multiple PNGs from one story, including variants composition.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. reg-viz/storycap on GitHub
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/reg-viz-storycap.svg)](https://hysenlabs.com/projects/reg-viz-storycap)

Was this useful?