tutorial

Monitoring Your Polymer App with Vigilmon: Health Checks, Heartbeats & Uptime Alerts

Add production-grade monitoring to a Polymer web components application — a health API, background job heartbeats, and instant alerts when your PWA or backend goes down.

Polymer is Google's library for building web components and Progressive Web Apps (PWAs) on top of the Web Components standard. It pioneered the modern web component ecosystem and remains widely deployed in production PWAs. But even a perfectly crafted Polymer PWA fails silently when its service worker caches stale data, the backend API goes down, or a background sync job stops running. Vigilmon gives you the visibility layer you need: continuous HTTP monitoring, heartbeat checks, and instant alerts via email or Slack.

What You'll Build

  • A health API endpoint for your Polymer PWA's backend
  • Vigilmon HTTP monitors for your PWA shell and backend
  • A heartbeat for background sync and scheduled tasks
  • Alert channels (email and Slack)
  • An uptime badge Polymer element

Prerequisites

  • A Polymer 3.x project (or Lit-based migration)
  • Node.js backend (Express or Firebase Functions) for the health endpoint
  • A free Vigilmon account

Step 1: Add a Health Endpoint

Polymer renders in the browser; your health checks live in the backend serving your PWA's API:

// server.js (Express)
import express from "express";

const app = express();

app.get("/health", async (req, res) => {
  const checks = {};
  let degraded = false;

  // Database / Firestore check
  try {
    // await db.collection("_health").doc("ping").get();
    checks.database = "ok";
  } catch (err) {
    checks.database = `error: ${err.message}`;
    degraded = true;
  }

  // Firebase Auth / Cloud check
  try {
    const resp = await fetch("https://www.googleapis.com/", {
      signal: AbortSignal.timeout(3000),
    });
    checks.googleCloud = resp.status < 500 ? "ok" : `http_${resp.status}`;
  } catch {
    checks.googleCloud = "unreachable";
    degraded = true;
  }

  res.status(degraded ? 503 : 200).json({
    status: degraded ? "degraded" : "ok",
    timestamp: new Date().toISOString(),
    checks,
  });
});

// Serve Polymer PWA static files
app.use(express.static("build/default"));

app.listen(process.env.PORT ?? 8080, () => {
  console.log("Server running on port", process.env.PORT ?? 8080);
});

Test it:

curl http://localhost:8080/health | jq .
# {"status":"ok","timestamp":"2026-06-29T...","checks":{"database":"ok","googleCloud":"ok"}}

Step 2: Configure Vigilmon HTTP Monitors

Log in to VigilmonMonitors → New Monitor:

Monitor 1: Polymer PWA Shell

| Field | Value | |---|---| | URL | https://yourpwa.com/ | | Method | GET | | Expected status | 200 | | Expected body | A stable string from your app shell HTML | | Check interval | 1 minute |

Monitor 2: Health API

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

Monitor 3: Service Worker Manifest (optional)

| Field | Value | |---|---| | URL | https://yourpwa.com/manifest.json | | Method | GET | | Expected status | 200 | | Expected body | "name" | | Check interval | 5 minutes |


Step 3: Heartbeat for Background Sync Tasks

PWAs rely on background sync APIs and server-side sync jobs. A Vigilmon heartbeat catches when these stop running:

npm install node-cron
// background-sync.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 crash the sync job due to monitoring failure
  }
}

// Example: push notification sync every 5 minutes
cron.schedule("*/5 * * * *", async () => {
  try {
    await processPushNotificationQueue();
    await pingHeartbeat();
  } catch (err) {
    console.error("[sync] Push notification sync failed:", err);
    // No ping → Vigilmon fires after the grace window
  }
});

// Example: PWA data prefetch sync every hour
cron.schedule("0 * * * *", async () => {
  try {
    await prefetchAppShellData();
    // Use a separate heartbeat URL for this job if needed
  } catch (err) {
    console.error("[sync] Prefetch failed:", err);
  }
});

async function processPushNotificationQueue() {
  // Your push notification processing logic
}

async function prefetchAppShellData() {
  // Your app shell data prefetch logic
}

