tutorial

Keystone CMS Monitoring with Vigilmon: GraphQL API, Admin UI & Database Connection Health Checks

Monitor your self-hosted Keystone CMS installation with Vigilmon — track GraphQL API health, Admin UI uptime, database connection pool, media upload service, and scheduled task execution to keep your headless CMS running reliably.

Your Keystone CMS GraphQL API went down overnight. The frontend team shipped three builds against a cached CDN layer, so nobody noticed until a content editor tried to publish a post and got a blank screen. By then the database connection pool had been exhausted for four hours and the scheduled publishing queue had backed up with 60 unprocessed items.

Keystone is an open-source headless CMS and application framework built on TypeScript and Node.js. It runs a GraphQL API and an Admin UI on port 3000 by default, backed by a database (PostgreSQL, MySQL, or SQLite). Self-hosting Keystone gives you full control over your content architecture — and full responsibility for knowing when the API, the Admin UI, or the underlying database layer breaks.

Vigilmon probes your Keystone instance from outside, the way a real client would. If the GraphQL endpoint becomes unreachable, if the Admin UI throws errors, or if the database connection pool drains, Vigilmon alerts your team before editors notice and before your frontend starts serving stale content.

What You'll Build

  • An HTTP monitor on the Keystone GraphQL API endpoint
  • An introspection health check for GraphQL schema availability
  • An Admin UI uptime monitor
  • A database connection pool health probe
  • A media upload service monitor
  • A scheduled task execution check
  • Alert channels for your content engineering team

Prerequisites

  • A self-hosted Keystone CMS installation (v6 / Next.js app or standalone)
  • Default port: 3000
  • A free account at vigilmon.online

Step 1: Monitor the GraphQL API Server

Keystone's GraphQL API is the primary data interface for all frontend consumers. A failure here means no content can be read or written — your site may still serve cached content but editorial workflows halt completely.

Test the endpoint:

curl -s -o /dev/null -w "%{http_code}" \
  -X POST http://your-keystone-host:3000/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __typename }"}'

Expected: a 200 response with {"data":{"__typename":"Query"}}. This is the lightest possible GraphQL query — it confirms the server is alive and processing requests without touching the database.

Set up the Vigilmon monitor:

  1. Log in to Vigilmon and click New Monitor → HTTP.
  2. Set URL to http://your-keystone-host:3000/api/graphql.
  3. Set Method to POST.
  4. Under Advanced → Body, paste: {"query":"{ __typename }"}
  5. Under Advanced → Headers, add: Content-Type: application/json
  6. Set Expected status code to 200.
  7. Under Advanced → Keyword check, add:
    • Keyword present: __typename
  8. Set Check interval to 60 seconds.
  9. Save the monitor.

Step 2: Monitor GraphQL Schema Availability

Beyond basic API reachability, you need to confirm that the Keystone schema — your content types, fields, and relationships — is fully loaded and queryable. A partially initialized Keystone instance can return 200 responses while refusing to serve actual content queries.

Test schema availability via introspection:

curl -s \
  -X POST http://your-keystone-host:3000/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { queryType { name } } }"}' \
  | python3 -m json.tool

A healthy response includes {"data":{"__schema":{"queryType":{"name":"Query"}}}}. Missing __schema data or an errors array in the response indicates the schema failed to compile — usually caused by a broken list type definition or a failed database migration.

Set up the Vigilmon monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to http://your-keystone-host:3000/api/graphql.
  3. Set Method to POST.
  4. Under Advanced → Body, paste: {"query":"{ __schema { queryType { name } } }"}
  5. Under Advanced → Headers, add: Content-Type: application/json
  6. Set Expected status code to 200.
  7. Under Advanced → Keyword check, add:
    • Keyword present: queryType
    • Keyword absent: errors
  8. Set Check interval to 120 seconds.
  9. Save the monitor.

Step 3: Monitor the Admin UI

Keystone's Admin UI runs on the same port as the GraphQL API and is the interface your content editors use. It can fail independently of the API — for example, if the Next.js build crashes or if static assets fail to serve — leaving editors with a broken interface while API consumers are unaffected.

Test the Admin UI:

curl -s -o /dev/null -w "%{http_code}" http://your-keystone-host:3000/

Expected: a 200 with the Admin UI HTML, which includes a reference to Keystone in the page title or body.

Set up the Vigilmon monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to http://your-keystone-host:3000/.
  3. Set Expected status code to 200.
  4. Under Advanced → Keyword check, add:
    • Keyword present: Keystone
  5. Set Check interval to 120 seconds.
  6. Save the monitor.

Step 4: Monitor Database Connection Pool

Keystone relies on Prisma for database access, and Prisma maintains a connection pool. If the pool becomes exhausted — due to a connection leak, a slow query pile-up, or the database server running out of connections — Keystone's API starts returning P2024 timeout errors while still accepting requests.

Probe the database layer by running a real content query through the API:

