If you have ever built a health check, you have probably written something close to this:
const res = await fetch(url, { method: 'GET', signal: AbortSignal.timeout(10000) });
const isUp = res.status === 200;
I ran a version of that for a while. It is wrong in at least five ways, and every one of them bit me while building an outage tracker for Indian services.
This is a write-up of what actually breaks, because most monitoring tutorials stop at the snippet above.
1. The server answers, the service is dead
The single biggest gap. 200 OK tells you a server returned a response. It tells you nothing about whether the thing a user came to do still works.
A bank homepage can render in 400ms while UPI payments from that same bank are failing at the switch. Different systems, different teams, different failure modes. Your check is green and the feature is on fire.
You cannot fully solve this from outside. What you can do is stop treating a 200 as proof of health, and stop displaying it as one.
2. 403 is not down
Plenty of sites block automated requests deliberately. Bot protection, WAF rules, rate limits, geo rules. In India this is common on high-value government and travel portals. IRCTC is the obvious example.
A naive checker marks these down permanently. Users learn to ignore your tool inside a week.
403 means the server is alive and refusing your specific request. That is different information from 500, and treating them the same throws away the distinction that matters most:
| Code | Server state | What it tells a user |
|---|---|---|
| 200 | Alive, responded | Little. The feature may still be broken. |
| 401 / 403 | Alive, refusing this request | Usually nothing about the outage. Often your check being blocked. |
| 404 | Alive | The path is wrong, not the service |
| 429 | Alive, rate limiting you | You are the problem, back off |
| 500 / 502 / 503 | Broken, overloaded, or in maintenance | Genuine signal |
| 504 | Something upstream did not answer | Genuine signal, usually a dependency |
| Timeout / DNS failure | Unknown | Ambiguous. Could be them, could be your route, could be your resolver. |
The useful reframe: your check produces reachable, refused, broken or unknown. Not up or down. Collapsing four states into two is where most of the false positives come from.
3. Your check succeeded at the edge
If a service sits behind a CDN, a cached page can serve 200 long after the origin has fallen over. You are monitoring the CDN, not the application.
Worse, plenty of applications return 200 with an error page in the body. A React shell that renders “Something went wrong” is still a 200. So is a maintenance page, quite often.
If you need to know whether the app works, you have to assert on something inside the response, not just the status line. Even then you are asserting on a page, not a payment.
4. It works from where you are standing
A single check from a single region tells you about the path between your server and theirs. Nothing more.
Indian outages are frequently regional. A telecom fault covering a few PIN codes. A state portal collapsing at 2pm on result day. An ISP route going bad in one city. From one vantage point all of these look either fine or globally dead, and both readings are wrong.
Multi-region probing helps and costs money. Which leads to the thing that actually works better.
5. The users already know
This is the conclusion I did not expect when I started.
For consumer-facing services, crowd reports are a better signal than synthetic checks. Not a supplement. Better. A server can answer while the feature is broken, but a person cannot be wrong about their own payment failing.
So the weighting on the tracker I run is deliberate: reports first, server check second. And when the check cannot reach something but nobody is reporting a problem, the page says we could not reach it. It does not say down. That one distinction removed most of the noise.
The methodology is public for the same reason any monitoring logic should be. If people cannot see how you decide, they have no reason to believe the verdict.
The problem nobody warns you about
Crowd signal has a cold start, and it is brutal.
A crowd-sourced tracker with no crowd is a server pinger with extra steps. The signal you have designed the whole system around does not exist until enough people arrive, and people arrive because the tool is useful, which it partly is not yet because the signal is thin.
Things that genuinely helped:
- Make the non-crowd signals carry the product early, and be honest in the copy about what they do and do not prove.
- Set a floor before reports mean anything. One report is a person with bad Wi-Fi. Geographic spread matters more than raw count.
- Make reporting one tap, no login. Every field you add cuts the volume you need.
- Do not fabricate activity. A tracker caught inventing reports is finished, and it is the one shortcut that is genuinely fatal.
## And the uncomfortable part
On 18 November 2025, Cloudflare had an outage that took down X and ChatGPT. Downdetector went down with it, because Downdetector runs on Cloudflare.
So does the tracker I run. So does a large chunk of the internet.
There is a real architectural point in here. Your monitoring should not share a failure domain with the things it monitors, and for most small teams it does, because everyone reaches for the same three providers. Fully solving it means running your status surface on genuinely independent infrastructure, which is more work and more money than it sounds.
The partial answer is a second route that does not share the dependency. A status feed on a different provider, or a social account, or anything that survives when your primary does not. Cheap insurance against the exact hour you are most needed.
What I would tell past me
- Return four states, not two.
reachable,refused,broken,unknown. - Never render
403as down. - A
200is weak evidence. Assert on content if the answer matters. - One vantage point measures your path, not their health.
- For consumer services, weight human reports above synthetic checks.
- Publish your logic. It is also how you find out you were wrong.
- Check what your monitoring runs on before you need it to survive something.
If you are building anything in this space, the thing I would push hardest on is the four-state model. Almost every false positive I have had traces back to squashing an ambiguous result into a confident one.
The tracker is SiteDownStatus if you want to see how the output ends up looking, and I am happy to talk through any of this in the comments.