Skip to content
PulZone
Aug 2, 2026 · Ben

How to check website and service status properly

Most uptime checks answer a question nobody asked: did something reply? Here is how to check status so that a pass means working and a page means broken.

Most uptime monitoring answers a question nobody asked.

"Did something at that address reply?" is not a question your customers care about. They care whether the page worked. Those two things agree with each other most of the time, and the times they disagree are exactly the outages that run for six hours while your dashboard stays green.

This is a practical guide to checking status so that a pass means working and an alert means broken.

Principle one: assert on content, not on connectivity

The single highest-value change most people can make to their monitoring is to stop checking for HTTP 200 and start checking for a specific string.

Consider how many ways a request can return 200 while being useless:

  • A custom error page rendered with a 200 status, because whoever wrote it did not set the status code.
  • A framework debug page, exposing your stack trace to the internet.
  • A cached copy served by your CDN while the origin behind it is on fire.
  • A maintenance page.
  • A login page, returned because the session handling broke and every request is now redirected to sign-in.
  • A perfectly correct page shell whose main content failed to load.
  • A parked-domain page, if DNS has drifted somewhere unexpected.

A monitor watching for the status code passes on all seven.

Pick a string that can only be present when the page has genuinely worked. Good candidates: a product name rendered from the database, a price, an element that only appears after a successful query. Bad candidates: anything in the header, the nav or the footer, because those are usually static and will render happily on top of a completely broken page.

The mirror image is just as useful: alert when a string that should never appear does. Fatal error, Warning:, undefined, Exception, Traceback — a check that fails when it sees any of those catches an entire category of breakage without you having to predict which page will break. See keyword monitoring.

Principle two: check the transaction, not the brochure

Almost everyone monitors their homepage. The homepage is usually the most cached, most static, most defensively built page on the site — the one least likely to break and least costly when it does.

Meanwhile the pages that actually matter go unwatched: checkout, signup, login, the search results page, the API endpoint your mobile app depends on. These are the pages with database queries, third-party calls and payment providers behind them. They are where failure is both most likely and most expensive.

You do not need full browser automation to get most of this value. A plain HTTP check against your login page that asserts the form is present catches a large share of real signup failures. A check against a search URL with a query in it, asserting that a known result appears, exercises your search backend end to end. A check against a product page asserting that a price is rendered proves the database is answering.

For anything genuinely transactional, expose a small internal health endpoint that does the real work — opens a database connection, runs a trivial query, touches the cache, pings the payment provider's sandbox — and returns a JSON summary. Then monitor that. You get transaction-level confidence at the cost of an HTTP check, and you decide exactly what "healthy" means rather than inferring it. Guard it with a token if it reveals anything useful to an attacker.

Principle three: an API needs its body read

If you are monitoring an API, the status code is even less informative than it is for a web page, because well-behaved APIs deliberately return 200 for responses that represent failure.

HTTP/1.1 200 OK
Content-Type: application/json

{"data": null, "errors": [{"message": "upstream timeout"}]}

That is a broken API returning a successful status, and it is completely standard behaviour for GraphQL. A useful API check asserts on:

  • Status — a specific code, or an explicit allow-list. "Any 2xx" is often too loose; a 204 where you expect a 200 with data is a bug.
  • Body content — a field that must be present, or an error key that must be absent.
  • Response time, with a threshold that means something for that endpoint.
  • Headers, where they matter — content type, rate-limit headroom, a cache status that tells you whether you are being served from cache.

You will usually need to send custom headers to authenticate. Use a token minted specifically for monitoring, with the narrowest possible scope, so that a monitoring system compromise is not an account compromise. See API monitoring.

Principle four: one probe is an opinion, not a fact

When a check fails, at least five different things could be true, and only one of them is "the service is down". The others are: the network path between that probe and your server is broken; your firewall or WAF has started blocking that probe; a routing change is sending traffic somewhere unhelpful; or the probe itself is unwell.

Alerting on a single failed check from a single location means paging a human for all five. Do that for a fortnight and your alerts will be muted, at which point you have the illusion of monitoring, which is strictly worse than knowing you have none.

Two rules fix most of this:

Confirm from elsewhere before alerting. A failure seen from one region and immediately re-tested from another is either a real outage — both fail — or a network problem local to the first probe. This is the single most effective anti-noise measure available, and it costs one extra request.

Require consecutive failures for slow-burn signals. For response-time thresholds especially, a single slow sample is noise. Three in a row is a trend.

Multi-region checking has a diagnostic bonus beyond noise reduction. "The site is down" starts an investigation. "The site is down from Europe but fine from North America" has already finished half of it.

Principle five: pick the interval from the promise you are making

Check interval is not a quality setting where more is better. It is a resolution setting, and the right value follows from what you have promised.

Sampling every five minutes means an outage shorter than five minutes may leave no trace at all. Your dashboard will show a clean month containing real failures. As covered in what is uptime, your interval sets a floor on detectable downtime and therefore a ceiling on the uptime figure you can honestly claim.

A workable rule:

  • Five minutes — blogs, brochure sites, internal tools, anything where a few minutes of downtime has no measurable cost. This is what the free tier gives you and it is genuinely enough for most sites.
  • One minute — anything taking money, and anything with users who will notice and complain.
  • Thirty seconds or faster — services with an SLA that has penalties, or where a minute of downtime cascades into other systems.

