tutorial

Monitoring Your Preact App with Vigilmon: Uptime, API Health & Alerts

Add production-grade monitoring to Preact apps — health check hooks, uptime monitors for your SPA and API, cron heartbeats, and webhook alert routing.

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:

  1. Monitors → New Heartbeat Monitor
  2. Set expected interval to 90 minutes
  3. 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

Email

  1. Alert Channels → Email
  2. Add your team's ops email
  3. Attach to both the SPA monitor and the API monitor

Slack Webhook

  1. Create a Slack Incoming Webhook for #alerts
  2. In Vigilmon, Alert Channels → Webhook
  3. 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.

Monitor your app with Vigilmon

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

Start free →