Preact's 3 kB footprint means your app loads fast — but a fast frontend can't compensate for a backend that's down or a CDN serving a broken build. Every render that calls your API becomes a user-visible failure when the server is unreachable. Vigilmon monitors your Preact app and its backend continuously so you find out about outages before your users do.
What You'll Build
- A health check hook that probes your API from the browser
- Vigilmon HTTP monitors for your Preact SPA and backend API
- A cron heartbeat for scheduled server-side tasks
- A global error handler that posts to a Vigilmon webhook
- Email and Slack alert channels
Prerequisites
- Preact project (Vite, Preact CLI, or custom bundler)
- A backend API (any language/framework)
- A free Vigilmon account
Step 1: Create a Health Check Hook
Preact uses the same hooks API as React, so a health check hook looks familiar.
// src/hooks/useHealthCheck.js
import { useState, useCallback } from "preact/hooks";
export function useHealthCheck(apiBaseUrl) {
const [status, setStatus] = useState({
healthy: false,
latencyMs: null,
error: null,
});
const [loading, setLoading] = useState(false);
const check = useCallback(async () => {
setLoading(true);
const start = Date.now();
try {
const res = await fetch(`${apiBaseUrl}/health`, {
signal: AbortSignal.timeout(5000),
});
const latencyMs = Date.now() - start;
if (!res.ok) throw new Error(`HTTP ${res.status}`);
setStatus({ healthy: true, latencyMs, error: null });
} catch (err) {
setStatus({
healthy: false,
latencyMs: null,
error: err.message ?? "Unknown error",
});
} finally {
setLoading(false);
}
}, [apiBaseUrl]);
return { status, loading, check };
}
Use it in your root component to run a check on mount:
// src/app.jsx
import { useEffect, useRef } from "preact/hooks";
import { useHealthCheck } from "./hooks/useHealthCheck";
export function App() {
const { status, check } = useHealthCheck(import.meta.env.VITE_API_BASE_URL);
const intervalRef = useRef(null);
useEffect(() => {
check();
intervalRef.current = setInterval(check, 60_000);
return () => clearInterval(intervalRef.current);
}, []);
return (
<div>
{!status.healthy && status.error && (
<div class="api-error-banner">API unavailable: {status.error}</div>
)}
{/* rest of your app */}
</div>
);
}
This runs health checks in the browser but doesn't replace external monitoring — you also need Vigilmon polling from outside.
Step 2: Add Vigilmon HTTP Monitors
Monitor 1: Preact SPA Uptime
| Field | Value |
|---|---|
| URL | https://app.yourdomain.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | <div id="app"> (or any stable string in your index.html) |
| Check interval | 1 minute |
This catches CDN outages, broken Vite builds, and misconfigured rewrites.
Monitor 2: Backend API Health
| Field | Value |
|---|---|
| URL | https://api.yourdomain.com/health |
| Method | GET |
| Expected status | 200 |
| Check interval | 1 minute |
Create both monitors in Vigilmon under Monitors → New HTTP Monitor.
Step 3: Backend Health Endpoint
Add a /health route to your backend. Here's a minimal example for a Node/Express backend:
// server.js
app.get("/health", async (req, res) => {
const checks = {};
let degraded = false;
try {
await db.query("SELECT 1");
checks.database = "ok";
} catch (err) {
checks.database = `error: ${err.message}`;
degraded = true;
}
res.status(degraded ? 503 : 200).json({
status: degraded ? "degraded" : "ok",
checks,
timestamp: new Date().toISOString(),
});
});
Remember to add Access-Control-Allow-Origin if your health check hook calls this cross-origin from the browser.
Step 4: Heartbeat for Scheduled Tasks
If your backend runs scheduled tasks (email digests, cache warmers, data exports), add a Vigilmon heartbeat monitor.
// server/jobs/scheduler.js
import cron from "node-cron";
const HEARTBEAT_URL = process.env.VIGILMON_HEARTBEAT_URL ?? "";
async function pingHeartbeat() {
if (!HEARTBEAT_URL) return;
try {
await fetch(HEARTBEAT_URL, { signal: AbortSignal.timeout(5000) });
} catch {
// never let monitoring failure crash the job
}
}
cron.schedule("0 * * * *", async () => {
try {
await runHourlyTask();
await pingHeartbeat(); // only ping on success
} catch (err) {
console.error("Hourly task failed:", err);
}
});
In Vigilmon:
- Monitors → New Heartbeat Monitor
- Set expected interval to 90 minutes
- Copy the ping URL:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Step 5: Global Error Handler Webhook
Preact exposes options.errorBoundary for global error handling. Use it to fire a Vigilmon webhook on unhandled component errors.
// src/main.jsx
import { options } from "preact";
import { render } from "preact";
import { App } from "./app";
const originalError = options.__e;
options.__e = (error, vnode) => {
console.error("[Preact error]", error, vnode);
const webhookUrl = import.meta.env.VITE_VIGILMON_WEBHOOK_URL;
if (webhookUrl) {
// Rate-limit to avoid flooding on repeated errors
const key = `err_${String(error).slice(0, 40)}`;
if (!sessionStorage.getItem(key)) {
sessionStorage.setItem(key, "1");
fetch(webhookUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `Preact error: ${error?.message ?? error}`,
url: window.location.href,
}),
}).catch(() => {});
}
}
if (originalError) originalError(error, vnode);
};
render(<App />, document.getElementById("app"));
In Vigilmon, create a Webhook Alert Channel and set its URL as VITE_VIGILMON_WEBHOOK_URL.
Security note: for high-security apps, proxy the webhook call through your backend instead of exposing the URL in client-side code.
Step 6: Configure Alert Channels
- Alert Channels → Email
- Add your team's ops email
- Attach to both the SPA monitor and the API monitor
Slack Webhook
- Create a Slack Incoming Webhook for
#alerts - In Vigilmon, Alert Channels → Webhook
- Paste the Slack URL:
{
"text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}
Step 7: Test Everything
# 1. Verify health endpoint
curl -s https://api.yourdomain.com/health | jq .
# 2. Temporarily return 503 from /health and confirm the alert fires
# 3. Use Vigilmon's "Test Alert" button to verify Slack/email delivery
# 4. Stop the cron process, wait 90+ minutes → heartbeat alert fires
What You Now Have
| Monitor | Catches | |---|---| | HTTP SPA check | CDN outage, broken builds, misconfigured rewrites | | HTTP API health | Backend crashes, DB failures, slow responses | | Heartbeat | Cron jobs stopping, scheduler crashes | | Error webhook | Runtime component errors in production |
Next Steps
- Add a Vigilmon status page and embed the badge in your app footer
- Create separate monitor groups for staging and production
- Use Vigilmon's response time history to track API latency trends over time
Found this useful? Vigilmon is free to start — sign up here and have your first monitor live in under 5 minutes.