Do not set everything to the fastest interval available. You will multiply your noise, add load to your own infrastructure, and — for third-party endpoints — risk being rate-limited into a self-inflicted outage.

Principle six: watch the things that fail on a calendar

Some failures are scheduled in advance and still take down real companies every year, because nothing was watching the date.

TLS certificates expire at a known instant, and at that instant every visitor gets a full-page warning describing your site as dangerous. Automated renewal helps and does not eliminate the risk — renewals fail, hooks silently stop reloading the server, one hostname gets left off a SAN list. Monitor the actual certificate served on the actual port, not the one you believe is installed, and warn at least two weeks out. See SSL certificate monitoring.

Domain registration is worse, because recovery is not in your hands and your email dies with it — including the renewal warnings. Domain expiry monitoring costs nothing and prevents a multi-day catastrophe.

Scheduled jobs fail by not happening, and absence generates no event. Invert it with a cron heartbeat: the job calls a URL when it finishes successfully, and the monitor alerts if that call does not arrive within the expected window. Put the heartbeat call at the end of the job and only on the success path — a heartbeat fired at the start tells you the job began, which is not the thing you wanted to know.

Principle seven: check the layers underneath

When the website is down, the useful question is which layer failed. If HTTP is the only thing you check, every failure looks identical.

Adding cheap lower-level checks turns one ambiguous alert into a diagnosis:

  • Ping (ICMP) — is the machine reachable at all?
  • TCP port — is the service listening? A port check on 5432 or 3306 distinguishes "the database is down" from "the app can't reach the database".
  • DNS — does the name still resolve, and to the address you expect?

Fire those together and the shape of the alert tells you where to look: ping fine, port 443 refused means the web server died rather than the box. Ping failing too means the box or the network. See ping and port monitoring.

Principle eight: monitor from outside, always

A monitor running on the server it monitors is not a monitor. When the machine goes down, so does its opinion about whether it is down. When the network in front of it fails, it will cheerfully report perfect health to nobody.

The same applies to the alerting path. If your alerts go out through the mail server on the box that just died, you have built a system that is silent precisely when it matters. Send alerts through a path with no shared failure domain with the thing being watched.

It is worth being straight about where this points: it is the strongest argument for not running your own monitoring at all. Anything you host shares a provider, a region or a network with something it is watching, and the correlated failure is exactly the one you most need to hear about. A monitoring service run by someone else, from regions you do not rent, has no shared failure domain with you by construction — and that, rather than convenience, is the real reason to buy this rather than build it.

Principle nine: route alerts like they will wake someone

The technical setup is the easy half. The half that decides whether monitoring survives contact with your team is what happens when a check fails.

  • Not everything deserves a page. Certificate expiring in fourteen days is an email. Checkout returning 500 is a phone. If both arrive the same way, the important one is buried.
  • The alert should carry the diagnosis. Which monitor, which region, what the response actually was, how long it has been failing. An alert that says only "monitor 7 is down" starts the investigation from zero.
  • Recovery notifications matter. Knowing something came back — and how long it was gone — is what turns alerts into a record you can reason about.
  • Test the path deliberately. Break something on purpose and confirm the alert arrives on the device it should. Do it again after anyone changes phone, job, or notification settings. An untested alerting path is a hope.

Principle ten: let the status page be a consequence

If a human has to notice a problem before your status page reflects it, your status page cannot tell anyone about problems — it can only confirm what you already knew, late.

Wire it the other way. Monitoring detects, the status page reflects. Then it is accurate at 04:00 with nobody awake, and your customers answer their own question instead of finding your contact form, which may be on the site that is currently down. Keep it on your own domain so it is recognisably yours, and choose which monitors are public — a status page should be a useful summary, not an unfiltered map of your infrastructure for anyone who wants one. See status pages.

A setup worth copying

For a typical small business site, this is a complete and proportionate arrangement:

What Type Interval Alerts
Homepage, asserting on rendered content HTTP + keyword 1 min Page
Checkout or signup HTTP + keyword 1 min Page
Health endpoint (DB, cache, payments) API, JSON assert 1 min Page
Public API API, status + body 1 min Page
Web server port 443 TCP 1 min Page
Server reachability Ping 1 min Email
TLS certificate Certificate Daily Email, 14 days out
Domain registration Domain expiry Daily Email, 30 days out
Nightly backup Cron heartbeat Expect daily Page if missed

Nine monitors. Well inside the free tier, and it covers essentially everything that takes small sites down.

The short version

Assert on content rather than connectivity. Check the pages that make money, not the one that is easiest to check. Read the response body on APIs. Confirm from a second location before waking anyone. Match interval to what you have promised. Watch the things that expire on a calendar. Check the layers underneath so an alert carries a diagnosis. Monitor from outside the thing you are monitoring. Route alerts by severity and test that they arrive. Let the status page follow the monitoring rather than a person.

Do that and a green dashboard means something. Which is, after all, the only reason to have one.

Set it up free — every check type described above is on the free plan, so none of these principles costs extra to follow.

Start monitoring in about a minute

Free forever for 50 monitors. No card, no trial clock, no sales call.