tutorial

Monitoring Chromatic Visual Tests with Vigilmon: Detect When Visual Regression Checks Stop Running

Use Vigilmon heartbeat monitors to detect when your Chromatic visual testing CI steps are silently skipped — so regressions never ship because the visual gate stopped working.

Your Chromatic visual regression gate had been protecting the design system for months. Then a refactor introduced a token in the Chromatic configuration that expanded to an empty string in the CI environment. The chromatic CLI ran, found zero changed stories, published an empty snapshot set, and exited 0. Every subsequent PR merged without a visual review — because Chromatic thought there was nothing to review.

Visual testing tools protect against unintended UI changes. But who protects you when the visual testing tool itself goes quiet? This tutorial shows you how to use Vigilmon heartbeat monitors to detect when your Chromatic CI step stops running, stops publishing, or stops catching changes.

What You'll Cover

  • Heartbeat monitoring for Chromatic publish runs in CI
  • Detecting when Chromatic publishes zero-story snapshots silently
  • Alerting on Chromatic runs that are skipped due to CI configuration drift
  • Monitoring Chromatic TurboSnap to catch when it incorrectly skips stories
  • CI integration for GitHub Actions and GitLab CI
  • Multi-branch monitoring (main baseline vs. PR checks)

Prerequisites

  • Chromatic configured in your Storybook project (npm install --save-dev chromatic)
  • A Chromatic project token
  • A free account at vigilmon.online

The Problem: What Chromatic's Status Checks Can't Catch

Chromatic integrates with your GitHub/GitLab status checks to block PRs with unreviewed visual changes. This works well for changes — but it can't protect you when:

  • The CI job that runs chromatic is accidentally removed or given a when: never condition
  • A missing or corrupted CHROMATIC_PROJECT_TOKEN causes the CLI to exit 0 with a warning
  • TurboSnap incorrectly marks all stories as unchanged and snapshots none of them
  • The Storybook build fails before Chromatic is invoked, and the CI step is marked as skipped
  • A scheduled baseline rebuild is dropped after a pipeline migration

From Chromatic's perspective, PRs that never trigger a run simply have no status check — they don't fail, they're just missing. Teams may merge those PRs assuming the check passed.

Vigilmon's heartbeat monitors treat a missing check as an alert condition.


Step 1: Create a Heartbeat Monitor in Vigilmon

  1. Log in to Vigilmon and click New Monitor → Heartbeat.
  2. Name it Chromatic — Main Baseline Publish.
  3. Set Expected interval to match your main-branch build cadence. If you merge to main multiple times per day, use 4 hours; for teams that merge daily, use 25 hours.
  4. Set Grace period to 30 minutes to absorb Storybook build time.
  5. Save and copy the Ping URLhttps://vigilmon.online/api/heartbeat/<unique-id>.

Step 2: Ping Vigilmon After a Successful Chromatic Publish

Add the heartbeat call as a CI step that fires after chromatic exits with code 0. The step should only run for your baseline branch (usually main or master) to avoid noise from PR runs.

GitHub Actions

# .github/workflows/chromatic.yml
name: Chromatic Visual Tests

on:
  push:
    branches: [main]
  pull_request:

jobs:
  chromatic:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # Required for TurboSnap change detection

      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Publish to Chromatic
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
          exitZeroOnChanges: true
          autoAcceptChanges: "main"

      - name: Ping Vigilmon heartbeat (main branch only)
        if: success() && github.ref == 'refs/heads/main'
        run: |
          curl -fsS -X POST "${{ secrets.VIGILMON_CHROMATIC_HEARTBEAT_URL }}" \
            --max-time 10 --retry 3 --retry-delay 5

The github.ref == 'refs/heads/main' guard ensures only baseline publishes trigger the heartbeat, not PR snapshots.

GitLab CI

# .gitlab-ci.yml
chromatic:publish:
  stage: test
  image: node:20
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  variables:
    CHROMATIC_PROJECT_TOKEN: $CHROMATIC_PROJECT_TOKEN
  before_script:
    - git fetch --unshallow   # Required for TurboSnap
    - npm ci
  script:
    - npx chromatic --project-token "$CHROMATIC_PROJECT_TOKEN" --exit-zero-on-changes --auto-accept-changes
    - |
      curl -fsS -X POST "$VIGILMON_CHROMATIC_HEARTBEAT_URL" \
        --max-time 10 --retry 3 --retry-delay 5
      echo "Vigilmon heartbeat sent"