Set up the heartbeat in Vigilmon:

  1. Monitors → New Heartbeat Monitor
  2. Set Expected interval to 10 minutes (2× the cron interval)
  3. Copy the ping URL to your .env:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx

Step 4: Display Uptime Status as a Polymer Element

Polymer 3.x uses ES module-based PolymerElement or you can use the lighter LitElement base. Here's a standalone uptime badge element:

// src/uptime-badge.js
import { PolymerElement, html } from "@polymer/polymer/polymer-element.js";

const BADGE_URL = "https://vigilmon.online/api/badge/your-monitor-id.svg";
const STATUS_URL = "https://vigilmon.online/status/your-monitor-slug";

class UptimeBadge extends PolymerElement {
  static get template() {
    return html`
      <style>
        :host {
          display: inline-flex;
          align-items: center;
        }
        img {
          opacity: 0;
          transition: opacity 0.2s;
        }
        img.loaded {
          opacity: 1;
        }
      </style>
      <a
        href="${STATUS_URL}"
        target="_blank"
        rel="noopener noreferrer"
        aria-label="Service uptime status"
      >
        <img
          id="badge"
          src="${BADGE_URL}"
          alt="Uptime"
          width="120"
          height="20"
          on-load="_onLoad"
        />
      </a>
    `;
  }

  _onLoad() {
    this.$.badge.classList.add("loaded");
  }
}

customElements.define("uptime-badge", UptimeBadge);

Use it in your Polymer app shell:

<!-- src/my-app.html or my-app.js template -->
<link rel="import" href="uptime-badge.html" />

<app-drawer-layout>
  <app-header-layout>
    <slot></slot>
  </app-header-layout>
  <footer>
    <uptime-badge></uptime-badge>
  </footer>
</app-drawer-layout>

Step 5: Set Up Alert Channels

In Vigilmon's Alert Channels settings:

Email

  1. Alert Channels → Email → add your on-call email
  2. Attach to all HTTP monitors and the heartbeat

Slack

  1. Create a Slack Incoming Webhook for #alerts
  2. Alert Channels → Webhook → paste the URL
  3. Payload template:
{
  "text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}

PagerDuty (for critical PWA incidents)

If your PWA has SLA commitments, hook Vigilmon into PagerDuty:

  1. Create a PagerDuty Events API v2 integration
  2. Alert Channels → Webhook in Vigilmon → paste the PagerDuty endpoint URL
  3. Set alerting threshold to 2 consecutive failures before paging on-call

Step 6: Verify Everything Works

# 1. Health endpoint
curl -s https://yourpwa.com/health | jq .

# 2. Break the DB connection string → confirm health returns 503
# Expected: Vigilmon alerts within 2 minutes

# 3. Stop the push notification sync cron → let heartbeat window expire
# Expected: heartbeat alert fires after the grace window

# 4. Vigilmon → "Test Alert" → confirm delivery to Slack/email

Also verify your service worker isn't masking outages by serving stale cached responses:

// In your service worker (sw.js)
// Network-first strategy for /health so Vigilmon always hits the live endpoint
self.addEventListener("fetch", (event) => {
  if (event.request.url.endsWith("/health")) {
    event.respondWith(fetch(event.request)); // Always go to network for health checks
    return;
  }
  // ... your normal caching strategies
});

Summary

| Monitor | What It Catches | |---|---| | HTTP PWA shell check | CDN failures, broken app shell deploys | | HTTP health API | Database, Firestore, and Google Cloud failures | | HTTP manifest check | Broken PWA install experience | | Heartbeat | Push notification sync crashes, prefetch failures |


Next Steps

  • Create separate monitors for staging, canary, and production channels
  • Use Vigilmon's response time graphs to detect backend latency regressions affecting Time to Interactive
  • Correlate Vigilmon downtime events with Lighthouse PWA scores to catch degraded offline experiences
  • Configure multi-channel alerting: email for low-severity, Slack + PagerDuty for critical

Ready to get started? Sign up for Vigilmon free — have your first monitor running 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 →