tutorial

Monitoring Payload CMS with Vigilmon

Payload CMS is a TypeScript-native headless CMS with a rich admin UI, REST API, and GraphQL API — but none of it comes with built-in uptime monitoring. Here's how to watch every layer of a Payload deployment with Vigilmon.

Payload CMS gives your team a fully self-hosted, TypeScript-native headless CMS with a beautiful admin panel, a REST API, a GraphQL API, and a local API — all without locking you into a SaaS plan. But self-hosting means you own the uptime. If the Node.js process crashes, the database goes away, or the admin panel bogs down under load, your editors are blocked and your front-end content delivery stops. Vigilmon gives you the external, always-on monitoring layer Payload doesn't include: server health, database connectivity, API response times, and admin panel performance watched from outside your infrastructure.

What You'll Set Up

  • HTTP uptime monitor for the Payload web server
  • Admin UI response-time monitor with p95 alerting
  • REST API response-time monitor for content delivery
  • GraphQL API health check
  • Cron heartbeat for Payload background jobs and scheduled tasks
  • SSL certificate expiry alert for the CMS domain

Prerequisites

  • Payload CMS v2 or v3 deployed and accessible over HTTPS
  • MongoDB or PostgreSQL running as the Payload database backend
  • A free Vigilmon account

Step 1: Monitor the Payload Server (Web Root Health)

Every Payload deployment exposes its root at / — and Payload v3 serves its admin panel from /admin. Start with a basic HTTP monitor to catch any process crash or network outage that takes the entire CMS offline:

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter your Payload URL: https://cms.yourdomain.com.
  4. Set Check interval to 1 minute.
  5. Set Expected HTTP status to 200.
  6. Enable Monitor SSL certificate and set Alert when certificate expires in less than 21 days.
  7. Click Save.

For a more precise health signal, add a dedicated /health route to your Payload configuration:

// payload.config.ts  (Payload v3)
import { buildConfig } from 'payload'

export default buildConfig({
  // ... your config
  express: {
    // Payload v2: add custom express middleware
  },
  // For Payload v3 (Next.js), add a route handler:
  // app/api/health/route.ts
})

For Payload v3 (Next.js app router), add a health route handler:

// app/api/health/route.ts
import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json({ status: 'ok', timestamp: new Date().toISOString() })
}

For Payload v2 (Express), add a middleware in your server.ts:

// server.ts
import express from 'express'
import payload from 'payload'

const app = express()

app.get('/health', (req, res) => {
  res.json({ status: 'ok', uptime: process.uptime() })
})

payload.init({ express: app, ... })

Update your Vigilmon monitor to target https://cms.yourdomain.com/health (or /api/health for v3). A 200 response confirms the Node.js process is up and accepting requests.


Step 2: Monitor Admin UI Response Time

The Payload admin panel at /admin is the primary interface for your content editors. A slow admin panel blocks publishing workflows. Monitor its p95 response time from Vigilmon:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter https://cms.yourdomain.com/admin.
  3. Set Check interval to 5 minutes.
  4. Under Response time alerts, enable Alert when p95 response time exceeds 2000 ms (2 seconds).
  5. Click Save.

The admin panel in Payload v3 is rendered by Next.js. A response-time spike on /admin typically indicates one of:

  • Database query slowness (collections with many documents and no indexes)
  • High Node.js CPU usage from a background Payload hook or migration
  • Cold-start latency if Payload is deployed as a serverless function

If you see persistent p95 alerts, check your database indexes:

// Ensure your most-queried collections have indexes on frequently filtered fields
// In payload.config.ts:
{
  slug: 'posts',
  fields: [...],
  indexes: [
    { fields: { createdAt: -1 } },   // MongoDB (Payload v2)
    { fields: { status: 1 } },
  ],
}

Step 3: Monitor the REST API Response Time

The Payload REST API at /api/{collection} is the primary content delivery interface for headless front-ends. Slow REST responses directly impact your front-end build times and ISR regeneration. Add a dedicated monitor:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter a representative REST endpoint: https://cms.yourdomain.com/api/posts?limit=10.
  3. Set Check interval to 2 minutes.
  4. Under Response time alerts, enable Alert when p95 response time exceeds 500 ms.
  5. Set Expected HTTP status to 200.
  6. Click Save.

