Integrates with your Storybook

UI regression testing for the AI era

More UI is being written, faster, by more people and AI agents than ever, and few of them see what they shipped. Merrykat renders every story in your Storybook on both sides of a pull request, works out what actually changed, and tells you whether it looks intentional.

A CI agent for the visual parts of your app

Like an AI reviewer for your code, but for the UI: it renders your components before and after the change, works out what is actually different, checks both sides for accessibility, and writes up what it found, with the screenshots to back it up. It all lands on the pull request, where the rest of the review already happens.

merrykat[bot]commented 2 minutes agoBot

✅ Looks good — 8 stories changed, and every change examined looks intentional, with no new accessibility violations.

A single color-token change, applied consistently: every diff is the primary blue darkening by one step, with no layout or text changes anywhere.

🟢 Looks intentionalForms/Button / Primary: primary button color is now a darker blue

The primary action button has moved from the previous mid-blue to a noticeably darker shade, with the hover state following it.

  • Verdict 🟢 Looks intentional (low severity, confidence 92%)
  • Matches the code change in this pull request
  • Also affects 7 other stories in the same way

9f3c2a1 vs baseline 4e1d9c0 (merge base) · 8 of 517 stories changed · 4m 12s · full results

A note from the people behind Merrykat

We started Happo in 2014, when screenshots were produced by PhantomJS, and a layout that looked fine in Firefox could still break in Internet Explorer. When we still used floats and absolute positioning for layout. Happo was built to catch those breakages in the browsers people actually used. Twelve years on, teams of every size build their pipelines on it. As one of our customers put it, “Happo is the AWS of visual regression testing.”

Merrykat is what we would build if we started over today, with agents writing more and more of the UI and nobody looking at every screenshot. Five lessons from those twelve years shaped it more than anything else:

  1. Most screenshots are never looked at. So Merrykat only takes them when there is something to compare, and does not keep them for long.
  2. A stored baseline drifts. Fonts and browsers update, and yesterday’s image stops being a fair comparison. We render both sides of the pull request together, in the same browser at the same moment, and compare them on the fly.
  3. One change is rarely one diff. A token tweak can touch a hundred stories. Sampling and grouping are built in, so it gets examined once.
  4. A diff without context is a guess. The code that changed, the story it touched, the accessibility tree on both sides: the more we know, the better the call.
  5. Feedback belongs where the work is. Results go on the pull request, keeping you in your flow and giving an agent on the branch something it can act on quickly.

We are still learning, and expect to keep learning for a while — this is a new kind of tool, for a new way of building software.

Happo isn’t going anywhere. It remains the tool for cross-browser coverage and for teams who want full control over their pipeline, and we keep building it. Merrykat sits next to it, for teams who would rather be told what changed than shown.

  • Henric
  • Joe

What you get

Accessibility baked in

button-name — new, 1 element · 0 pre-existing.

Every story runs through axe-core on both sides, in the same browser as the screenshot. Only what your pull request newly broke or fixed is reported — never the violations you inherited.

Only renders what could have changed

8/517 stories checked · the rest identical at source.

A build that can say which stories are byte-identical between the two commits gets those skipped entirely. A sample is compared anyway on every run, so a generator that stops following a dependency is caught rather than trusted forever.

Dark mode, light mode, every viewport

Each viewport renders and diffs on its own.

A viewport can be a size, or a media feature under test: prefers-color-scheme, prefers-contrast and forced-colors each render and diff on their own. Dark mode is a viewport, not a separate test suite.

Flakiness tracked automatically

Differed once across identical captures → treated as unchanged.

A story that differs between two captures moments apart is recorded as flaky and treated as unchanged, not hidden behind a tolerance threshold. Repeat offenders are quarantined: longer settle time, an extra attempt, and a named list.

Summarized in the pull request

One comment per commit and one check run: what changed, what broke, and a recommendation on each. A new push marks the previous comment outdated so the latest sits at the bottom of the conversation. The check outcome is decided by the engine, never by the model — genuine breakage fails it whether the model agrees or not.

Secure by design

  • No repository contents permission
  • No network access while rendering
  • Diff encrypted per installation
  • Short-lived assets and run details

The GitHub App holds no permission to read your repository’s contents at all, and stories render with no network access whatsoever.

Getting started

Three steps to get you started

1. Install the GitHub App

Pick the repositories it should watch. The page it lands you on shows the CI workflow, ready to copy.

2. Upload your Storybook build from CI

Run it on pull requests and on pushes to your default branch — those default-branch builds are what baselines resolve to.

3. Configure it, if you want to

The defaults are a desktop and a mobile viewport with the accessibility pass on. Everything else is optional.

merrykat.config.ts
export default {
  viewports: [
    { name: 'desktop', width: 1280, height: 800, accessibility: true },
    { name: 'mobile', width: 420, height: 700 },
    {
      name: 'dark',
      width: 1280,
      height: 800,
      media: { colorScheme: 'dark' },
    },
  ],
  accessibility: { enabled: true },
};

FAQ

Do I need Storybook?
Yes. Merrykat compares two static Storybook builds, your pull request’s and its baseline’s, and renders every story in both. If your components don’t have stories yet, that’s the place to start.
Which Storybook versions and frameworks work?
Storybook 7 and later out of the box, and 6.x built with --build-stories-json. Merrykat renders the static build in a browser, so React, Vue, Angular, Svelte, Web Components and anything else Storybook supports all work the same way.
Do I need to write tests?
No. Every story is already a test case. Per-story settings go in parameters.merrykat, if you need any; see Configuration.

Ready for the future of UI regression testing?