Skip to content

Checking the response, not just the status

A 200 OK means the server answered. It does not mean the answer was right.

An API that starts returning an HTML error page with a 200, a JSON endpoint whose content-type quietly changes, a health check that keeps returning {"healthy": false} — all of those are green on a status-code-only monitor, and all of them are outages your users notice before you do.

Every HTTP monitor has a Check the response section on its create and edit form. Add as many checks as you like; the endpoint has to pass all of them.

Subject Example
The status code equals 200
A response header content-type contains application/json
A field in the JSON body data.healthy equals true
The response body contains operational, or does not contain Exception
How long it took is less than 2000 (milliseconds)
The response size is greater than 500 (bytes)

Header names are matched case-insensitively, so Content-Type and content-type are the same check — type whichever your own docs use.

For a JSON field, use dots for nesting and plain numbers for array positions: data.healthy, results.0.id.

Each check ends with a choice:

  • alert me — a failure marks the check down and can open an incident.
  • just flag it — the run shows as degraded on your dashboard and sends no alert at all.

Use just flag it for things that are worth watching but not worth waking up for — a cache header switching from HIT to MISS, a response creeping over a size you expect.

The accepted status codes are checked first

Section titled “The accepted status codes are checked first”

Every HTTP monitor already has a list of accepted status codes — 200, 201, 202, 204 and the 200-299 range by default. That list is checked before any of your checks run, and a code outside it fails the monitor immediately.

So a status check here is for narrowing what’s already allowed (“specifically 200, not 204”), not for widening it. To accept more codes, change the accepted status codes rather than adding a check.

Checks are evaluated top to bottom. The first alert me failure decides the result immediately and is the one named in the alert.

just flag it failures don’t stop the run — we remember the first one and keep going, in case a later check is a real failure. So if a just flag it check fails and a later alert me check also fails, the result is down and the alert names the alert me one.

Put the broadest check first. If the status code is wrong, hearing “status was 503” is more useful than hearing that a JSON field you could never have read is missing.

Checking headers is cheaper than checking the body

Section titled “Checking headers is cheaper than checking the body”

If your checks only look at the status code, headers, or how long it took, we don’t download the response body at all — we read the headers and close the connection. For a large page this is a real difference, and it can make a monitor cheaper than the older single-keyword match it replaces.

We download the body for a check on the body, a JSON field, or the response size.

Size is on that list on purpose. The content-length header is something the server claims, and plenty of responses don’t send one at all — so the only honest way to check a size is to measure it.

A HEAD request asks for the headers and nothing else, so there is no body to check. If your monitor’s method is HEAD, checks on the body, a JSON field or the size are rejected when you save, rather than failing every run afterwards.

Status and header checks work normally on HEAD — those are what it’s for.

What happens if a check can’t be evaluated

Section titled “What happens if a check can’t be evaluated”

If a check refers to something we can’t read — a JSON field on a body that isn’t valid JSON, or a subject we don’t recognise — the run is marked down, not passed.

That is deliberate. The alternative is a monitor you believe is checking something, reporting green forever while checking nothing, and a monitor that lies about being healthy is worse than no monitor.

The practical case: if your API starts returning an HTML error page, a check like data.error is missing would technically be satisfied — there is no data.error in an HTML document. We fail it instead, and the alert says the body was not valid JSON.

Monitors created through the API can also carry a single keyword match and a single json_query. Those still work exactly as before and are checked first; nothing you have configured changes. The checks described here are additive, and they are the ones exposed in the dashboard.