Bel is a small JavaScript library for creating composable HTML elements using tagged template literals as first-class DOM nodes. It lets you write HTML-like syntax in plain JavaScript without a compilation step or virtual DOM — each template literal returns a real Element you can insert, update, or compose freely. But lightweight rendering doesn't shield your production app from server outages, failing dependencies, or silent worker crashes. Vigilmon gives you the uptime monitoring and alerting you need to catch those problems fast. This tutorial shows you how to wire it up.
What You'll Build
- A health endpoint for the server powering your Bel app
- Vigilmon HTTP monitors for your app URL and health API
- A heartbeat for background tasks that supply data to your Bel views
- Email and Slack alerts when something breaks
- A status badge rendered as a Bel element in your footer
Prerequisites
- A Node.js/browser app using Bel for HTML rendering
- A free Vigilmon account
Step 1: Add a Health Endpoint
Bel apps are served from a backend process. Add a /health route to expose dependency status:
npm install express
// health-server.js
import express from "express";
const app = express();
const PORT = process.env.HEALTH_PORT ?? 3001;
app.get("/health", async (req, res) => {
const checks = {};
let degraded = false;
// Check your primary data source
try {
const response = await fetch(process.env.DATA_SERVICE_URL + "/health", {
signal: AbortSignal.timeout(3000),
});
checks.dataService = response.ok ? "ok" : `http_${response.status}`;
if (!response.ok) degraded = true;
} catch (err) {
checks.dataService = `error: ${err.message}`;
degraded = true;
}
// Check secondary dependencies
try {
const res = await fetch(process.env.CACHE_URL + "/ping", {
signal: AbortSignal.timeout(2000),
});
checks.cache = res.status < 500 ? "ok" : `http_${res.status}`;
} catch {
checks.cache = "unreachable";
}
res.status(degraded ? 503 : 200).json({
status: degraded ? "degraded" : "ok",
timestamp: new Date().toISOString(),
checks,
});
});
app.listen(PORT, () => {
console.log(`[health] Listening on :${PORT}`);
});
Test it:
curl http://localhost:3001/health | jq .
# {"status":"ok","timestamp":"2026-07-03T...","checks":{"dataService":"ok","cache":"ok"}}
Step 2: Set Up Vigilmon HTTP Monitors
Log in to Vigilmon and create two monitors.
Monitor 1: App URL
| Field | Value |
|---|---|
| URL | https://yourapp.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | A stable string from your index page |
| Check interval | 1 minute |
This catches server crashes, deployment failures, and CDN misconfigurations that break your Bel UI entirely.
Monitor 2: Health API
| Field | Value |
|---|---|
| URL | https://yourapp.com/health |
| Method | GET |
| Expected status | 200 |
| Check interval | 1 minute |
Step 3: Heartbeat for Background Jobs
If you run background jobs that fetch data consumed by your Bel views — API pollers, cache refreshers, or content importers — add a Vigilmon heartbeat to detect when they silently stop:
npm install node-cron
// jobs.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 the ping crash the job runner
}
}
async function syncContentCache() {
console.log("[jobs] Syncing content cache...");
// Fetch and cache content for Bel views
console.log("[jobs] Sync complete");
}
cron.schedule("*/10 * * * *", async () => {
try {
await syncContentCache();
await pingHeartbeat(); // Only ping on success
} catch (err) {
console.error("[jobs] Content sync failed:", err);
// Vigilmon will alert when the heartbeat window lapses
}
});
In Vigilmon:
- Monitors → New Heartbeat Monitor
- Set the interval to 25 minutes (2.5× the cron period as grace)
- Copy the ping URL to your
.env:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Step 4: Add a Status Badge as a Bel Element
Bel template literals return real DOM nodes, making it easy to compose a status badge:
// components/status-badge.js
const bel = require("bel");
function statusBadge() {
const BADGE_URL = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const MONITOR_URL = "https://vigilmon.online/status/your-monitor-slug";
return bel`
<a href="${MONITOR_URL}" target="_blank" rel="noopener noreferrer" aria-label="Service status">
<img
src="${BADGE_URL}"
alt="Uptime status"
width="120"
height="20"
loading="lazy"
/>
</a>
`;
}
module.exports = statusBadge;
Compose it in your main layout:
// layout.js
const bel = require("bel");
const statusBadge = require("./components/status-badge");
function appLayout(content) {
return bel`
<div class="app">
<main class="content">
${content}
</main>
<footer class="footer">
<p>© 2026 Your App</p>
${statusBadge()}
</footer>
</div>
`;
}
module.exports = appLayout;
Because Bel returns real DOM elements, the badge is a native node and integrates naturally with any DOM manipulation library or vanilla diffing you use alongside it.
Step 5: Configure Alert Channels
In Vigilmon's Alert Channels settings:
Email Alerts
- Alert Channels → Email → enter your ops email
- Attach to both monitors and the heartbeat
Slack Webhook
- Create a Slack Incoming Webhook for
#ops-alerts - Alert Channels → Webhook → paste the webhook URL
- Payload template:
{
"text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}
Step 6: Test End-to-End
# 1. Verify health endpoint
curl -s https://yourapp.com/health | jq .
# 2. Point the monitor at a broken URL, confirm Vigilmon alerts within 2 minutes
# 3. Remove VIGILMON_HEARTBEAT_URL and let the cron job run
# Expected: heartbeat alert fires after the grace window
# 4. Vigilmon → Test Alert → confirm Slack/email delivery
Summary
| Monitor | What It Catches | |---|---| | HTTP app check | Server crashes, deployment failures, CDN outages | | HTTP health API | Dependency failures, degraded data services | | Heartbeat | Silent job failures, stalled cache refreshers |
Next Steps
- Monitor staging and production as separate Vigilmon monitors
- Use Vigilmon's response time graphs to spot regressions after deploys
- Enable on-call escalation so critical alerts reach you instantly
Monitor your Bel app in minutes with Vigilmon. Sign up free — no credit card required.