Skip to main content

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​

  1. Dynamic match level Prefer the Dynamic match level for pages with emails, timestamps, or randomized data. Combine with ignoreRegions/floatingRegions for animations and moving containers.

    Per-story example (CSF):

    export const PriceCard = {
    parameters: {
    eyes: {
    matchLevel: 'Dynamic', // tolerate fluctuating minor text
    },
    },
    };
  2. 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,
    },
    ],
    },
    },
    };
  3. Make stories deterministic (pro tip)

    Eyes appends ?eyes-storybook=true to 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 fully for 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 storybookConfigDir to point Eyes to the right .storybook per 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" }