tutorial

How to Monitor Stage0 with Vigilmon

Add production-grade uptime monitoring and heartbeat checks to your Stage0-powered web application with Vigilmon — catch outages and silent failures before your users notice.

Stage0 is a low-level JavaScript framework for building high-performance web applications through direct, precise DOM manipulation — no virtual DOM overhead, just surgical updates to the exact nodes that need to change. It's the go-to choice when you need maximum throughput and complete control over the rendering pipeline. But raw DOM performance can't protect you from a down server, a failed deployment, or a silently crashed background worker. Vigilmon provides continuous HTTP monitoring, heartbeat checks, and instant alerts so you know the moment something breaks — before your users do.

What You'll Build

  • A /health endpoint for your Stage0 Node.js backend
  • Vigilmon HTTP monitors for your app and API
  • A heartbeat monitor for background jobs
  • Alert channels (email and Slack)
  • An uptime badge embedded in your Stage0 UI

Prerequisites

  • A Node.js project using Stage0 (with Express or a plain HTTP server)
  • A free Vigilmon account

Step 1: Add a Health Endpoint

Stage0 handles client-side DOM updates with direct node references, but your server needs an HTTP health endpoint that Vigilmon can poll at regular intervals:

// 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.query("SELECT 1");
    checks.database = "ok";
  } catch (err) {
    checks.database = `error: ${err.message}`;
    degraded = true;
  }

  // Cache check (e.g. Redis)
  try {
    // await redisClient.ping();
    checks.cache = "ok";
  } catch (err) {
    checks.cache = `error: ${err.message}`;
    degraded = true;
  }

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

// Serve your Stage0 app's static assets
app.use(express.static("public"));

app.listen(process.env.PORT ?? 3000, () => {
  console.log("Server running on port", process.env.PORT ?? 3000);
});

Test it locally:

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

Step 2: Configure Vigilmon HTTP Monitors

Log in to VigilmonMonitors → New Monitor:

Monitor 1: Stage0 App (Frontend)

| Field | Value | |---|---| | URL | https://yourapp.com/ | | Method | GET | | Expected status | 200 | | Expected body | A stable string from your HTML shell | | Check interval | 1 minute |

Monitor 2: Health API

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

Two independent monitors keep failure classes separate: a CDN outage (frontend down, API healthy) is distinct from a database failure (API degraded, frontend still cached).


Step 3: Heartbeat for Background Tasks

Stage0 applications frequently push live data to the browser — streaming updates, polling loops, or server-sent events fed by background workers. A Vigilmon heartbeat monitor detects when these upstream processes stop running silently:

// 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 heartbeat errors crash the scheduler
  }
}

// Run every 5 minutes for a live data feed
cron.schedule("*/5 * * * *", async () => {
  try {
    await processDataStream();
    await pingHeartbeat(); // Only ping after successful execution
  } catch (err) {
    console.error("[scheduler] Stream processing failed:", err);
    // No ping → Vigilmon alerts when the heartbeat window expires
  }
});

async function processDataStream() {
  // Process incoming data stream for Stage0 live views
}

Set up the heartbeat in Vigilmon:

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

Step 4: Embed an Uptime Badge in Your Stage0 UI

Stage0 works with real DOM nodes via tagged template literals. You can include a Vigilmon status badge using Stage0's html helper alongside direct node references:

// app.js (client-side with Stage0)
import { html, component } from "stage0";

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

// Define footer with badge using stage0 template
const footerView = html`
  <footer class="footer">
    <a href="${STATUS_URL}" target="_blank" rel="noopener noreferrer" aria-label="Service uptime status">
      <img src="${BADGE_URL}" alt="Uptime" width="120" height="20" />
    </a>
  </footer>
`;

// Define main app component
const AppView = html`
  <div class="app">
    <main>
      <p #content></p>
    </main>
  </div>
`;

function App(initData) {
  const root = AppView.cloneNode(true);
  const refs = AppView.collect(root);

  // Append footer (static, no data binding needed)
  root.appendChild(footerView.cloneNode(true));

  // Update function — only patches the content node
  function update(data) {
    refs.content.textContent = data.message;
  }

  update(initData);
  return { root, update };
}

const { root, update } = App({ message: "Your content here." });
document.getElementById("app").appendChild(root);

// Later, update only the content — badge node is untouched
update({ message: "Live data loaded." });

Stage0's direct DOM node references mean the badge <img> is never touched during content updates — the framework only patches the exact nodes you give it references to.


Step 5: Set Up Alert Channels

In Vigilmon's Alert Channels settings:

Email Alerts

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

Slack Alerts

  1. Create a Slack Incoming Webhook for your #alerts channel
  2. Alert Channels → Webhook → paste the Slack webhook URL
  3. Use this 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 health endpoint returns 200
curl -s https://yourapp.com/health | jq .status

# 2. Simulate a failure — break your DB connection string and redeploy
# Expected: health endpoint returns 503; Vigilmon alerts within ~2 minutes

# 3. Remove the heartbeat URL and let the scheduler run one cycle
# Expected: heartbeat alert fires after the grace window expires

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

Summary

| Monitor | What It Catches | |---|---| | HTTP app check | CDN failures, broken static file serving | | HTTP health API | Database, cache, and external dependency failures | | Heartbeat | Scheduler crashes, silent stream processing failures |


Next Steps

  • Create separate Vigilmon projects for staging and production
  • Use Vigilmon's response time graphs to detect backend latency regressions alongside Stage0's rendering performance
  • Configure escalating alerts: email for recoveries, Slack for active outages, PagerDuty for SLA-critical monitors

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 →