tutorial

Monitoring Puppeteer Scripts with Vigilmon: Detect Silent Headless Chrome Failures

Use Vigilmon heartbeat monitors to alert when your Puppeteer headless Chrome automation scripts stop running — catch scheduler failures, hung browsers, and silent script exits.

Your Puppeteer script scraped a critical dashboard and checked a payment flow every six hours. Then a Chrome update changed how headless mode launched, and the script began silently exiting with code 0 before any page loaded. The monitoring data stopped updating. The team noticed — five days later, when someone asked why the dashboard had flatlined.

This is the silent automation failure problem. A Puppeteer script has no built-in "phone home" mechanism. It either runs and you hope it worked, or it doesn't run and you might never know. The fix is heartbeat monitoring: your script pings Vigilmon after each successful run, and Vigilmon alerts you when that ping stops arriving on schedule.

What You'll Cover

  • Heartbeat monitoring for scheduled Puppeteer scripts
  • Catching Puppeteer processes that exit silently or hang
  • Detecting Chromium/Chrome launch failures
  • Multi-script monitoring for different automation tasks
  • Alerting on scripts that time out or navigate to the wrong page

Prerequisites

  • A Puppeteer script (version 19+, or using puppeteer-core)
  • A free account at vigilmon.online

The Problem: What Standard Puppeteer Error Handling Misses

Puppeteer throws errors you can catch — but alerting you when no one invokes it at all is not Puppeteer's job. You're silently exposed when:

  • The cron job or scheduled task running Puppeteer is deleted or misconfigured
  • Chromium fails to launch (GPU driver, sandboxing, missing libs) and the process exits 0
  • The script hangs indefinitely waiting for a selector that no longer exists
  • A network timeout silently swallows the page load and the script exits cleanly
  • A Node.js version upgrade breaks the puppeteer native module and the process crashes without alerting anyone

Vigilmon's heartbeat pattern closes all of these gaps.


Step 1: Create a Heartbeat Monitor in Vigilmon

  1. Log in to Vigilmon and click New Monitor → Heartbeat.
  2. Name it after your script: Puppeteer — Dashboard Scraper or Puppeteer — Payment Flow Check.
  3. Set Expected interval to match how often the script runs. For an hourly script, use 1 hour; for a daily check, use 24 hours.
  4. Set Grace period to allow for browser startup time and network latency. 15 minutes works for most scripts.
  5. Save and copy the Ping URL — it looks like https://vigilmon.online/api/heartbeat/<unique-id>.

Step 2: Add a Heartbeat Ping to Your Puppeteer Script

Create a shared utility module:

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

async function pingVigilmon(url) {
  if (!url) return;

  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 };

Wrap your Puppeteer script to send the heartbeat only after verified success:

// scripts/check-payment-flow.js
const puppeteer = require("puppeteer");
const { pingVigilmon } = require("../lib/vigilmon");

const HEARTBEAT_URL = process.env.VIGILMON_HEARTBEAT_URL;

async function run() {
  const browser = await puppeteer.launch({
    headless: "new",
    args: ["--no-sandbox", "--disable-dev-shm-usage"],
  });

  try {
    const page = await browser.newPage();
    await page.goto("https://example.com/checkout", {
      waitUntil: "networkidle2",
      timeout: 30000,
    });

    // Verify critical elements are present
    await page.waitForSelector("#checkout-form", { timeout: 10000 });
    await page.waitForSelector("#payment-button", { timeout: 10000 });

    // Optionally run through the flow
    const title = await page.title();
    if (!title.includes("Checkout")) {
      throw new Error(`Unexpected page title: ${title}`);
    }

    console.log("Payment flow check passed");

    // Only ping after all assertions pass
    await pingVigilmon(HEARTBEAT_URL);
    console.log("Vigilmon heartbeat sent");
  } finally {
    await browser.close();
  }
}

run().catch((err) => {
  console.error("Script failed:", err.message);
  process.exit(1);
  // No heartbeat sent — Vigilmon will alert after the grace period
});

The heartbeat fires only inside the try block after all assertions succeed. Errors in the catch/finally path suppress the ping, which triggers a Vigilmon alert after the grace period.


Step 3: Schedule the Script

Linux/macOS cron

