Marko.js is eBay's battle-tested HTML-first framework, renowned for streaming server-side rendering and exceptional time-to-first-byte. But fast SSR only helps when your server is actually running. Vigilmon gives you the visibility layer you need: continuous HTTP monitoring, heartbeat checks, and instant alerts routed to email or Slack.
What You'll Build
- A health API endpoint for your Marko.js server
- Vigilmon HTTP monitors for your Marko app and backend services
- A heartbeat for scheduled background tasks
- Alert channels (email and Slack)
- An uptime badge on your Marko pages
Prerequisites
- A Marko.js project (
@marko/runor a custom Express/Hapi setup) - Node.js for the health endpoint
- A free Vigilmon account
Step 1: Add a Health Endpoint
Marko renders HTML server-side, so your health check lives in your Node.js server layer. Here's how to add one with Express:
// server.js
import express from "express";
const app = express();
// Health endpoint — register BEFORE Marko catch-all
app.get("/health", async (req, res) => {
const checks = {};
let degraded = false;
// Database check
try {
// await db.query("SELECT 1");
checks.database = "ok";
} catch (err) {
checks.database = `error: ${err.message}`;
degraded = true;
}
// Cache check
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,
});
});
// Marko page routes
app.get("/", (req, res) => {
res.setHeader("Content-Type", "text/html");
require("./src/pages/index.marko").render({}, res);
});
app.listen(process.env.PORT ?? 3000);
Test it:
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 Vigilmon → Monitors → New Monitor:
Monitor 1: Marko.js Application
| Field | Value |
|---|---|
| URL | https://yourapp.com/ |
| Method | GET |
| Expected status | 200 |
| Expected body | A stable string from your rendered HTML (e.g. site title) |
| Check interval | 1 minute |
Monitor 2: Health API
| Field | Value |
|---|---|
| URL | https://yourapp.com/health |
| Method | GET |
| Expected status | 200 |
| Check interval | 1 minute |
Two monitors cover two independent failure classes: the Node process itself and the underlying data/service layer.
Step 3: Heartbeat for Background Tasks
Marko apps often handle heavy server-side data aggregation and scheduled rendering tasks. Use a Vigilmon heartbeat to catch silent failures:
npm install node-cron
// 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 {
// Monitoring must never crash the job
}
}
// Cache-warming job — runs every 10 minutes
cron.schedule("*/10 * * * *", async () => {
try {
await warmPageCache();
await pingHeartbeat();
} catch (err) {
console.error("[scheduler] Cache warming failed:", err);
}
});
async function warmPageCache() {
// Pre-render high-traffic Marko pages into your cache layer
}
Set up the heartbeat in Vigilmon:
- Monitors → New Heartbeat Monitor
- Set Expected interval to 20 minutes (2× the cron interval)
- Copy the ping URL to your
.env:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Step 4: Display Uptime Status on a Marko Page
Add the badge as a Marko component:
<!-- src/components/status-badge.marko -->
<a
href="https://vigilmon.online/status/your-monitor-slug"
target="_blank"
rel="noopener noreferrer"
aria-label="Service uptime status"
>
<img
src="https://vigilmon.online/api/badge/your-monitor-id.svg"
alt="Uptime"
width=120
height=20
loading="lazy"
/>
</a>
Include it in your layout:
<!-- src/layouts/default.marko -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Marko App</title>
</head>
<body>
<${input.renderBody}/>
<footer>
<status-badge/>
</footer>
</body>
</html>
Step 5: Set Up Alert Channels
In Vigilmon's Alert Channels settings:
- Alert Channels → Email → add your on-call email
- Attach to both HTTP monitors and the heartbeat
Slack
- Create a Slack Incoming Webhook for
#alerts - Alert Channels → Webhook → paste the URL
- 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. Health endpoint
curl -s https://yourapp.com/health | jq .
# 2. Kill the database connection -> confirm health returns 503
# Expected: Vigilmon alerts within 2 minutes
# 3. Stop the scheduler -> wait for the heartbeat window
# Expected: heartbeat alert fires after the grace window
# 4. Vigilmon -> "Test Alert" -> confirm delivery to Slack/email
Summary
| Monitor | What It Catches | |---|---| | HTTP app check | Node process crash, SSR failures, broken deploys | | HTTP health API | Database, cache, and upstream service failures | | Heartbeat | Scheduler crashes, cache-warming failures |
Next Steps
- Monitor your streaming response time — Vigilmon's response time graphs are ideal for catching Marko TTFB regressions
- Create separate monitors for staging vs. production
- Configure multi-channel alerting: email for low-severity, Slack for critical
Ready to get started? Sign up for Vigilmon free — have your first monitor running in under 5 minutes.