Step 3: Detect Zero-Story Snapshots

When Chromatic publishes but captures zero stories (misconfigured Storybook, TurboSnap over-pruning), it exits 0 but has done nothing useful. Add a guard that checks the publish output before sending the heartbeat:

      - name: Publish to Chromatic
        id: chromatic
        uses: chromaui/action@latest
        with:
          projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
          exitZeroOnChanges: true
          autoAcceptChanges: "main"

      - name: Verify snapshot count
        run: |
          SNAPSHOT_COUNT="${{ steps.chromatic.outputs.storybookCount }}"
          if [ -z "$SNAPSHOT_COUNT" ] || [ "$SNAPSHOT_COUNT" -eq "0" ]; then
            echo "ERROR: Chromatic published 0 stories — TurboSnap or Storybook config issue"
            exit 1
          fi
          echo "Chromatic published $SNAPSHOT_COUNT stories"

      - name: Ping Vigilmon heartbeat
        if: success() && github.ref == 'refs/heads/main'
        run: |
          curl -fsS -X POST "${{ secrets.VIGILMON_CHROMATIC_HEARTBEAT_URL }}" \
            --max-time 10 --retry 3 --retry-delay 5

The snapshot count gate catches the silent zero-story case before the heartbeat is sent.


Step 4: Nightly Baseline Rebuild Monitoring

Teams using Chromatic's --force-rebuild for scheduled baseline refreshes need a separate heartbeat:

# .github/workflows/chromatic-nightly.yml
name: Chromatic Nightly Baseline Rebuild

on:
  schedule:
    - cron: "0 4 * * 1-5"   # 04:00 UTC Monday–Friday

jobs:
  chromatic-rebuild:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Rebuild Chromatic baseline
        run: |
          npx chromatic \
            --project-token "$CHROMATIC_PROJECT_TOKEN" \
            --force-rebuild \
            --auto-accept-changes \
            --exit-zero-on-changes
        env:
          CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

      - name: Ping Vigilmon heartbeat
        if: success()
        run: |
          curl -fsS -X POST "${{ secrets.VIGILMON_CHROMATIC_NIGHTLY_HEARTBEAT_URL }}" \
            --max-time 10 --retry 3 --retry-delay 5

Create a second Vigilmon heartbeat monitor (Chromatic — Nightly Rebuild) with a 25-hour interval and 1-hour grace period to cover weekday runs.


Step 5: Multi-Monitor Setup

| Monitor | Name | Interval | What it catches | |---|---|---|---| | Heartbeat | Chromatic — Main Baseline Publish | 4–25 h | Missed main-branch publishes | | Heartbeat | Chromatic — Nightly Rebuild | 25 h | Scheduled baseline rebuild failures | | HTTP | Chromatic — Project URL | 5 min | Chromatic service outage affecting reviews |

For the HTTP monitor, use your project's Chromatic review URL and set a keyword check on a string that appears in Chromatic's review UI (e.g., chromatic).


Step 6: Configure Alert Channels

In Vigilmon, go to Notifications → New Channel and configure:

  • Email — immediate alert to your design systems or frontend platform team
  • Slack webhook — ping your #visual-regression or #design-system-alerts channel

Sample missed-heartbeat notification:

🔴 MISSED HEARTBEAT: Chromatic — Main Baseline Publish
Last ping: 27 hours ago
Expected interval: 25 hours

Recovery notification:

✅ HEARTBEAT RECOVERED: Chromatic — Main Baseline Publish
Gap: 27 hours

What You're Now Catching

| Silent failure mode | How Vigilmon detects it | |---|---| | CI job that runs Chromatic is deleted | No ping arrives → alert after grace period | | Missing CHROMATIC_PROJECT_TOKEN | CLI exits 0 with warning, no heartbeat sent → alert | | Storybook build fails before Chromatic runs | No heartbeat → alert | | TurboSnap skips all stories (zero snapshots) | Snapshot count guard fails, no heartbeat → alert | | Nightly baseline rebuild job is dropped | No ping at expected interval → alert | | Chromatic service outage | HTTP monitor detects 5xx or keyword missing → alert |


Chromatic catches the visual regressions your code reviewers miss — but only when it actually runs. Vigilmon's heartbeat monitors give you the external signal Chromatic can't provide about itself: a definitive alert when your visual testing pipeline hasn't produced a baseline in longer than expected.

Add Vigilmon to your Chromatic pipeline today — register free at vigilmon.online.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →