
Cloudflare Workers run your code at Cloudflare's edge — distributed across hundreds of data centres globally, with sub-millisecond cold starts and no servers to manage. When they work, they're fast and reliable. When they fail, the errors are often subtle: a Worker that throws an uncaught exception returns a 500 to users with nothing in your logs unless you've set up explicit error handling.
Monitoring Workers requires a different approach from monitoring a traditional application server.
Cloudflare's dashboard shows you analytics for your Workers:
These are useful but reactive — you see what happened, not what's happening right now. And analytics won't tell you which specific routes are failing, or alert you when error rates spike.
Cloudflare has introduced Workers Observability (previously Tail Workers) which lets you stream real-time logs from your Workers. Enable it in your wrangler.toml:
[observability]
enabled = true
Or use a Tail Worker to process logs programmatically:
[[tail_consumers]]
service = "my-log-worker"
Your Tail Worker receives every request event and can forward errors to your logging service, Slack, or alerting system.
Workers that throw unhandled exceptions return a generic 500 error. Wrap your handler to catch and report errors:
export default {
async fetch(request, env, ctx) {
try {
return await handleRequest(request, env, ctx);
} catch (error) {
// Log the error
ctx.waitUntil(reportError(error, request, env));
// Return a proper error response
return new Response(JSON.stringify({
error: 'Internal server error',
message: env.ENVIRONMENT === 'development' ? error.message : undefined
}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
};
async function reportError(error, request, env) {
// Send to your logging/alerting service
await fetch(env.ERROR_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: error.message,
stack: error.stack,
url: request.url,
timestamp: new Date().toISOString()
})
});
}
Add a dedicated health check route to your Worker that external monitoring can check:
async function handleRequest(request, env) {
const url = new URL(request.url);
if (url.pathname === '/health') {
return handleHealth(request, env);
}
// ... rest of your routing
}
async function handleHealth(request, env) {
const checks = {};
// Check KV availability if you use it
if (env.MY_KV) {
try {
await env.MY_KV.get('health-check-key');
checks.kv = 'ok';
} catch (e) {
checks.kv = 'error';
}
}
// Check D1 database if you use it
if (env.DB) {
try {
await env.DB.prepare('SELECT 1').run();
checks.database = 'ok';
} catch (e) {
checks.database = 'error';
}
}
const allOk = Object.values(checks).every(v => v === 'ok');
return new Response(JSON.stringify({
status: allOk ? 'ok' : 'degraded',
...checks,
timestamp: new Date().toISOString()
}), {
status: allOk ? 200 : 503,
headers: { 'Content-Type': 'application/json' }
});
}
Point your uptime monitor at /health and you get a real signal about Worker functionality, not just whether Cloudflare's edge is responding.
Many Workers act as a middleware layer — handling authentication, rate limiting, A/B testing, or caching before forwarding requests to an origin server. In this architecture, you have two layers to monitor:
A Worker can be running perfectly while the origin it proxies to is down. The Worker will return errors (502 or whatever you configure), but the failure is actually in the origin.
Monitor both the Worker endpoint and your origin's health check endpoint directly:
// In your Worker health check
async function handleHealth(request, env) {
// Check origin health
let originStatus = 'unknown';
try {
const originResponse = await fetch(`${env.ORIGIN_URL}/health`, {
cf: { cacheEverything: false }
});
originStatus = originResponse.ok ? 'ok' : 'error';
} catch (e) {
originStatus = 'unreachable';
}
return new Response(JSON.stringify({
status: originStatus === 'ok' ? 'ok' : 'degraded',
worker: 'ok',
origin: originStatus
}), {
status: originStatus === 'ok' ? 200 : 503,
headers: { 'Content-Type': 'application/json' }
});
}
Workers bind to Cloudflare's storage primitives — KV, D1, R2, Durable Objects. These can experience availability issues independently of the Worker runtime itself. A Worker that reads from KV will fail if KV has a regional issue.
Build awareness of these dependencies into your health check, and monitor Cloudflare's own status page at cloudflarestatus.com for platform-level incidents.
Workers have CPU time limits (typically 50ms on the free plan, configurable on paid plans). A Worker that consistently hits its CPU limit will throw errors. Cloudflare's analytics will show this as CPU time spikes.
Optimise expensive operations, use waitUntil() for non-critical work after the response is sent, and monitor average CPU time in your analytics.
Cloudflare Workers run on Cloudflare's own infrastructure, so monitoring them from within Cloudflare misses platform-level issues. External monitoring from independent infrastructure gives you independent verification.
Domain Monitor monitors your Workers from multiple global locations outside Cloudflare's network. If your Worker fails in a specific region — or globally — you're alerted immediately. Create a free account and point a monitor at your Worker's health check endpoint.
Combined with Cloudflare's own analytics and Tail Workers for detailed logs, external uptime monitoring gives you the complete picture.
For more context on edge and platform monitoring, see uptime monitoring best practices and multi-location uptime monitoring.
When your site goes down, your status page becomes the most important page you have. Here's why it matters, what happens when you don't have one, and what a good status page does during a real outage.
Read moreYour domain is resolving, but pointing to the wrong server — showing old content, a previous host's page, or someone else's site entirely. Here's what causes this and how to diagnose it.
Read moreUptime monitoring isn't foolproof. Single-location monitors, wrong health check endpoints, long check intervals, and false positives can all cause real downtime to go undetected. Here's what to watch out for.
Read moreLooking to monitor your website and domains? Join our platform and start today.