tutorial

Monitoring Cypress Test Suites with Vigilmon: Catch Silent E2E Test Failures

Use Vigilmon heartbeat monitors to detect silent Cypress failures — scheduled test suite drift, stuck runners, and end-to-end tests that stop executing entirely.

Your nightly Cypress regression suite ran green for three weeks, then silently stopped on a Tuesday when someone reverted the CI config. Nobody noticed until a broken checkout flow reached 40,000 users. Cypress had no errors to report — it simply wasn't being invoked anymore.

This is the silent E2E test failure problem. HTTP monitors can't help because there's no endpoint to poll. The fix is heartbeat monitoring: Cypress pings a unique URL at the end of every successful run, and if Vigilmon doesn't receive that ping within the expected window, you get alerted.

This tutorial shows you how to instrument Cypress with Vigilmon heartbeat monitors so you always know when your end-to-end tests stop running.

What You'll Cover

  • Heartbeat monitoring for scheduled Cypress runs
  • Catching Cypress runs that stop triggering entirely
  • Alerting on test suites that fail silently or hang
  • Multi-environment E2E monitoring (staging and production)
  • Detecting test drift when CI schedules break

Prerequisites


The Problem: What Standard Cypress Monitoring Misses

Cypress Dashboard (now Cypress Cloud) tracks run history — but it won't alert you when:

  • The CI job that triggers Cypress is accidentally disabled
  • A branch filter excludes the trigger entirely
  • The cypress run command exits 0 because no specs matched the glob
  • Cypress Cloud's scheduled triggers are paused without notification
  • A runner machine is down and the queue silently backs up

Vigilmon's heartbeat pattern closes all of these gaps.


Step 1: Create a Heartbeat Monitor in Vigilmon

A heartbeat monitor expects a ping on a regular interval. No ping → alert.

  1. Log in to Vigilmon and click New Monitor → Heartbeat.
  2. Give it a name like Cypress E2E — Nightly.
  3. Set the Expected interval to match your test schedule. For a nightly run, use 24 hours. For pre-deploy smoke tests, use 4 hours with a 30-minute grace period.
  4. Set the Grace period to 1 hour for long suites (allow for slow browsers and retries).
  5. Save and copy the Ping URL — it looks like https://vigilmon.online/api/heartbeat/<unique-id>.

Step 2: Add a Vigilmon Plugin to Cypress

Create a Cypress plugin that sends the heartbeat after a fully successful run:

// cypress/plugins/vigilmon.js
const https = require("https");

function pingVigilmon(url) {
  return new Promise((resolve, reject) => {
    const req = https.request(url, { method: "POST" }, (res) => {
      resolve(res.statusCode);
    });
    req.on("error", reject);
    req.setTimeout(10000, () => {
      req.destroy(new Error("Vigilmon ping timed out"));
    });
    req.end();
  });
}

module.exports = { pingVigilmon };

Register it in your Cypress config:

// cypress.config.js
const { defineConfig } = require("cypress");
const { pingVigilmon } = require("./cypress/plugins/vigilmon");

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on("after:run", async (results) => {
        const heartbeatUrl = process.env.VIGILMON_HEARTBEAT_URL;
        if (!heartbeatUrl) return;

        // Only ping when all tests passed and none were pending
        if (results.totalFailed === 0 && results.totalPending === 0) {
          try {
            await pingVigilmon(heartbeatUrl);
            console.log("Vigilmon heartbeat sent");
          } catch (e) {
            console.error("Vigilmon heartbeat failed:", e.message);
          }
        }
      });
    },
    baseUrl: "http://localhost:3000",
    specPattern: "cypress/e2e/**/*.cy.{js,jsx,ts,tsx}",
  },
});

The after:run event fires after all specs complete. The heartbeat is only sent when totalFailed === 0 — failures suppress the ping, causing Vigilmon to alert after the grace period.


Step 3: Store the Secret and Run Cypress

Local development

VIGILMON_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id>" \
  npx cypress run

GitHub Actions

# .github/workflows/e2e.yml
name: E2E Tests

on:
  schedule:
    - cron: "0 2 * * *"  # 02:00 UTC nightly
  push:
    branches: [main]

