How to Use Loki for Visual Regression Testing in React
Use Loki to capture Storybook stories, compare them with committed baselines, and review visual changes in React locally and in CI.
Loki runs visual regression tests against Storybook stories: it captures screenshots, compares them with reference images, and shows differences for review. In a React project, the core workflow is to install Loki, start Storybook, create and commit a baseline, then run loki test after changes. Review every difference before accepting it. Loki does not start Storybook for you, and visual comparisons do not replace interaction, accessibility, or unit tests.
1. Prepare React stories and install Loki
Represent the UI states that matter as Storybook stories before adding snapshots. Include states such as loading, empty, error, disabled, long content, and relevant themes or sizes. A screenshot test only covers the story and rendering conditions it captures.
The Loki getting-started guide lists Node 16+ and documents installation with Yarn. That guide was last updated in 2024, so treat its compatibility details as historical guidance and check the Loki version, your Storybook version, and your CI runtime before adopting them.
# From the React project root
yarn add --dev loki
yarn loki init
With npm, the equivalent dependency installation is:
npm install --save-dev loki
npx loki init
The initializer detects the project and adds a default Loki configuration, usually in package.json. Review the generated targets and viewport dimensions instead of assuming they match your production UI. Web defaults described in Loki’s guide use laptop and iPhone configurations with local Chrome. You can choose configurations by name; the guide documents selecting names with a regular expression, for example a configuration containing laptop.
For recent Storybook versions, the guide says no extra integration should normally be needed. Older setups may require importing loki/configure-react from .storybook/preview.js. Confirm whether your installed Loki and Storybook versions require that step; do not add legacy setup blindly.
See the Loki getting-started guide and the Loki project site for the project’s documented setup and supported targets.
2. Start Storybook and create the first baseline
Start the Storybook server in a separate terminal. Loki connects to the running Storybook and captures its stories; it does not launch the server itself. Loki’s README explicitly says to make sure Storybook and any simulator or emulator are running before tests.
# Terminal 1: use your project's existing Storybook script
yarn storybook
# Terminal 2: create initial reference images
yarn loki update
If the project uses npm scripts, run the corresponding configured Storybook script, such as npm run storybook, then run npx loki update. The command name depends on the scripts already in your project.
On its first update, Loki captures the current stories as reference images. These are the expected appearance against which later runs compare. Inspect the results to make sure the server loaded the intended stories, fonts, assets, and environment before treating them as a valid baseline. Commit the reference images to version control. Loki’s guide says Git LFS is an optional way to store them.
3. Run comparisons and review visual differences
After changing a component, styling, or story, run Loki’s test command against the same Storybook setup:
yarn loki test
Loki captures the stories again and compares those images with the references. Its getting-started guide documents current captures under loki/current and visual differences under loki/difference. The CLI reference also documents configurable reference-image, current-output, and difference-image directories; check your generated config and installed CLI documentation for the exact options supported by your version.
- Open each reported difference image alongside the reference and current capture.
- Decide whether the change is an unintended regression, a test setup issue, or an expected design change.
- Fix regressions and rerun the test.
- For an intentional change, approve the changed reference using
yarn loki approveor the command Loki prints for updating only failed tests. - Review and commit the reference-image change with the implementation that caused it.
Approval changes what future runs consider correct. Do not approve all changed snapshots without inspecting them.
4. Add Loki to continuous integration
A practical CI pattern is to build Storybook as static files, then tell Loki to read that build. Loki’s official CI guide uses --requireReference and --reactUri file:./storybook-static. Requiring references makes CI fail when a story has no baseline, helping prevent a test run from silently establishing its own expected output.
# Example package.json scripts; adapt to the scripts your project uses
{
"scripts": {
"build-storybook": "storybook build",
"test:visual": "loki test --requireReference --reactUri file:./storybook-static"
}
}
For example, a GitHub Actions job can install dependencies, build Storybook, and run the visual tests:
name: Visual regression
on:
pull_request:
push:
branches: [main]
jobs:
loki:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
- run: yarn install --frozen-lockfile
- run: yarn build-storybook
- run: yarn test:visual
This is a workflow shape, not a promise that every Loki, Storybook, Node, and browser combination works together. Use the package manager and lockfile for your repository, select a supported Node version based on the installed dependency versions, and configure the Loki browser target and dependencies for the runner. The Loki README recommends Chrome in Docker and also lists local Chrome, Chrome in AWS Lambda, iOS simulator, and Android emulator targets. Docker is needed for the documented chrome.docker target; GraphicsMagick is optional for the gm diff engine.
Keep CI focused on detecting changes. Do not run loki update or approve changed references automatically in the verification job. Review and commit baseline updates deliberately so a pull request shows both the code and its expected visual result.
5. Choose targets and tune comparisons
| Decision | Guidance |
|---|---|
| Browser target | Loki documents Docker Chrome as its recommended target, as well as local Chrome and other platform targets. A controlled browser environment makes it easier to keep captures consistent across developers and CI. |
| Viewport and configuration | Review generated configuration dimensions and names. Use the target sizes your team needs; a desktop capture cannot detect a mobile-only layout regression. |
| Static build or server | For CI, Loki documents serving a static Storybook build through --reactUri file:./storybook-static. For local work, start the development Storybook server first. |
| Diff engine | The CLI reference lists pixelmatch, looks-same, and gm. GraphicsMagick is an optional dependency for the gm engine. Consult the reference for the supported configuration keys and defaults in your installed version. |
| Baseline storage | Commit references with the code so changes are reviewable. Git LFS is an optional storage approach mentioned by Loki’s guide when image files warrant it. |
There is no universally correct threshold or target set: the right choice depends on the precision your project needs and how stable its rendering environment is. Avoid changing comparison settings simply to hide a real regression. If you use named Loki configurations, the documented regex selection can let you run a focused subset, such as a laptop configuration, while iterating.
6. Make screenshot tests repeatable
- Use deterministic story data. Avoid random values, current timestamps, rotating content, and network responses that change between runs. Fix or mock them in the story environment.
- Wait for the UI to settle. Ensure fonts, images, animations, and asynchronous state are ready before the capture. Disable or stabilize motion in test mode when it causes inconsistent frames.
- Keep the rendering environment consistent. Browser version, operating system, fonts, device scale, viewport, and color settings can affect pixels. Prefer the same target and CI image for baseline creation and comparison.
- Keep stories purposeful. Each visual test should represent a meaningful state. Large, redundant story sets increase capture time and review effort.
- Review reference changes with code. A baseline is test data. Treat edits as part of the change review, not disposable generated output.
7. Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| Cannot connect to Storybook or no stories are captured | The Storybook server is not running, the port or URI is wrong, or the static output path does not match the build. | Start Storybook separately for local runs. In CI, confirm the build completed and the --reactUri path points to the generated directory. Check the configured Storybook port and URI. |
| CI reports a missing reference | A story is new, the reference directory is missing from the checkout, or the wrong reference path is configured. | Run loki update in the intended environment, review the new reference, and commit it. Check that CI checks out the committed reference files and uses the matching configuration. |
| Many unrelated pixels change between runs | Rendering differs due to browser or OS changes, missing fonts, animation, dynamic data, or assets loading at different times. | Stabilize test data and motion, verify assets and fonts are available, and align the local and CI capture environment. Recreate baselines only after confirming the new environment is intended. |
| Browser target fails to launch | The target’s prerequisites are unavailable; for example, the Docker target needs Docker, and local Chrome requires a compatible Chrome installation. | Install or enable the required runtime for the selected target, or choose a target supported by the environment. Verify compatibility against your installed Loki version rather than relying on old version numbers. |
gm diff engine errors |
GraphicsMagick is not installed or is not available on the process path. | Install GraphicsMagick if you selected the gm engine, or choose another documented engine supported by your configuration. |
| Old Storybook integration fails | The project may require a compatibility setup that newer Storybook versions do not need, or vice versa. | Check the Loki integration guidance for the installed versions. The guide mentions loki/configure-react for some older setups; add it only if your version combination requires it. |
| Diffs are hard to interpret | Current and reference files may be confused, or the selected story set may include states that are not relevant to the change. | Open the reference, current capture, and difference output together. Confirm the affected story and configuration before approving or changing thresholds. |
8. Performance, reliability, and cost
Loki runs captures in the browser target you configure. Total runtime depends on the number of stories, target configurations, browser startup, and the rendering work each story performs. The supplied Loki documentation does not provide a general benchmark, so measure the workflow in your repository rather than relying on a universal runtime estimate.
For reliability, make the CI browser and Storybook build reproducible, keep baselines under version control, and require references during CI. A capture failure is not evidence that the UI is correct; distinguish browser startup, page loading, and comparison failures from a visual difference that needs review.
Loki is installed as a development dependency and the documented baseline workflow stores image files in the repository, optionally using Git LFS. The research sources do not specify Loki service pricing. If a team prefers a hosted visual review workflow, Storybook’s current visual testing guide describes its Chromatic addon as a hosted option; its setup and terms are separate from Loki. See Storybook’s visual testing guide.
Or skip the browser setup
Loki is designed to compare Storybook stories against baselines. For a one-off screenshot of a deployed page, ScreenshotNeo provides a website screenshot API and MCP server. It does not replace Loki’s story-by-story baseline review, but avoids running a browser capture stack for a URL screenshot.
One GET request returns an image or PDF. This cURL example saves a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python equivalent:
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)
Node.js equivalent:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));
Read the ScreenshotNeo API documentation for authentication, formats, and request options. Cookie banners, newsletter popups, and chat widgets are removed before capture; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. The MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 screenshots. Every feature is on every plan.
Sign up for ScreenshotNeo and get 1,000 screenshots a month free, with no card required.
FAQ
Does Loki test React components directly?
Loki captures the stories rendered by Storybook. Put the React component states you want checked into stories, then let Loki compare their rendered screenshots.
Should I commit Loki screenshots?
Commit the reference images so changes to the expected UI can be reviewed with the code. Loki’s guide also mentions Git LFS as an optional way to store them.
Can Loki tell whether a visual change is a bug?
No. It identifies image differences. A developer must decide whether each difference is an unintended regression, an environmental inconsistency, or an intentional UI change.
Does a passing visual test prove the component works?
No. It indicates that the captured appearance matched its baseline under the configured conditions. Keep behavior and accessibility checks in your test strategy as well.


