Monitoring
A broken sidecar degrades results without taking PullMD down. If the Playwright sidecar dies, JavaScript-heavy pages come back nearly empty while every request still answers 200. Monitor /api/status to catch it.
Health check
To check the sidecars, request /api/status:
curl -i http://localhost:3000/api/status
This response shows the Playwright sidecar down:
{
"ok": false,
"version": "3.18.2",
"services": {
"trafilatura": { "status": "ok", "latencyMs": 13 },
"playwright": { "status": "down", "error": "unreachable" },
"markitdown": { "status": "ok", "latencyMs": 14 }
}
}
- The endpoint returns HTTP
200when every configured sidecar answers and503when at least one is down or degraded, so a plain HTTP status check is enough. - Each sidecar's
statusisok,down,degradedornot-configured. A sidecar you didn't configure counts as healthy. erroris one ofunreachable,timeout,unhealthy,http <code>,misconfiguredorpolicy-missing. It never includes internal host names, because the endpoint is public.degradedwithpolicy-missingmeans thepullmd-playwrightimage is older than 3.17.0 and doesn't report that it enforces SSRF protection. Images older than 3.15.2 don't enforce it. Renders keep working. To clear it, update that image.- If the check itself fails, the endpoint returns
503with"error": "check-failed". - The endpoint needs no sign-in, so a monitor can poll it without credentials.
- PullMD caches results for 5 seconds, and simultaneous requests share one check, so polling can't flood your sidecars.
Uptime Kuma
Add a monitor of type HTTP(s) with the URL https://pullmd.example.com/api/status and accepted status codes 200-299.
Extraction stats
GET /api/stats shows how each extractor performed over the last 7 days: count, share, average quality, average length and average time. To use another period, set window to a SQLite datetime modifier such as -30 days. An invalid value returns "total": 0.
curl "http://localhost:3000/api/stats?window=-30%20days"
A sudden drop in playwright results, or a rise in low-quality results, points to a broken sidecar or a site that changed. The per-domain lists (lowQualityDomains, fallbackByDomain) show which sites to write a recipe for. They're visible only to the admin, or to everyone when sign-in is off and public history is on.
Cache size
GET /api/storage reports the number of cached conversions (total), the database size (dbSizeBytes), how many rows expire within 10 days (expiringSoon), the oldest entry, the retention period, and the cache hits and total requests over 7 days (cacheHits7d, requests7d).
Recipes
GET /api/recipes/status returns "ok": false when one or more recipes were rejected. The response also lists loaded and rejected counts per recipe file. Check it after you change your recipes.