curl -s \
  -X POST http://your-keystone-host:3000/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ users(take: 1) { id } }"}' \
  | python3 -m json.tool

Replace users with any list type defined in your Keystone schema. A healthy database connection returns a data object. An exhausted connection pool or unreachable database returns an errors array with a database timeout message.

Set up the Vigilmon monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to http://your-keystone-host:3000/api/graphql.
  3. Set Method to POST.
  4. Under Advanced → Body, paste: {"query":"{ users(take: 1) { id } }"}
  5. Under Advanced → Headers, add: Content-Type: application/json
  6. Set Expected status code to 200.
  7. Under Advanced → Keyword check, add:
    • Keyword present: data
    • Keyword absent: P2024
  8. Set Check interval to 120 seconds.
  9. Save the monitor.

Step 5: Monitor the Media Upload Service

Keystone handles media (images, files) through its images and files APIs. If the storage backend — local disk, S3, Google Cloud Storage, or Azure Blob — becomes unreachable, upload attempts silently fail or throw 500 errors while the rest of the API continues to work.

Test the upload service endpoint:

curl -s -o /dev/null -w "%{http_code}" \
  http://your-keystone-host:3000/api/graphql \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __type(name: \"ImageFieldOutput\") { name } }"}'

A healthy response with 200 and the type name confirms the image type is registered in the schema, which only succeeds when the image storage backend is configured and reachable at startup. If images are not part of your schema, substitute any file-related type name.

Set up the Vigilmon monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to http://your-keystone-host:3000/api/graphql.
  3. Set Method to POST.
  4. Under Advanced → Body, paste: {"query":"{ __type(name: \"ImageFieldOutput\") { name } }"}
  5. Under Advanced → Headers, add: Content-Type: application/json
  6. Set Expected status code to 200.
  7. Set Check interval to 300 seconds.
  8. Save the monitor.

Step 6: Monitor Scheduled Task Execution

Keystone supports scheduled tasks through custom hooks or external cron integrations. If your scheduled publishing jobs (for time-based content releases) stop running, posts accumulate in a pending state and never go live. Monitor this by exposing a health endpoint from your custom Keystone configuration, or by querying for stale scheduled items directly:

curl -s \
  -X POST http://your-keystone-host:3000/api/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"{ posts(where: { status: { equals: \"scheduled\" }, publishedAt: { lt: \"2026-01-01T00:00:00.000Z\" } }) { id } }"}'

Replace the date with a reasonable staleness threshold (e.g., 1 hour ago). A non-empty result from this query means items were scheduled to publish but have not been processed — indicating a failed scheduler.

For a simpler approach, add a /api/health endpoint in your Keystone extendExpressApp configuration that returns {"status":"ok"} after confirming the task queue is not stale, then monitor that endpoint:

Set up the Vigilmon monitor:

  1. Click New Monitor → HTTP in Vigilmon.
  2. Set URL to http://your-keystone-host:3000/api/health (or your custom health endpoint).
  3. Set Expected status code to 200.
  4. Under Advanced → Keyword check, add:
    • Keyword present: ok
  5. Set Check interval to 300 seconds.
  6. Save the monitor.

Step 7: Alert Channels

Go to Notifications → New Channel in Vigilmon and configure:

  • Email — immediate alerts to your CMS platform team
  • Webhook — Slack or Discord for editorial awareness

A failing GraphQL API alert in Slack looks like:

🔴 DOWN: keystone-graphql-api (HTTP monitor)
Expected 200, got 503 Service Unavailable
Region: EU-West
Triggered: 2026-06-14 02:44 UTC

When the API recovers:

✅ RECOVERED: keystone-graphql-api
Downtime: 22 minutes

Set critical severity for the GraphQL API and database connection monitors — a down API blocks all editorial and frontend work. Set warning severity for the Admin UI, media upload, and scheduled task monitors. Use Alerting → Escalation to page an engineer if the GraphQL API is unreachable for more than 5 minutes during business hours.


What You've Built

| Scenario | How Vigilmon catches it | |---|---| | Keystone process crash | HTTP monitor on :3000/api/graphql fails with connection refused | | GraphQL schema compilation failure | Introspection query returns errors or missing queryType | | Database connection pool exhausted | Real content query returns P2024 timeout error | | Database host unreachable | Content query returns error with no data field | | Admin UI build crash | Root path monitor returns non-200 or missing Keystone keyword | | Image storage backend unreachable | ImageFieldOutput type query fails or returns errors | | Scheduled publishing queue stalled | Custom health endpoint reports stale pending items |


A headless CMS is only as reliable as its API. External monitoring with Vigilmon gives your team a real-time signal when Keystone's GraphQL endpoint, database layer, or Admin UI breaks — before your frontend serves stale content and before your editors find out through a blank screen.

Start monitoring your Keystone CMS today — register free at vigilmon.online.

Monitor your app with Vigilmon

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

Start free →