Skip to content

What do you need to do?

Docs

Probe methodology

Honesty is the product, so here is exactly how a check runs: where it probes from, how often, how long it waits, how many failures it takes before something is called down, and where our own detection is deliberately biased and what that bias costs you.

On this page

Regions

The cloud fleet runs from ten regions: US-East, US-West, Europe, Asia-Pacific, US-Central, Canada, UK, Southeast Asia, Australia, and South America. How many of them your own checks (HTTP, TCP, DNS, SMTP, and Ping) may use is set by your plan: four regions on Free, eight on Growth, all ten on Scale. You pick which of your plan's regions probe a given check when you create it, all of them by default; a region outside your plan shows in the picker as locked with the tier that includes it. Heartbeat monitors have no region: nothing reaches out for them. The Monitor agent runs from wherever you install it, in addition to any cloud regions bound to the same check. See Checks & monitors for the full region and interval picture, including the Monitor agent's own rules.

The public outage tracker is a separate product from your own checks, sharing the same prober code but watching third-party services rather than anything you own. See its own methodology page for that product's specifics.

Cadence per tier

A check's interval is set once, at creation, and never changes on its own after that: upgrading or downgrading your plan does not rewrite an existing check's interval, only the floor offered to new ones. The floor itself is defined by tier in TIER_MIN_INTERVAL_SECONDS, in packages/db/checks.ts, the one place this number lives; quoting the seconds here would let this page drift the moment that table changes, so read the constant if you need the exact current value for every plan. As of this writing: Free and Growth run as fast as 60 seconds, Scale (and MSP, which includes everything in Scale) as fast as 30 seconds.

The public outage tracker's catalog runs on its own, separate cadence ladder (fast, standard, slow, and tail tiers, defined as CATALOG_CADENCE_SECONDS in packages/db/outage-catalog.ts) chosen per service by how often that service actually has incidents, not by anyone's subscription. It has nothing to do with your own check intervals above.

Timeouts

A single HTTP probe attempt has a 10-second timeout, and that budget resets on each redirect hop it follows (redirects are never auto-followed by the underlying fetch; each hop is independently validated and re-pinned to a safe address before it is taken). A probe is bounded end to end by a hard wall-clock deadline of the per-hop timeout multiplied by the maximum number of hops it can take, so a target that strings together several slow redirects cannot run indefinitely. The exact numbers (the per-hop timeout and the hop limit) live in packages/checker/index.ts, and the deadline mechanism that enforces the total budget lives in packages/checker/probe-deadline.ts. A probe that blows its budget is recorded as a normal failed check, not a crash: it is reported the same way a connection refusal is, just with a timeout as the reason.

Before something is called down

One failed probe in a region does not make that region down. Each region keeps its own failing streak, and only flips from operational to down once every probe since the first failure has failed and the streak has lasted at least 3 minutes (and spans at least two probes); one success is enough to flip it back and clears the streak. Brief failures between a probe region and your service, a dropped packet or a momentary blip on our side, last well under a minute, while a real outage persists, so waiting out 3 minutes keeps those blips from reading as an outage. This decision is pure and unit-tested on its own (computeRegionTransition in packages/db/index.ts), independent of anything else on the page.

Checks normally run once per interval, so a probe can land a few seconds short of the 3 minute mark and leave the flip a whole interval late. When a failing streak is within a minute or so of the mark, one more probe from the same region is scheduled for just after it, so a check on a 60 second interval is reported down about 3 minutes after a real outage starts. That re-probe confirms nothing on its own: if the target has recovered, it records an ordinary success. A cap limits how many of these re-probes can be in flight at once; past the cap a re-probe is shed and the check's normal interval applies, logged so the shed is a visible fact rather than a silent slowdown.

