tutorial

Monitoring Your Alpine.js App with Vigilmon: Uptime, API Health & Alerts

Add production-grade monitoring to Alpine.js apps — health check components, uptime monitors for your server and API, cron heartbeats, and webhook alert routing.

Alpine.js sprinkles interactivity directly into your HTML — no build step, no bundler, just script tags and x-data. But beneath that simplicity your server is still fielding fetch requests, and if it goes down your Alpine components silently stop responding. Vigilmon monitors your Alpine.js server and its endpoints continuously so you find out about outages before users notice frozen UI.

What You'll Build

  • A health check Alpine component that probes your API from the browser
  • Vigilmon HTTP monitors for your server and key API endpoints
  • A cron heartbeat for background jobs
  • A global error hook that fires a Vigilmon webhook on unhandled errors
  • Email and Slack alert channels

Prerequisites

  • An Alpine.js app served from any backend (Laravel, Rails, Django, Node, Go, etc.)
  • A backend API endpoint your Alpine components call
  • A free Vigilmon account

Step 1: Create a Health Check Alpine Component

Alpine's x-data and x-init make it straightforward to run a health check and surface the result to users.

<!-- health-check.html -->
<div
  x-data="{
    healthy: null,
    latencyMs: null,
    error: null,
    async check() {
      const start = Date.now();
      try {
        const res = await fetch('/health', { signal: AbortSignal.timeout(5000) });
        this.latencyMs = Date.now() - start;
        if (!res.ok) throw new Error('HTTP ' + res.status);
        this.healthy = true;
        this.error = null;
      } catch (err) {
        this.healthy = false;
        this.latencyMs = null;
        this.error = err.message;
      }
    }
  }"
  x-init="check(); setInterval(() => check(), 60000)"
>
  <template x-if="healthy === false">
    <div class="alert alert-error">
      API error: <span x-text="error"></span>
    </div>
  </template>
  <template x-if="healthy === true">
    <div class="status-ok">
      API healthy · <span x-text="latencyMs"></span>ms
    </div>
  </template>
</div>

Include this component in your layout so it appears on every page and gives users early warning of degradation.


Step 2: Add a /health Endpoint to Your Backend

Vigilmon needs a stable URL to probe from outside. Add a /health route to your server.

Laravel (PHP)

// routes/web.php
Route::get('/health', function () {
    $checks = [];
    $degraded = false;

    try {
        DB::select('SELECT 1');
        $checks['database'] = 'ok';
    } catch (\Exception $e) {
        $checks['database'] = 'error: ' . $e->getMessage();
        $degraded = true;
    }

    return response()->json([
        'status'    => $degraded ? 'degraded' : 'ok',
        'checks'    => $checks,
        'timestamp' => now()->toIso8601String(),
    ], $degraded ? 503 : 200);
});

Rails (Ruby)

# config/routes.rb
get '/health', to: 'health#show'

# app/controllers/health_controller.rb
class HealthController < ApplicationController
  def show
    checks = {}
    degraded = false

    begin
      ActiveRecord::Base.connection.execute('SELECT 1')
      checks[:database] = 'ok'
    rescue => e
      checks[:database] = "error: #{e.message}"
      degraded = true
    end

    status = degraded ? :service_unavailable : :ok
    render json: { status: degraded ? 'degraded' : 'ok', checks:, timestamp: Time.now.iso8601 }, status:
  end
end

Node.js / Express

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(),
  });
});

Step 3: Add Vigilmon HTTP Monitors

Monitor 1: Server Uptime

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

Monitor 2: Key API Endpoint

Monitor the endpoint your Alpine components depend on most heavily.

| Field | Value | |---|---| | URL | https://yourdomain.com/api/data | | Method | GET | | Expected status | 200 | | Check interval | 2 minutes |

Create both monitors in Vigilmon under Monitors → New HTTP Monitor.


Step 4: Heartbeat for Background Jobs

If your backend runs any scheduled tasks (email queues, report generators, sync jobs), add a heartbeat monitor.

// Node.js example
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 crash the job due to monitoring failure
  }
}

cron.schedule("0 * * * *", async () => {
  try {
    await runHourlyJob();
    await pingHeartbeat();
  } catch (err) {
    console.error("Job failed:", err);
  }
});

For Laravel, use the scheduler:

// app/Console/Kernel.php
protected function schedule(Schedule $schedule): void
{
    $schedule->call(function () {
        // your job logic
        Http::get(config('services.vigilmon.heartbeat_url'));
    })->hourly();
}

In Vigilmon:

  1. Monitors → New Heartbeat Monitor
  2. Set expected interval to 90 minutes
  3. Add the ping URL to your environment:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx

Step 5: Global Error Hook via Alpine Magic

Alpine's Alpine.magic() lets you register a global helper you can call anywhere. Pair it with a Vigilmon webhook to capture unhandled fetch errors from Alpine components.

<script>
  document.addEventListener("alpine:init", () => {
    Alpine.magic("reportError", () => (message, context = {}) => {
      const webhookUrl = document.querySelector("meta[name='vigilmon-webhook']")
        ?.getAttribute("content");
      if (!webhookUrl) return;

      // Simple dedup via sessionStorage
      const key = "err_" + message.slice(0, 40);
      if (sessionStorage.getItem(key)) return;
      sessionStorage.setItem(key, "1");

      fetch(webhookUrl, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          text: `Alpine.js error: ${message}`,
          url: window.location.href,
          context,
        }),
      }).catch(() => {});
    });
  });
</script>

<!-- In your layout, store the webhook URL in a meta tag (server-rendered) -->
<meta name="vigilmon-webhook" content="{{ config('services.vigilmon.webhook_url') }}">

Use $reportError in any Alpine component:

<div
  x-data="{
    async loadData() {
      try {
        const res = await fetch('/api/data');
        if (!res.ok) throw new Error('HTTP ' + res.status);
        return res.json();
      } catch (err) {
        $reportError(err.message, { component: 'data-loader' });
        throw err;
      }
    }
  }"
  x-init="loadData()"
>

Step 6: Configure Alert Channels

Email

  1. Alert Channels → Email
  2. Add your team's on-call email
  3. Attach to the server health monitor and API endpoint 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://yourdomain.com/health | jq .

# 2. Temporarily return 503 and confirm the alert fires

# 3. Use Vigilmon's "Test Alert" button to verify Slack/email delivery

# 4. Stop the cron job, wait 90+ minutes → heartbeat alert fires

What You Now Have

| Monitor | Catches | |---|---| | HTTP health check | Server crashes, DB failures, deploy errors | | API endpoint check | Key routes returning errors or going down | | Heartbeat | Background jobs stopping or crashing | | Error webhook | Runtime fetch errors in Alpine components |


Next Steps

  • Add a Vigilmon status page and link it from your app footer
  • Monitor separate API endpoints for each major Alpine component that fetches data
  • Use Vigilmon's response time history to track latency on your busiest endpoints

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 →