All docs
Recipes3 min readUpdated

Detect the capture environment with isUIVerify

isUIVerify() is true only while UI Verify captures a render, so a component can freeze animations or a live clock just for the screenshot. The isChromatic equivalent.

isUIVerify() is a small helper that returns true only while UI Verify is capturing your UI. Call it inside a component to branch to a deterministic end state during a capture - freeze a running animation, render the final frame of a chart, drop a live clock - while keeping the real behaviour in production. It is the UI Verify equivalent of Chromatic's isChromatic().

Reach for it only when a media query or fixture data cannot: an infinite JS animation, a charting library's animate-on-mount prop, a <canvas> render loop. Determinism at capture time is the first fix - see Fix flaky visual tests - and isUIVerify() is the escape hatch for the JavaScript that determinism cannot reach from outside.

Add the helper

UI Verify does not ship this as a package to install - paste this zero-dependency helper into your project and import it wherever a component needs to know it is being captured. It reads the markers UI Verify sets on every capture, plus a UI_VERIFY env var for server-side rendering.

isUIVerify.ts
// True while UI Verify is capturing this render. Zero dependencies - safe in a production bundle.
export function isUIVerify(): boolean {
  // Server-side rendering / build time: no window, so read an env var set for the capture run.
  if (typeof process !== "undefined" && process.env.UI_VERIFY) return true;
  if (typeof window === "undefined") return false;
  // Browser capture (Storybook, Playwright, Vitest): the capturer sets a UA marker and a global.
  const ua = window.navigator?.userAgent ?? "";
  return ua.includes("UIVerify") || "__UI_VERIFY__" in window;
}

Use it in a component

The common case is an animation that plays forever, so the screenshot catches it at a different frame each run. Branch the animating prop on isUIVerify() so the component renders its resting frame under capture and animates normally for real users.

tsx
import { isUIVerify } from "./isUIVerify";

// A charting library that animates on mount: freeze it only while capturing.
<LineChart isAnimationActive={!isUIVerify()} data={data} />;

How detection works

A render happens in one of two places, so the helper checks both. In the browser - Storybook replay, and the Playwright and Vitest capture SDKs - the capturer sets a UIVerify marker on navigator.userAgent and a window.__UI_VERIFY__ global before any of your code runs, so isUIVerify() returns true automatically. Nothing to configure.

Server-side rendering and build time

If the decision runs where there is no window - a server-rendered or statically built page captured through the Playwright archive - no browser marker can be set yet. For that case, set a UI_VERIFY environment variable on your app server for the capture run only, and the helper's process.env.UI_VERIFY check picks it up. Keep it unset in production so real users get the real behaviour.

Does this affect my production bundle?

No. The helper is a few lines with no dependencies, and in production every check is false: there is no UI_VERIFY env var, no capture marker on the user agent, and no __UI_VERIFY__ global, so isUIVerify() returns false and your component takes its normal path.

Coming from Chromatic? This replaces isChromatic() one-for-one - a migrated isChromatic() call returns false under UI Verify until you swap it for isUIVerify(). Your coding agent can do the swap with the Storybook determinism skill.

Visual testing for agents

UI Verify captures your UI on every pull request and an AI judge tells an intended change from a real regression. See how it works.

Get started