How to run Loki screenshot tests in Docker
Set up Loki with Chrome in Docker, capture and review Storybook baselines, and troubleshoot common network and stability problems.
Short answer: Start your Storybook server, configure Loki to capture stories with Chrome in Docker, create approved reference screenshots with loki update, and compare later captures with loki test. Review the screenshots and diffs before approving any changed references. Loki does not start Storybook for you.
This guide covers the local workflow and the Docker settings most likely to matter in CI. Loki’s getting-started and CLI documentation was last updated in 2024, so check the documentation matching your installed release before relying on historical version requirements or image defaults.
1. Install and initialize Loki
The documented starting point is Node.js 16 or newer, Yarn, and Docker. The Node requirement comes from historical Loki documentation; treat it as a guide rather than a promise about compatibility with current releases. Check the Loki and Storybook versions already in your project before changing them.
yarn add loki --dev
yarn loki init
If your project uses npm, install Loki as a development dependency and invoke the local binary through your package scripts or npx. The examples below use Yarn because that is the documented Loki workflow.
Initialization creates or updates Loki configuration for the project. Inspect the resulting config and keep it under version control. A typical setup selects the chrome.docker target; exact generated fields can vary by Loki release.
2. Start Storybook before capturing
Run Storybook in a separate terminal and leave it running while Loki captures stories:
yarn storybook
Loki must be able to reach that server to discover and render stories. If Storybook uses a non-default host or port, pass the matching values to Loki. For example, the CLI documentation demonstrates forwarding a port option through Yarn like this:
yarn loki test -- --port 9009
Use the argument-forwarding syntax supported by your installed package manager and Loki version. A port override only helps if Storybook is actually listening on that port and Docker can reach it.
3. Configure Chrome in Docker
Loki’s supported target name is chrome.docker. The CLI documents several Docker-specific options:
| Option | What it controls | When to consider it |
|---|---|---|
--chromeDockerImage |
The Chrome container image Loki starts. | When you need an image compatible with your Loki release or want a controlled browser image. |
--dockerNet |
The Docker network mode, such as host or bridge. |
When the Chrome container cannot reach the Storybook server using the current network setup. |
--chromeDockerUseCopy |
Copies local stories instead of relying on a volume mount. | When the default mounted files are not available as expected in your Docker or CI environment. |
--dockerWithSudo |
Runs Docker commands with sudo. |
When the environment requires elevated privileges to invoke Docker. |
The CLI page lists yukinying/chrome-headless-browser-stable:118.0.5993.117 as its default Chrome Docker image. That is a historical documented value, not a current recommendation. Check the installed Loki release’s docs and the image requirements before pinning or replacing it.
Options can be passed to Loki through the package manager. For instance, a port argument is shown with a separator after the script name. Apply the same forwarding convention to Docker options, and confirm the accepted names and values with your installed Loki CLI.
yarn loki test -- --dockerNet bridge
There is no universally correct network mode. Choose one that lets the browser container reach the host and port serving Storybook in your environment. Likewise, choose between a mount and copy mode based on how your local files are exposed to Docker.
4. Create baselines and run comparisons
- Start Storybook and wait until it is ready to serve stories.
- Create the initial reference screenshots:
yarn loki update
- Inspect the generated references. Loki documents
./.loki/referencefor approved references,./.loki/currentfor the latest captures, and./.loki/differencefor visual diffs. - Commit approved baseline images to version control. Git LFS is optional according to the getting-started guide and may be useful if your baseline set is large.
- For later changes, capture and compare against the committed baseline:
yarn loki test
When a test reports differences, inspect both the current screenshot and the difference image. If the UI change is intentional and the new render is correct, update the reference:
yarn loki approve
Approve only after review. Some Loki versions also suggest a command to approve only failed stories; use the exact command shown by your installed version if you need that narrower workflow.
5. Make screenshot tests stable
Control network-dependent stories
Loki’s configuration documentation says a failed network request fails the test by default. Avoid letting screenshots depend on live third-party APIs, changing production data, or services that are unavailable in CI. Stub requests or provide fixed fixtures so each story renders the same intended state on every run.
Disable animation when it causes timing differences
Animations can make captures differ depending on when Chrome takes the screenshot. Loki documents the chromeEnableAnimations option for disabling animations. Use it when motion is not part of what the test is meant to verify; if animation appearance is itself under test, control the state and timing in the story instead.
Signal completion for asynchronous stories
Stories that render after asynchronous work may be captured too early. The Loki flaky-test guidance describes an async callback pattern for explicitly signaling that rendering is complete. Use the API supported by your installed Loki version and make the signal happen only after the visual state is ready.
6. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Loki cannot find or load stories | Storybook is not running, is not ready, or Loki is pointed at the wrong host or port. | Start Storybook first, wait for readiness, and confirm the host and port passed to Loki match the server. |
| The Chrome container cannot connect to Storybook | The configured Docker network does not provide the needed route to the host server. | Check the host and port from the container’s perspective; try a suitable --dockerNet mode for your environment. |
| Chrome starts but files or stories are missing | The container’s volume mount cannot see the project files. | Review the mount and working directory. Try --chromeDockerUseCopy if copying stories fits the environment. |
| Docker permission denied | The current user cannot invoke Docker. | Configure Docker access for that environment or use --dockerWithSudo where sudo is the established CI or local setup. |
| Unexpected diffs between identical commits | Animations, asynchronous rendering, fonts, data, or external requests are not deterministic. | Disable irrelevant animation, signal async completion, control network data, and ensure required assets are available consistently. |
| A network failure causes a test failure | A story’s request failed, which Loki treats as a failure by default. | Mock the request or provide deterministic test data; check whether the request is expected and reachable in the test environment. |
| Every story appears changed after a browser update | The Chrome image or rendering environment changed relative to the approved references. | Check the image tag and Loki version. Review the diffs as a possible rendering change before approving new references. |
| A CLI option is rejected or ignored | The option name, value, or package-manager forwarding syntax differs from the installed version. | Check that release’s CLI documentation and ensure arguments are passed through to Loki rather than consumed by Yarn or npm. |
7. Performance, reliability, and baseline maintenance
Capture time depends on the number and complexity of stories, browser startup, page rendering, and network activity. Keep stories focused and independent, avoid unnecessary live requests, and use a stable Chrome image to reduce environmental variation. The Loki sources describe project aims such as reproducibility and CI support, but do not provide performance guarantees or benchmark figures.
For reliable CI runs, make the Storybook startup step explicit, wait for readiness, and use the same Loki, Chrome image, and relevant configuration across runs. Store approved references alongside the code so reviewers can see when a baseline changes. A cache or artifact system can reduce repeated setup costs in CI, but ensure it does not silently substitute stale reference images.
Review the generated current images and diffs before accepting changes. The .loki output folders help distinguish the committed reference from the new capture and the visual difference. Clean up or archive generated output according to your repository workflow, while preserving the approved references used for future comparisons.
Or skip the browser setup
If you need a screenshot of a page rather than Storybook component regression testing, ScreenshotNeo is a website screenshot API and MCP server. It does not replace Loki’s baseline comparison workflow; it handles website captures with one GET request. See the API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
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}`);
await Bun.write('shot.webp', res);
- Cookie and consent banners are accepted, while 60+ known consent platforms, newsletter popups, and chat widgets are removed before the shot; each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools for AI agents and MCP clients. - The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is available on every plan.
Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card required.
FAQ
Does Loki launch Storybook automatically?
No. Start the Storybook server before running Loki capture or comparison commands.
Should I commit the reference screenshots?
Yes. Committed references let local and CI runs compare against the same reviewed baseline. Git LFS is optional.
Should I approve every diff that Loki reports?
No. Approve only after checking that the changed screenshot reflects an intended UI update.
Can I use Loki for arbitrary website screenshots?
Loki’s workflow here is for capturing and comparing Storybook stories. For general website screenshot capture, use a screenshot API such as ScreenshotNeo.