A confirmed region-down transition is one more step from paging anyone. Alert rules can require a minimum number of regions to be confirmed down at once (min_failing_regions, default 1) before operator channels (Slack, operator email, PagerDuty, webhooks) fire; this quorum stacks on top of, never instead of, each region's own 3 minute failure rule. It only silences operator paging, never the public status page or subscriber notifications, which follow the region transition exactly as before, so what your customers are told never depends on how you have your own paging tuned. The full rule, including how quorum pairs a down transition with its matching recovery, is in packages/db/alert-quorum.ts.

Vocabulary

A single region is always one of three states: operational, down (two confirmed failures, as above), or briefly recovering back through operational on the next success. Nothing in a single region is ever "degraded"; degraded is a property of the check as a whole, once you look across every region it runs from:

  • Operational. Every region that has reported is operational.
  • Degraded. At least one region is down and at least one is still operational, a partial, regional failure rather than a total one.
  • Down. Every region that has reported is down.
  • Unknown. No region has ever reported a result for this check yet, a brand-new check or one with no history, not a claim about its health either way.
  • Stale. Every region that reported is either unreported or old: a region's last result stops counting as fresh once it is more than three times the region's interval old, so a probe fleet that has stopped reaching a check does not keep showing its last, possibly outdated, reading as current.

This is the one aggregation rule, defined once (aggregateStatus and its staleness-aware counterpart in packages/db/index.ts) and read everywhere it is shown: your dashboard, the public status page, and the public API all report the identical thing because they all call the same function rather than each re-deriving it.

The public outage tracker's catalog uses one more word, blocked, that never appears for your own checks. See the false-positive section below for what it means and why it exists only there.

The false-positive trade-off

Your own checks and the public outage tracker optimize for opposite failure modes, on purpose, because the cost of being wrong points in opposite directions for each.

A check you own is watching your own service. Missing a real problem (a false negative) costs you a customer finding out before you do; a false alarm costs you a notification you can dismiss in seconds. Given that asymmetry, your checks resolve every failure to a plain down once confirmed: a timeout, a connection refusal, a 5xx, a failed response assertion, all become down with no separate "maybe it's not really down" bucket. The cost of this choice is real and worth naming: if your own WAF, CDN, or bot-defense layer ever blocks our probe's requests specifically, whether by IP reputation, a missing browser fingerprint, or a stricter rate limit, that reads as your service being down, even though a real visitor would have gotten through. That is the trade you are making by using us to watch your own infrastructure: fewer missed outages, at the cost of occasionally chasing a false alarm caused by your own front door being pickier than it is with real traffic.

The outage tracker watches services we do not own, and publishing a false "down" claim about someone else's service is the one thing that product cannot afford to get wrong: it damages a vendor we have no relationship with and undermines every other reading on the page. So its classifier (classifyCatalogObservation in packages/db/outage-results.ts) reserves "down" for failure modes a real user would actually experience (refused or reset connections, DNS failure, TLS failure, a 5xx, or a genuinely user-experienceable timeout) and files everything that looks like our own probe being singled out under "blocked" instead: an HTTP 403, 405, 406, 429, or 451, a redirect loop that only an automated, datacenter-sourced client would ever hit, or a hang with no corroborating evidence that the service itself is actually broken.

That last rule changed on 2026-08-27 (REA-346) after an audit of the catalog found a bare timeout, with zero HTTP response ever received, was the single largest source of false "down" claims in the whole catalog: 47% of every down reading across 2,117 probes was exactly this, including services that were never actually down, just consistently slower to respond than our timeout. A hang by itself is symmetric evidence: it is equally explained by "the service is down" and by "something between us and the service ate our request," and a datacenter-sourced prober cannot tell those apart from the hang alone. So a hang now only becomes "down" when a second, independent endpoint for the same service answered with an actual unhealthy status in the same round, positive evidence something is really broken; a hang with no such evidence, including a sibling endpoint that hung the identical way, is filed as "blocked," not down. The full rule, including the exact bot-defense status codes and the reasoning behind each one, is documented in that module.

We never let a vendor's own claimed status override what we actually observed, which is whether our check passed; their own status feed is shown as side-by-side context, never a rewrite of our reading. Both products' rules govern only what we classify from what we ourselves saw.