Advanced usage
This page is your last stop before the API reference for trickier setups, scale/perf tuning, and production-hardening.
If you haven’t yet, first follow Quick Start and Integration with Storybook
to get a green run, then return here to refine.
Handling dynamic content effectively
-
Dynamic match level Prefer the Dynamic match level for pages with emails, timestamps, or randomized data. Combine with
ignoreRegions/floatingRegionsfor animations and moving containers.Per-story example (CSF):
export const PriceCard = {
parameters: {
eyes: {
matchLevel: 'Dynamic', // tolerate fluctuating minor text
},
},
}; -
Ignore regions Use ignore regions for truly irrelevant content (ads/timestamps). Use floating regions when something moves within bounds (snackbars/toasts).
export const WithToast = {
parameters: {
eyes: {
ignoreRegions: [{ selector: '.timestamp' }],
floatingRegions: [
{
selector: '.toast',
maxUpOffset: 10,
maxDownOffset: 10,
maxLeftOffset: 40,
maxRightOffset: 40,
},
],
},
},
}; -
Make stories deterministic (pro tip)
Eyes appends
?eyes-storybook=trueto the story iframe. Branch off it to freeze dates/seeds.const params = new URL(window.location.href).searchParams;
if (params.get('eyes-storybook')) {
(window as any).__NOW__ = new Date('2025-01-01T00:00:00Z');
Math.random = () => 0.42;
}
Asynchronous UIs & interactions
If a story uses Storybook play (interactions), Eyes captures after the play function finishes.
Then any waitBeforeCapture delay applies.
- Prefer
navigationWaitUntil: 'networkidle2'for UIs with long async work. - In interactions, favor explicit readiness markers (data-ready, aria-busy=false) over sleeps.
// applitools.config.js
module.exports = {
navigationWaitUntil: 'networkidle2',
waitBeforeCapture: '#ready', // or a global predicate as above
};
Network hygiene & performance
Trim noise and speed up cycles:
-
Block chatter:
npx eyes-storybook --networkBlockPatterns "*/ads/*,*/analytics/*"Or in config:
module.exports = { networkBlockPatterns: ['*/ads/*', '*/analytics/*'] }; -
Cache requests:
module.exports = { browserCacheRequests: true }; -
Subset locally, go broad in CI:
npx eyes-storybook --include /Button:.*/ -
Avoid unnecessary full-page capture: keep
fullyfor pages/containers that truly need it.
Concurrency & throughput tuning
Balance speed vs. resources/quota.
- Local tab fan-out (
APPLITOOLS_CONCURRENT_TABS) Default is 3. Increase cautiously on small CI runners.export APPLITOOLS_CONCURRENT_TABS=5
Monorepos & multiple Storybooks
- Use
storybookConfigDirto point Eyes to the right.storybookper package. - Run separate batches per package to keep results focused.
Theming, locales, and feature flags
Drive stories with globals/args and run Eyes with different permutations using --include filters or multiple CI jobs;
tag each run with properties (theme=dark, locale=fr‑FR, etc.).
Docker & CI hardening
If Chrome struggles in containers, set runInDocker: true or override puppeteerOptions.executablePath.
Ensure enough shared memory and fonts are available.
Prefer serving a static Storybook in CI, then run Eyes against its URL.
# GitHub Actions sketch
- run: npm run build-storybook
- run: npx http-server storybook-static -p 6006 &
- run: npx eyes-storybook -u http://localhost:6006 -e
env:
APPLITOOLS_API_KEY: ${{ secrets.APPLITOOLS_API_KEY }}
Root Cause Analysis (RCA) for encoded DOM/CSS
Provide a domMapping JSON to map hashed identifiers back to readable names:
module.exports = { domMapping: './dom-mapping.json' };
// { "abcd": "cls-button", "qwerty": "var-color" }