Replace posts with a collection you actively query in production. The ?limit=10 ensures the query is bounded and returns quickly even on large collections.

For authenticated endpoints, you can use Vigilmon's custom headers to pass an API key:

Authorization: users API-Key YOUR_API_KEY_HERE

Payload supports API Key authentication per collection — enable it in your collection config:

{
  slug: 'products',
  auth: {
    useAPIKey: true,
  },
}

Step 4: Monitor the GraphQL API

Payload's GraphQL API at /api/graphql serves all queries made via the GraphQL interface. It's particularly sensitive to N+1 query patterns on deeply nested relationship fields. Add a health monitor:

  1. Click Add MonitorHTTP / HTTPS.
  2. Enter https://cms.yourdomain.com/api/graphql.
  3. Set Method to POST.
  4. Set Request body to:
    {"query": "{ Posts(limit: 1) { docs { id } } }"}
    
    (replace Posts with a collection name from your schema)
  5. Set Request header Content-Type: application/json.
  6. Set Expected HTTP status to 200.
  7. Set Check interval to 5 minutes.
  8. Click Save.

A non-200 response or a {"errors": [...]} body indicates the GraphQL layer is failing. Payload surfaces GraphQL errors in the response body even when the HTTP status is 200, so watch your response body for the errors key if you need deeper validation.


Step 5: Heartbeat Monitor for Payload Background Jobs

Payload v3 introduced a built-in Jobs Queue for background processing (email sends, image processing, webhook dispatching). If the jobs queue worker stops processing, tasks pile up silently. Use Vigilmon's cron heartbeat to detect stalled workers:

  1. Click Add MonitorCron Heartbeat.
  2. Set the expected ping interval to match your worker cadence (e.g. 5 minutes for a frequently-running queue).
  3. Copy the heartbeat URL: https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_ID.

In your Payload job worker, ping the heartbeat after each successful queue drain:

// jobs/worker.ts  (Payload v3 jobs queue)
import payload from 'payload'
import fetch from 'node-fetch'

async function runWorker() {
  await payload.jobs.run()                // process pending tasks

  // Ping Vigilmon heartbeat to signal the worker is alive
  await fetch('https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_ID').catch(() => {})
}

setInterval(runWorker, 5 * 60 * 1000)    // every 5 minutes

If the Node.js process crashes or the jobs queue throws an unhandled exception, the heartbeat stops arriving and Vigilmon alerts your team.


Step 6: Configure Alert Channels and Thresholds

  1. Go to Alert Channels in Vigilmon and add Slack, email, or a PagerDuty webhook.
  2. Set Consecutive failures before alert to 2 on the web root monitor — Payload hot-reload during development can cause a brief 503 that clears on retry.
  3. For the REST API monitor, keep consecutive failures at 1 — a single REST failure during production represents a real content delivery gap.
  4. Use Maintenance windows during Payload version upgrades or database migrations:
# Suppress alerts during a planned upgrade
curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"monitor_id": "YOUR_MONITOR_ID", "duration_minutes": 15}'

# Perform your upgrade
npm install payload@latest
npx payload migrate

# Maintenance window expires automatically

Summary

| Monitor | Target | Alert Threshold | What It Catches | |---|---|---|---| | Web root | /health | Any non-200 | Process crash, server unreachable | | Admin UI | /admin | p95 > 2 s | Editor experience degradation | | REST API | /api/posts | p95 > 500 ms | Content delivery slowdown | | GraphQL API | /api/graphql | Any error | GraphQL layer failure | | Jobs heartbeat | Heartbeat URL | Missed ping | Queue worker stalled | | SSL certificate | CMS domain | Expiry < 21 days | TLS renewal failure |

Payload gives your team a TypeScript-native, fully self-hosted CMS without vendor lock-in — but self-hosting means you own the reliability story. With Vigilmon monitoring every layer from the web root to the GraphQL API, your content editors and front-end teams get the same confidence that managed CMS platforms provide, running entirely on your own infrastructure.

Monitor your app with Vigilmon

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

Start free →