jobs:
  cypress:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: npm ci

      - name: Start application
        run: npm run start:ci &
        # Wait for the server to be ready
      - name: Wait for server
        run: npx wait-on http://localhost:3000 --timeout 30000

      - name: Run Cypress tests
        env:
          VIGILMON_HEARTBEAT_URL: ${{ secrets.VIGILMON_E2E_HEARTBEAT_URL }}
        run: npx cypress run --browser chrome

      # Heartbeat is sent automatically by the after:run plugin hook.
      # If Cypress exits non-zero (test failures), no heartbeat is sent.

GitLab CI

# .gitlab-ci.yml
cypress:nightly:
  stage: test
  image: cypress/browsers:latest
  schedule:
    - cron: "0 2 * * *"
  variables:
    VIGILMON_HEARTBEAT_URL: $VIGILMON_E2E_HEARTBEAT_URL
  script:
    - npm ci
    - npm run start:ci &
    - npx wait-on http://localhost:3000
    - npx cypress run --browser chrome

Step 4: Handle Parallel Cypress Runs

When running Cypress in parallel across multiple machines, send the heartbeat only from the final machine after all shards complete. The cleanest approach is a post-run job:

# .github/workflows/e2e-parallel.yml
jobs:
  cypress:
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run start:ci &
      - run: npx wait-on http://localhost:3000
      - name: Run shard ${{ matrix.shard }}
        env:
          # No heartbeat URL here — set only in the heartbeat job below
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
        run: |
          npx cypress run \
            --record \
            --parallel \
            --ci-build-id "${{ github.run_id }}" \
            --shard ${{ matrix.shard }}/${{ strategy.job-total }}

  heartbeat:
    needs: cypress  # Only runs after ALL shards complete
    runs-on: ubuntu-latest
    if: success()
    steps:
      - name: Ping Vigilmon heartbeat
        run: |
          curl -fsS -X POST "${{ secrets.VIGILMON_E2E_HEARTBEAT_URL }}" \
            --max-time 10 \
            --retry 3 \
            --retry-delay 2

The needs: cypress + if: success() combination ensures the heartbeat fires only when every shard passed.


Step 5: Multi-Environment E2E Monitoring

For teams testing against staging and production:

| Suite | Environment | Monitor name | Interval | |---|---|---|---| | Nightly full regression | Staging | Cypress E2E — Staging — Nightly | 25 h | | Pre-deploy smoke | Staging | Cypress Smoke — Staging | 4 h | | Post-deploy verify | Production | Cypress Smoke — Production | 2 h | | Weekly accessibility | Staging | Cypress A11y — Weekly | 8 days |

Parameterize by environment:

// cypress.config.js
on("after:run", async (results) => {
  const env = config.env.TARGET_ENV || "staging";
  const heartbeatVar = `VIGILMON_${env.toUpperCase()}_HEARTBEAT_URL`;
  const heartbeatUrl = process.env[heartbeatVar];

  if (heartbeatUrl && results.totalFailed === 0) {
    await pingVigilmon(heartbeatUrl);
  }
});
TARGET_ENV=production VIGILMON_PRODUCTION_HEARTBEAT_URL="..." npx cypress run

Step 6: Alert Channels

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

  • Email — immediate alert when a heartbeat is missed
  • Slack webhook — ping your #qa-alerts or #e2e-tests channel

When a Cypress suite stops pinging:

🔴 MISSED HEARTBEAT: Cypress E2E — Nightly
Last ping: 26 hours ago
Expected interval: 24 hours

When it recovers:

✅ HEARTBEAT RECOVERED: Cypress E2E — Nightly
Gap: 26 hours

What You're Now Catching

| Silent failure mode | How Vigilmon detects it | |---|---| | CI job that triggers Cypress is disabled | No ping arrives → alert after grace period | | No specs match the glob (empty run exits 0) | No ping on 0-test run → alert | | Runner machine goes offline | No ping → alert after grace period | | Cypress hangs on a flaky test forever | Suite timeout → no ping → alert | | Branch filter accidentally excludes trigger | No ping → alert after grace period | | Cypress Cloud scheduled run paused | No ping → alert after interval |


Cypress gives you fast, reliable E2E tests — until the runner quietly disappears. Vigilmon's heartbeat monitors give you the external signal that Cypress itself can't provide: a definitive alert when your end-to-end tests haven't run in longer than expected.

Add heartbeat monitoring to your Cypress suite 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 →