Your app defines healthy. We hold it to that.

Expose a health route that returns ok, degraded, or down. UptimeStatus calls it on a schedule, keeps the history, and owns the alerting.

A contract small enough to write before lunch.

A 200 from your homepage proves the web server is up. It says nothing about the database, the queue, or the third-party API your checkout depends on. Only your application can see those, and it already knows when they are wrong.

So put that knowledge in a route. Return a status of ok, degraded, or down, and optionally a map of named booleans for the details. UptimeStatus polls it, records what it said, and reacts.

# GET https://api.yourcompany.com/health
{
  "status": "degraded",
  "checks": {
    "database": true,
    "redis": true,
    "queue_backlog": false
  }
}

Checked from outside, where your app cannot vouch for itself.

A health route inside a monolith that is down cannot tell anyone it is down. The polling, the history, and the alerting have to live somewhere else.

UptimeStatus calls your route on the schedule you choose, stores every verdict with its sub-checks and response time, and turns the transition to down into an incident on your channels. Degraded states stay visible without waking anyone up.

api.yourcompany.com/health Degraded
Degraded
queue_backlog: false
112ms · just now
Healthy
all checks passing
98ms · 5m ago
Healthy
all checks passing
101ms · 10m ago

What health checks include.

Any framework. It is just a JSON route.

Rails, Laravel, Express, Django, Stacks, a Go binary: if it can return a small JSON object, it can report health. There is no SDK to adopt and no format to migrate to later, and the same route works unchanged if you ever move monitoring tools.

{ "status": "ok" }
FAQ

Health checks, answered.

What does my endpoint need to return?

JSON with a status field set to ok, degraded, or down, plus an optional checks object mapping names to booleans. Only the status field drives the monitor state; the checks map is stored with the result so you can see which dependency went red.

How is this different from uptime monitoring?

An uptime check asks whether the endpoint responds. A health check asks the application itself. Your app can see things a probe cannot: the database connection pool, the queue backlog, a downstream API. The health route reports that verdict and we treat it as the source of truth.

What does degraded actually do?

The monitor shows degraded and the result is recorded in the history, but no incident opens and nobody gets paged. Incidents are reserved for the transition to down. Degraded is for the "working, but worth a look" middle ground.

What if the endpoint returns HTML or times out?

Both count as down. A response with no parseable status field is a failure, and the check gives up after 15 seconds. A health route that cannot answer a simple GET quickly is itself a finding.

How often is the route called?

As often as every 30 seconds on Pro and every 5 minutes on Free. Self-hosted installs set their own schedule. Keep the route cheap and side-effect free, since it will be called a lot.

Should the health route be public?

The checker sends a plain GET, so the route needs to be reachable without credentials. Return only status and booleans, never internals like hostnames or versions, and use an unguessable path if you want it out of casual reach.

Start monitoring in under 2 minutes.

No credit card required for the self-hosted, open-source version.