How we measure
Every number on this site comes from probes we operate ourselves. No provider feeds us data. No status-page scraping inflates any uptime figure. This page explains exactly what we measure, how we turn raw observations into a "service was up at minute N" verdict, and how those verdicts compose into the rankings on the home page.
This page is our public commitment about how the system works. The numbers behind every ranking are exposed via our read-only API, so any figure on the site is reproducible by anyone with an HTTP client. If something here looks wrong, tell us at hello [at] uptimeproject [dot] org .
Probes
Cadence
Consensus
License
The probe network
We run five probe agents on geographically and network-diverse infrastructure across four cloud providers. Vultr Seattle and Vultr Singapore share a provider, a deliberate trade-off favouring an Asia-Pacific vantage point over a fifth distinct provider at a less-useful location. Probes ship their observations to our ingest endpoint over a private overlay network, not via the public internet.
| Provider | Location |
|---|---|
| Hetzner | Falkenstein, DE |
| OVH | Roubaix, FR |
| DigitalOcean | New York, US |
| Vultr | Seattle, US |
| Vultr | Singapore, SG |
Critical rules. Every probe monitors every service; the variance across vantage points is the data. A probe inside a measured provider's network would have a structurally favourable path that distorts the comparison, so a probe never votes on the provider it runs on (see who votes). There are no AWS, GCP, Azure or Cloudflare probes.
Five probes is the minimum size at which our strict-majority consensus rule (below) can still produce a verdict when one probe is down for maintenance. We plan to grow the fleet to seven over time, adding two, not five, because diminishing returns on geographic diversity kick in fast once you have one probe per continent.
Check types
Each service is monitored by one or more checks. The check type determines what is measured; the per-check interval determines how often. The probe fires each check on a deterministic per-check offset within its interval window, so the fleet does not synchronise outbound traffic against any single target, even when many services share the same upstream provider.
| Type | What it measures | Cadence | Timeout |
|---|---|---|---|
| HTTP | Per-phase timing (DNS, TCP connect, TLS handshake, time-to-first-byte, total). Every HTTP check names the exact status its endpoint is expected to return, and anything else is a failure, including a 5xx and a network-level error. | 60 s | 30 s |
| DNS | Recursive query to an explicit resolver (default 1.1.1.1:53) with optional expected-RDATA match. Bypasses the OS resolver entirely. | 300 s | 10 s |
| TCP | Raw TCP connection establishment time to a host:port. Used where HTTP is not the right surface. Not currently exercised by the v1 service registry; supported by the probe binary for future additions. | operator-configurable | operator-configurable |
| TLS | Full TLS handshake + certificate-chain validation + optional days-until-expiry threshold. In the current registry every TLS check carries a 14-day expiry threshold so we get a warning lead time on cert rotation. TLS results are recorded but do not vote on a service's status. | 3600 s | 30 s |
| Storage | HTTPS GET against a published test object. Validates SHA-256 body hash and Content-Type. Catches silent corruption, not just connectivity. | 300 – 600 s | 90 s |
HTTP status classification. Every HTTP check records success only on the status it declares in advance, and every other outcome is a failure: a different status, a 5xx, or a network-level error (DNS failure, connection refused, timeout, TLS error). The declared status is often a 4xx, because a 401 from an API we hold no credentials for means the server was reachable, routed our request and answered.
Expected status codes. This exists because we send no credentials, so an authenticated API answers every one of our requests with 401 or 403. The original rule counted any 2xx, 3xx or 4xx as success, under which those services could not record an outage unless the endpoint stopped answering entirely. 17 declared an expected status on 2026-09-08 and the rest followed on 2026-09-24, so there is no longer a default to fall back to. We confirmed each expected value was identical from all five probes before adopting it, and a service whose unauthenticated response legitimately changes will read as down until we correct the registry. A daily job re-probes every target and tells us when that happens. Earlier data was recorded under the blanket rule and has not been restated.
Targets changed on 2026-09-24. The same audit found 15 checks whose target could not express an outage whatever status we asserted. Nine answered a redirect to a marketing page, which is a static edge rule rather than a service. Six measured a vendor's own marketing homepage, which was the right edge but meant the latency we published was page weight. GitHub was retargeted for the same payload reason, off a 577 KB page. All 16 were changed in place, keeping their history. Their availability and latency before and after that date are not measuring the same thing, and a 90-day window spanning it splices the two.
Git hosts are measured on git. GitHub and GitLab each carry an extra check against git's smart HTTP endpoint,
the ref advertisement that opens every clone and fetch, because a git host can
serve its website and its API while git fetch fails. Both run against an empty public repository we own on that host, so
no third party's decision to archive or rename can affect the result, and the
response stays at 444 bytes. The repository matters: the same request against
a large project returns its entire ref list, 4.6 MB in one case we measured.
Redirect handling. HTTP checks do not follow redirects. A 301 or 302 IS a valid response and we record the status code we were given. Following redirects would also make the per-phase timing meaningless because each round trip resets the timer.
Authoritative DNS providers. For managed authoritative-DNS services (e.g. AWS Route 53, Google Cloud DNS) we do not use the dns check type. Those products do not run public recursive resolvers (they answer zone-delegated queries), so a recursive query to 1.1.1.1 would measure 1.1.1.1's cache 95% of the time, not the provider. Instead we measure their public control-plane API endpoint over HTTP and TLS. Public recursive resolvers (Cloudflare 1.1.1.1, Quad9, Google Public DNS) are measured directly via the dns check type because the resolver IS the product surface.
From measurement to status
Every probe-check fire produces one row in our raw measurements table. To turn those rows into a public-facing "is this service up?" verdict, we aggregate in two stages: consensus across probes for each check, then one verdict for the service.
Step 1: consensus per check
Each service has one or more primary checks, and only primary checks vote. TLS checks are never primary. In every minute, each voting probe's results for a primary check are combined into one verdict for that check:
A strict majority of voting probes passed the check (success_count > probe_count / 2).
At least one voting probe passed, but not a majority. Includes 50/50 ties.
No voting probe passed.
Fewer than three probes voted in the minute. Excluded from availability calculations.
"Strict majority" matters. With four voting probes a clean 2-of-4 tie counts as degraded, not up; calling a check "up" when half the probes saw it as down would undermine the entire argument of this page. The table below shows how the rule plays out at each likely fleet size:
| Probes voting | Rule |
|---|---|
| < 3 voting | Insufficient signal, no verdict recorded |
| 3 voting | success_count = 0 → down; ≥ 2 → up; else degraded |
| 4 voting | success_count = 0 → down; ≥ 3 → up; else degraded |
| 5 voting | success_count = 0 → down; ≥ 3 → up; else degraded |
| 7 voting (post-expansion) | success_count = 0 → down; ≥ 4 → up; else degraded |
Why < 3 is "unknown". With only one or two probes voting in a minute, a single false negative on a flaky network would flip the verdict. Three independent probes is the smallest number that still survives one probe being down for maintenance and one false negative without the result becoming arbitrary. "Unknown" minutes are excluded from the availability denominator (see below) so they neither artificially inflate nor depress a service's score.
Step 2: the service verdict
Every primary check must reach consensus. If any primary check is down, the minute is down. Otherwise, if any is degraded, the minute is degraded. A minute is up only when every primary check is up.
Who votes
- A probe on the measured provider's own network does not vote on it. That applies to our Hetzner, OVHcloud and DigitalOcean probes, which still measure those providers.
- A probe that fails 30% or more of its one-minute checks in a minute, with at least 10 of them run, abstains for that minute. Failures that broad point at the probe, not at the services it measured.
Earlier history. These rules replaced one under which a probe counted as up if any of its checks passed, TLS included, and every reporting probe voted. Minutes before the change on July 25, 2026 00:00 UTC were computed under that rule and have not been restated.
Availability calculation and ranking
Availability percentage for any window is:
Unknown minutes are excluded from both numerator and denominator. If a
window contains only unknown minutes (e.g. a new service in its first
hour), the availability is reported as no data rather than 0% or 100%, both
of which would be misleading. The API reports the count separately as
unknown_minutes, beside
measured_minutes, so callers who
care about under-measurement can see it.
Availability is reported to two decimal places. At a daily granularity that is the smallest meaningful resolution: one single down-minute in a 1440-minute day already rounds to 99.93%, so finer precision would be noise.
Ranking. The leaderboard sorts services by average availability over the selected window (7 days, 30 days, or 90 days; 30 days is the default), descending. Services with identical availability share a rank, shown as "=1", and the next rank skips accordingly. Within a tie, rows are listed alphabetically; no secondary metric breaks it. Medal colours mark only a top-three position held by one service. A service with no data in the selected window sorts below everything else and is shown as "No data" rather than being hidden.
What the percentage actually means. A monthly 99.9% rating allows roughly 43 minutes of cumulative downtime in a 30-day window; 99.99% allows about 4 minutes 19 seconds. For the rest of the story (how vendors define their own denominators, why the headline number rarely captures the operational tax of an incident, and what to look at instead), see What 99.99% uptime actually buys you.
Tier 1 vs Tier 2: what feeds the leaderboard
We separate the data we collect into two tiers that are stored, queried, and ranked independently. Everything described in this page above (probe checks, consensus, availability percentages, the leaderboard) is Tier 1 only. Tier 2 exists in parallel as a sidecar, never as a ranking input.
-
Tier 1: independent measurement. Our own probe fleet, the rules above, the
measurements_rawhypertable and everything aggregated from it. This is the only data that drives the public leaderboard, category pages, and per-service availability numbers. It is the project's reason to exist. -
Tier 2: vendor status pages. What the provider says about itself. Scraped on a 5-minute schedule from
each service's public status page (the URL listed in our service registry),
parsed into a normalised severity vocabulary (operational, minor, major, critical,
maintenance, unknown), and written to a separate hypertable (
status_page_observations) with explicit provenance: which adapter parsed it, whether the fetch succeeded, what the vendor banner said, how long the fetch took. No view, materialised or otherwise, joins this table with Tier 1 data for ranking purposes.
Why the separation matters. Status pages are structurally biased: a vendor publishing "100% uptime" on a public dashboard during a customer-facing incident has financial reasons to do so (SLA credits) and is, by definition, the entity with the lowest incentive to be honest about its own product. Mingling Tier 2 numbers into Tier 1 averages would let the vendor's editorial decision quietly re-weight our ranking. Keeping them in separate tables makes the comparison the editorial product: "they reported 99.99%, we measured 99.87%" is exactly the kind of signal a reader cannot get from the vendor's own dashboard, and it stays useful only as long as the two numbers are computed independently.
Eleven adapters parse status pages today: Atlassian Statuspage, Status.io,
Better Stack, Sorry, AWS Health, Google Cloud, Azure, Hetzner, Backblaze,
KeyCDN and Fastly. A service whose status page no adapter can read is
still recorded, as an observation with adapter
none, so a gap in our Tier 2
coverage is itself visible as a time-series, not as a silent missing row.
Any Tier 2 figure displayed on the site is labelled as such; the
leaderboard never shows one.
What we do not measure
We measure external reachability from our probe vantage points. That is the entire promise of the headline rankings.
We do not measure provider-internal signals: queue depth, compute capacity, error rates inside a provider's own infrastructure, or anything else a provider does not expose to external clients. A service can be reachable from our probes but slow, and we record that as latency percentiles separately from availability. A provider's internal incident that does not affect external API responses will not appear in our data, by design, because that is the line between "uptime as the user experiences it" and "uptime as the provider's internal dashboards see it".
We do not measure whether an authenticated operation would succeed. We hold no credentials for any service we rank and send none, so we can establish that an API is reachable, routing, and answering the status it should. We cannot establish that a payment would clear or a bucket write would land. A provider can therefore be at 100% here while a customer with an API key is having a bad day. Closing that gap would mean holding production credentials for all 55 ranked services, which is a larger risk than the measurement is worth.
We never use provider-supplied data in the headline rankings. We do ingest provider status-page banners into a separate Tier 2 table as an editorial cross-check (see Tier 1 vs Tier 2), but that data never mingles with Tier 1 measurements and any Tier 2 figure shown on the site is labelled as such.
Data retention and freshness
- Raw measurements are kept for 90 days, compressed after 7 days. After 90 days the raw chunks are dropped, because by then every minute and day they contain has been folded into the aggregates below.
- Per-minute consensus (service_minute_status) is materialised as a TimescaleDB continuous aggregate, refreshed every minute with a 10-minute look-back to fold in any late-arriving probe batches. Retained indefinitely.
- Per-day availability (service_daily_uptime) is refreshed hourly at minute 5 from the per-minute aggregate. Retained indefinitely.
- Public leaderboard hydrates from the public API on every page load (refresh = fresh numbers, capped by the API's 5-minute edge-cache TTL). End-to-end staleness is at most ~1 hour for the leaderboard (driven by the daily-aggregate's hourly refresh), ~1 minute for any individual service's current-status badge.
- Timestamps on the site and via the API are UTC. Minute and day buckets are aligned to UTC, not to any local time zone.
Independence and conflicts of interest
UptimeProject has no commercial relationships with any measured provider. No provider pays for inclusion, position, or favourable treatment. No provider gets advance notice of incidents we detect.
Where affiliate links appear, they are standard consumer-side referral commissions that exist independently of our measurements and do not influence ranking, inclusion, or anything else observable on this site. Ranking is a deterministic function of the measurement data using the formula defined above: no editorial weighting, no manual promotion, no exceptions for sponsored services.
The service registry (which services we monitor and with what checks) lives in a private repository, with a dated, justified commit for every change. That history is not published. We will produce the change record for any specific service on request.
Verify our claims
This page is the authoritative description of how UptimeProject measures, classifies, and ranks. The numbers behind every leaderboard entry are exposed via our public read-only API. Browse the interactive reference at /docs/api/ or fetch the raw OpenAPI document at api.uptimeproject.org/v1/openapi.json.
If a published figure looks wrong, query the API for the underlying minute and daily aggregates over the same window and reproduce the calculation defined in "Availability calculation" above. If they don't match, tell us; corrections are public.
Frequently asked
Why is HTTP 4xx sometimes treated as success?
Because we send no credentials, so an authenticated API answers 401 or 403 no matter how healthy it is. A 401 means the server was reachable, routed our request and the auth layer answered, which is the uptime signal; whether the response is what a particular client wanted is application-layer. Requiring a 2xx everywhere would make a public uptime score depend on our being authorised to call every endpoint we measure. A 4xx only counts as success where the check names that exact code in advance, so the same 403 is success for one service and an outage for another. 5xx and network errors are never success.
What is an expected status code, and why does every check have one?
Most of the APIs we measure require authentication, and we deliberately send none. Such an endpoint answers an unauthenticated GET with 401 or 403 forever. Under a blanket "any 4xx is up" rule those services could never record an outage: the score only moved if the endpoint stopped answering altogether, so a broken API behind a healthy edge would have scored 100%. We found this on 17 services on 2026-09-08 and fixed those; a second audit on 2026-09-24 found the rule was the smaller half of the problem, and that nine more checks were pointed at a URL that answered a redirect to a marketing page. A redirect is a static edge rule, so naming its status would have pinned the wrong measurement. Those nine were retargeted onto real API routes first. Every HTTP check now names the exact status its endpoint should return, and anything else (a different 4xx, a 5xx, a timeout) is a failure. Every expected value was confirmed identical from all five probes before we adopted it, and a daily job re-checks all of them against the registry.
Why "1-minute buckets" and not 10 seconds or 1 hour?
One minute is the smallest bucket where the median check has fired from every probe at least once (60 s default check interval, 5 probes, deterministic per-check jitter spreads them across the window). Shorter buckets would have systematic gaps where "unknown" dominated. Longer buckets would hide brief incidents: a 90-second outage spread across two adjacent minutes shows up as two degraded minutes, which a 1-hour bucket would round to a single non-event.
Why do "unknown" minutes get excluded from the availability denominator?
Unknown means we did not measure the service reliably in that minute, usually because fewer than three of our probes voted. Counting unknown as "up" would inflate availability with minutes we cannot defend. Counting it as "down" would penalise services for gaps in our own probe coverage, which is unfair. Excluding it is the only honest choice; the API reports the count separately as unknown_minutes.
Why might a provider show 100% on their own status page while we report less?
Provider status pages report on the internal state of provider-owned systems. We report on external reachability from independent vantage points. Both can be technically correct: a regional fibre cut between Roubaix and the provider has zero internal signal but a real impact on our Roubaix probe. Conversely, an internal incident that does not reach the customer surface will not appear in our data. We measure what users experience.
How often does the leaderboard update?
Per-minute consensus refreshes every minute. The daily availability table refreshes hourly at minute 5 (TimescaleDB continuous aggregates + a regular materialized view). The static site itself hydrates against the public API on every page load: a browser refresh re-fetches the leaderboard with at most ~5 minutes of edge-cache TTL between you and the database. End-to-end, the public leaderboard is at most ~1 hour behind real-time (driven by the daily-aggregate refresh, not the website cadence).
Why does the leaderboard rank 55 services when you list 56?
Because 1 of them are measured only against their provider's status page, not by our probes. They exist as separate entries so that incidents a provider attributes to a specific product line stay attributed to it. Ranking them would hand one provider 2 rows where the probes see a single service. The ranked entry is the comparable one.
A service was added recently and shows "no data yet". When will it have a ranking?
Services need at least one complete daily bucket (00:00–23:59 UTC) before they have a 1-day availability number, and 30 daily buckets for a 30-day ranking. New services are included in the registry immediately and appear in the leaderboard as "No data"; the ranking populates as data accumulates.
Why aren't there AWS, GCP, or Azure probes?
A probe on AWS measuring AWS would have a structurally favourable network path that no AWS competitor enjoys, which would corrupt the comparison. Three of our probes do run on providers we measure, and each is left out of the consensus for its own provider (see "Who votes" above).
Can I get the raw measurements?
Yes. The public API at api.uptimeproject.org exposes per-minute consensus and per-day availability. Per-minute and per-day aggregates are retained indefinitely, but the public API caps responses to the trailing 90-day window for cost and cache reasons; older history is available on request. The OpenAPI spec is linked in the footer. Raw per-probe per-check rows are not currently public; they are retained internally for 90 days for our own analysis. If you have a research use case, write to us.
Data license
All measurement data published on this site and via the public API is licensed under CC BY 4.0. You can use, share, and build on it for any purpose, including commercial, with attribution to UptimeProject and a link back to this methodology page.
Questions, corrections, research collaboration? hello [at] uptimeproject [dot] org