Home / Blog / Uptime monitoring
Uptime monitoring

Why does a website return 200 OK while customers see a broken page?

A green HTTP check and an unusable site are not contradictions. Here is what a status code actually proves, the failures it cannot see, and how to check for the page your customers experience.

A small shop with its lights on and front door propped open but completely empty shelves inside, viewed from the sidewalk on an overcast afternoon

What a 200 response actually proves

A 200 status code tells you that something at the address answered a request and considered it successful. That something might be your application, or it might be a load balancer, a CDN edge, a reverse proxy, or a maintenance page served by your host. Each of those layers is capable of returning 200 with a body that has nothing to do with your product. The status code is generated by whichever layer answered first, and a healthy front door says nothing about the rooms behind it. Related: Status Page Best Practices That Reduce Support Tickets

Even when the application itself answers, a 200 is often the default. Many frameworks return 200 for an error page rendered by a catch-all route, for a template that rendered with empty data because the database query returned nothing, or for a JavaScript shell that will fail once the browser tries to load its bundle. The app did what it was told: it rendered a page. The fact that the page is useless is invisible at the HTTP layer.

Keep reading: How to Choose an Uptime Check Interval That Actually Catches Outages, Status Page Best Practices That Reduce Support Tickets, Uptime vs Response Time: What to Monitor and Why Both Matter. See how PingCrumb helps you uptime monitoring and hosted status pages.

The failure modes that hide behind a green check

The most common one is the empty or partial page. A backend service times out, the frontend catches the exception to avoid a crash, and the user sees a header, a footer, and a blank middle. Login forms that post to a dead endpoint look identical to healthy ones until you submit. Product listings render with zero products. Search returns nothing. Every one of these is a 200 response with a body that fails the customer, and a plain status check will report perfect uptime through all of it. Related: How to Choose an Uptime Check Interval That Actually Catches Outages

A second family is the stale or wrong content problem. A CDN keeps serving a cached page after the origin died, so the site looks alive but no new orders, comments, or logins go through. A misconfigured deploy points the domain at the wrong environment and the staging site appears with test data. A DNS change sends traffic to a parked page at the registrar, which cheerfully returns 200. In each case the request succeeded. It just succeeded at the wrong thing.

How to check for the page customers actually see

The first upgrade is a keyword or content assertion: the check passes only if the response body contains a string that proves the real app rendered. Choose something that comes from data, not from the static template. A footer copyright line appears on the error page too. A product name from the database, the logged-in username on an authenticated endpoint, or a version string the app injects from live config are much better proof. Pair it with a negative assertion, so the check fails if it sees the words your framework uses on its default error page.

The second upgrade is to check a response that cannot be faked by a proxy. A dedicated health endpoint that queries the database, touches the cache, and returns a small JSON document with explicit fields is far more honest than the homepage. Monitor both: the homepage for what the public sees, and the health endpoint for what the system is doing. If they disagree, you have learned something specific about where the break is. Most monitoring services, PingCrumb included, support keyword matching on the body and expected JSON values, so this is configuration rather than code. Related: Uptime vs Response Time: What to Monitor and Why Both Matter

When to go beyond a single request

Some failures only appear across a sequence of requests. A checkout that loads perfectly but fails at payment confirmation. A login that accepts credentials and then redirects to a blank dashboard. For these, a scripted multi-step check that logs in, performs one action, and asserts on the result catches what a single GET cannot. Keep it small. One flow, one assertion per step, run every few minutes. A sprawling browser script becomes its own source of false alarms. Related: How to Set Up Alerting That Avoids False Alarms

The honest tradeoff is that richer checks fail more often for reasons unrelated to downtime: a copy change breaks a keyword match, a redesign moves a button. Treat those as maintenance rather than as a reason to go back to plain status checks. A team that reviews its content assertions whenever the page they target changes will keep a monitor that reflects reality. A team that lets them rot ends up with the same green-but-broken problem, one layer up.

Key takeaways
  • A 200 status only proves that some layer answered successfully; it may be a CDN, proxy, or parked page rather than your app.
  • Empty pages, broken forms, stale cached content, and wrong-environment deploys all look identical to a healthy site at the HTTP level.
  • Keyword assertions on data-driven content and a dedicated health endpoint catch most of these silently broken states.
  • Multi-step checks are worth it for critical flows like login and checkout, but keep them small and maintain them with every UI change.
Julien Jimenez
Written by

Julien Jimenez

Julien Jimenez is an independent software builder based in Paris. He designs, ships, and operates focused SaaS products for small businesses and independent professionals. Read the full author page.

Know before your customers do

Uptime monitoring and hosted status pages. PingCrumb is built to help you put this into practice.

Start monitoring

Get the PingCrumb playbook

Practical guides on uptime monitoring, straight to your inbox as we publish them. No spam, unsubscribe any time.

By subscribing you agree to our privacy policy.