# Edit crontab: crontab -e
# Run every 4 hours
0 */4 * * * VIGILMON_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id>" \
  /usr/bin/node /home/user/scripts/check-payment-flow.js >> /var/log/puppeteer.log 2>&1

Systemd timer (recommended for Linux servers)

# /etc/systemd/system/puppeteer-check.service
[Unit]
Description=Puppeteer Payment Flow Check

[Service]
Type=oneshot
User=deploy
WorkingDirectory=/home/deploy/scripts
Environment=VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/<id>
ExecStart=/usr/bin/node check-payment-flow.js
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/puppeteer-check.timer
[Unit]
Description=Run Puppeteer check every 4 hours

[Timer]
OnCalendar=*:0/4:00
Persistent=true

[Install]
WantedBy=timers.target
systemctl enable --now puppeteer-check.timer

GitHub Actions

# .github/workflows/puppeteer-check.yml
name: Puppeteer Health Check

on:
  schedule:
    - cron: "0 */4 * * *"   # Every 4 hours
  workflow_dispatch:

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

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Install dependencies
        run: npm ci

      - name: Run Puppeteer script
        env:
          VIGILMON_HEARTBEAT_URL: ${{ secrets.VIGILMON_PUPPETEER_HEARTBEAT_URL }}
        run: node scripts/check-payment-flow.js

Step 4: Handle Script Timeouts Explicitly

Puppeteer scripts can hang indefinitely on network waits or broken selectors. Add a top-level timeout to ensure the script always exits within a known window:

// Wrap with an overall timeout
const SCRIPT_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes

const timeoutHandle = setTimeout(() => {
  console.error("Script timed out after 5 minutes — no heartbeat will be sent");
  process.exit(1);
}, SCRIPT_TIMEOUT_MS);

run()
  .then(() => {
    clearTimeout(timeoutHandle);
    process.exit(0);
  })
  .catch((err) => {
    clearTimeout(timeoutHandle);
    console.error("Script failed:", err.message);
    process.exit(1);
  });

Set Vigilmon's grace period to at least the script's maximum runtime plus buffer (e.g. 10 minutes grace for a 5-minute timeout).


Step 5: Monitor Multiple Scripts

For teams running several Puppeteer automation tasks, create one Vigilmon heartbeat monitor per script:

| Script | Purpose | Monitor name | Interval | |---|---|---|---| | check-payment-flow.js | Verifies checkout works | Puppeteer — Payment Flow | 4 h | | scrape-dashboard.js | Updates analytics data | Puppeteer — Dashboard Scraper | 1 h | | check-login.js | Verifies auth flow | Puppeteer — Login Check | 2 h | | screenshot-homepage.js | Visual regression baseline | Puppeteer — Screenshot Capture | 24 h |

Store heartbeat URLs per-script in environment variables:

VIGILMON_PAYMENT_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id1>"
VIGILMON_DASHBOARD_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id2>"
VIGILMON_LOGIN_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id3>"

Step 6: Configure Alert Channels

In Vigilmon, go to Notifications → New Channel:

  • Email — immediate alert when a heartbeat is missed
  • Slack webhook — notify #ops-alerts or #monitoring channel

When a Puppeteer script stops pinging:

🔴 MISSED HEARTBEAT: Puppeteer — Payment Flow
Last ping: 5 hours ago
Expected interval: 4 hours

When it recovers:

✅ HEARTBEAT RECOVERED: Puppeteer — Payment Flow
Gap: 5 hours

What You're Now Catching

| Silent failure mode | How Vigilmon detects it | |---|---| | Cron job deleted or misconfigured | No ping → alert after grace period | | Chromium fails to launch (sandboxing, libs) | Process exits → no ping → alert | | Script hangs on a missing selector | Timeout fires → process exits → no ping → alert | | Assertion fails (wrong page content) | Error thrown → no ping → alert | | Node.js module fails to load | Process crashes → no ping → alert | | Network timeout swallows page load silently | Timeout throws → no ping → alert |


Puppeteer automates what humans would check manually — but only while it's running. Vigilmon's heartbeat monitors give you the external signal that Puppeteer can't provide: confirmation that your headless Chrome scripts ran and succeeded within the expected window.

Start monitoring your Puppeteer scripts 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 →