tutorial

How to Monitor Haunted with Vigilmon

Add production-grade monitoring to a Haunted web components app — health endpoints, heartbeat checks, and instant alerts when your app goes down.

Haunted brings React Hooks to native web components, letting you build stateful custom elements with useState, useEffect, and other familiar hooks — no framework required. When your Haunted-powered components are serving real users, you need to know the moment anything breaks. Vigilmon gives you continuous uptime monitoring, heartbeat checks, and instant alerts to email or Slack.

What You'll Build

  • A health endpoint for your Haunted app's backend
  • Vigilmon HTTP monitors covering your web components shell and API
  • A heartbeat for scheduled background jobs
  • Alert channels (email and Slack)
  • An uptime badge embedded in a Haunted custom element

Prerequisites

  • A Haunted project (typically a Vite or Rollup build with a Node/Express API backend)
  • A free Vigilmon account

Step 1: Add a Health Endpoint

Haunted apps ship as static bundles backed by an API server. Add a /health route to your Express backend:

// server.js
import express from "express";

const app = express();

app.get("/health", async (_req, res) => {
  const checks = {};
  let degraded = false;

  // Database connectivity check
  try {
    // await db.execute("SELECT 1");
    checks.database = "ok";
  } catch (err) {
    checks.database = `error: ${err.message}`;
    degraded = true;
  }

  // External dependency check
  try {
    const response = await fetch("https://api.example.com/ping", {
      signal: AbortSignal.timeout(3000),
    });
    checks.externalApi = response.ok ? "ok" : `http_${response.status}`;
  } catch {
    checks.externalApi = "unreachable";
    degraded = true;
  }

  res.status(degraded ? 503 : 200).json({
    status: degraded ? "degraded" : "ok",
    timestamp: new Date().toISOString(),
    checks,
  });
});

app.listen(process.env.PORT ?? 3000);

Test it locally:

curl http://localhost:3000/health | jq .
# {"status":"ok","timestamp":"2026-07-03T...","checks":{"database":"ok","externalApi":"ok"}}

Step 2: Configure Vigilmon HTTP Monitors

Log in to VigilmonMonitors → New Monitor.

Monitor 1: Haunted App Shell

| Field | Value | |---|---| | URL | https://yourapp.com/ | | Method | GET | | Expected status | 200 | | Expected body | A stable string from your HTML (e.g. a custom element tag name) | | Check interval | 1 minute |

Monitor 2: Health API

| Field | Value | |---|---| | URL | https://yourapp.com/health | | Method | GET | | Expected status | 200 | | Check interval | 1 minute |

Two monitors cover two distinct failure classes: static file serving and backend data layer failures.


Step 3: Heartbeat for Background Jobs

Haunted apps often drive scheduled tasks on the server — data syncing, cache warming, notification dispatch. Use a Vigilmon heartbeat to detect silent failures.

npm install node-cron
// scheduler.js
import cron from "node-cron";

const VIGILMON_HEARTBEAT_URL = process.env.VIGILMON_HEARTBEAT_URL ?? "";

async function pingHeartbeat() {
  if (!VIGILMON_HEARTBEAT_URL) return;
  try {
    await fetch(VIGILMON_HEARTBEAT_URL, { signal: AbortSignal.timeout(5000) });
  } catch {
    // Never let monitoring crash the job
  }
}

cron.schedule("*/10 * * * *", async () => {
  try {
    await runDataSync();
    await pingHeartbeat();
  } catch (err) {
    console.error("[scheduler] Data sync failed:", err);
    // Vigilmon fires after the heartbeat window expires with no ping
  }
});

async function runDataSync() {
  // Your scheduled task logic here
}

Create the heartbeat in Vigilmon:

  1. Monitors → New Heartbeat Monitor
  2. Set Expected interval to 20 minutes (2× the cron interval)
  3. Copy the ping URL into your environment:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx

Step 4: Display an Uptime Badge in a Haunted Component

Haunted's hooks model makes embedding a live status badge clean and reactive:

// src/components/status-badge.js
import { component, useState, useEffect } from "haunted";
import { html } from "lit-html";

const BADGE_URL = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL = "https://vigilmon.online/status/your-monitor-slug";

function StatusBadge() {
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    setLoaded(true);
  }, []);

  return html`
    <a
      href="${STATUS_URL}"
      target="_blank"
      rel="noopener noreferrer"
      aria-label="Service uptime status"
    >
      ${loaded
        ? html`<img src="${BADGE_URL}" alt="Uptime" width="120" height="20" />`
        : html`<span>Loading status…</span>`}
    </a>
  `;
}

customElements.define("status-badge", component(StatusBadge));

Use it anywhere in your HTML:

<!-- index.html -->
<footer>
  <status-badge></status-badge>
</footer>
<script type="module" src="/src/components/status-badge.js"></script>

Step 5: Configure Alert Channels

In Vigilmon's Alert Channels settings:

Email

  1. Alert Channels → Email → add your on-call address
  2. Attach to both HTTP monitors and the heartbeat

Slack

  1. Create a Slack Incoming Webhook for #alerts
  2. Alert Channels → Webhook → paste the webhook URL
  3. Payload template:
{
  "text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}

Step 6: Verify Everything Works

# 1. Confirm the health endpoint
curl -s https://yourapp.com/health | jq .

# 2. Simulate a DB failure → confirm health returns 503
# Expected: Vigilmon alert within ~2 minutes

# 3. Remove VIGILMON_HEARTBEAT_URL and let the scheduler run
# Expected: heartbeat alert after the grace window

# 4. Vigilmon → "Test Alert" → confirm delivery to Slack/email

Summary

| Monitor | What It Catches | |---|---| | HTTP app shell check | CDN failures, broken static deploys | | HTTP health API | Database, external API, and service failures | | Heartbeat | Silent scheduler failures, broken background jobs |


Next Steps

  • Create separate monitors for staging and production environments
  • Use Vigilmon's response time graphs to catch latency regressions across releases
  • Route critical alerts to Slack, low-severity alerts to email

Ready to get started? Sign up for Vigilmon free — have your first monitor running in under 5 minutes.

Monitor your app with Vigilmon

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

Start free →