HTTP Endpoint Monitoring Explained: Why a 200 Isn't Always Healthy
Endpoint monitoring explained: how status codes really work, sensible response-time thresholds, and why a 200 OK can hide a completely broken application.
Endpoint monitoring is the practice of repeatedly hitting a specific URL or API route and checking that the response is not just present, but correct. It's a step beyond a basic "is the server up?" ping, because the hard truth of running web services is that "up" and "healthy" are different states — and the difference is where most undetected outages live. This post explains what endpoint monitoring actually inspects, how to read status codes properly, and why a reassuring 200 OK is sometimes the most dangerous response your app can give you.
What an endpoint check actually does
A single endpoint check is a small, repeatable contract. It sends an HTTP request to a URL on a schedule and evaluates the response against expectations:
- Did the connection open? DNS resolved, TCP connected, TLS negotiated.
- What status code came back? And is it the one you expected?
- How long did it take? From request to first byte, and to a complete response.
- Does the body look right? Optionally, does it contain (or not contain) a specific string?
Each of those four can fail independently, and each tells you something different. Checking only the first one — the thing a naive "ping" does — leaves three large categories of failure invisible.
Reading status codes properly
Status codes are the most misread signal in monitoring. The five families are worth keeping straight:
| Range | Meaning | Monitoring stance |
|---|---|---|
2xx | Success | Usually healthy — but see below |
3xx | Redirect | Depends. A redirect to HTTPS is fine; an unexpected redirect to a login or error page is not |
4xx | Client error | 404 on a page that should exist is an outage. 401/403 may be expected on protected routes |
5xx | Server error | Almost always a real problem: 500, 502, 503, 504 |
| Connection failure | No response at all | DNS, TLS or network — the host is unreachable |
Two traps catch people out. First, redirects are not automatically healthy — a site that has fallen back to redirecting every request to a holding page returns clean 3xx codes the whole time. Second, a 503 Service Unavailable during a deploy might be expected for thirty seconds but is an incident if it persists, so duration matters as much as the code itself.
The right approach is to assert the specific code you expect for that route, not "anything in the 2xx range". A health endpoint should return 200; a protected admin route returning 200 to an unauthenticated probe might mean your auth has broken open.
Why a 200 isn't always healthy
This is the heart of endpoint monitoring. HTTP status codes are set by your web framework, but the meaning of the page is set by your application — and the two can disagree completely.
Common ways a 200 OK lies to you:
- The custom error page. A single-page app catches an API failure and renders "Sorry, something went wrong" — with a
200, because as far as the framework is concerned it served a page successfully. - The empty shell. The HTML loads but the data behind it never arrives, so the user sees a perpetual spinner. Status code:
200. - The stale cache. A CDN serves a cached
200for a page whose origin has been down for an hour. - The wrong content entirely. A misconfiguration serves the default web-server welcome page, or another tenant's site, with a perfectly valid
200.
The defence is content assertions: alongside the status code, check that the response body contains a known-good marker — an order-confirmation string, a specific element, an API field — or that it does not contain a known-bad one like "error" or "maintenance". This is the difference between confirming the server answered and confirming it answered correctly.
Setting response-time thresholds
Slow is a failure mode, not a footnote. A page that technically returns 200 after fifteen seconds has already lost the user. But thresholds need to be set per-endpoint, because a static page and a heavy reporting query have wildly different reasonable baselines.
A sensible way to set thresholds:
- Measure the baseline first. Watch the normal response time for a week before deciding what "slow" means for that route.
- Alert on a multiple of normal, not an absolute number. If a route normally answers in 200ms, an alert at 2 seconds catches a tenfold regression. A flat "alert over 5 seconds" rule would have missed it.
- Separate degraded from down. A slow response is a warning; a timeout or
5xxis an incident. Route them to different places so latency creep doesn't page anyone overnight. - Watch trends, not just the threshold. Response time that's been climbing steadily for a week is a leak or a growing table — worth catching before it crosses the line.
Tuning checks to avoid false alarms
The internet drops packets, and a single failed request is rarely a real outage. As with all monitoring, confirm before you alert: require two or three consecutive failures, or re-test from a second location, before declaring an incident. The small added delay is far cheaper than a team that has learned to ignore the monitor. Pair that with alerting only on state changes — one notification when it breaks, one when it recovers — and your endpoint checks stay trustworthy.
How DomainOps handles endpoints
DomainOps lets you define HTTP endpoint checks with expected status codes, response-time thresholds and optional content assertions, runs them on a schedule from outside your network, confirms failures to suppress transient blips, and alerts via email, Slack or Pushover with both failure and recovery events. It lives in the same dashboard as your SSL, DNS, domain-expiry and exposure monitoring, so when an endpoint goes red you can immediately see whether an expired certificate or a DNS change is the reason.
The full mechanics — assertions, thresholds and routing — are in the endpoint monitoring docs, with the simpler reachability checks covered under liveness.
If you've ever been told "the site's down" while your dashboard showed all green, content-aware endpoint monitoring is the fix. Get started for free and add your first endpoint in a couple of minutes.