Blog

Uptime monitoring for several apps: what to watch

Most uptime monitoring starts with one check per app: request the home page every few minutes and alert if it fails. That catches the big outages. It misses the ones customers actually write in about, because a home page can load from a cache while sign-in, checkout, or the thing your app does is broken behind it.

With several apps, those quiet failures add up. Here is what is worth watching for each app, how to check each piece cheaply, and how to set up alerts and status pages so one person can keep up with all of it.

Outside checks and inside checks

Google's SRE book makes a useful split in its chapter on monitoring distributed systems. Black-box monitoring tests what a user would see from outside. White-box monitoring looks at the system's internals. It also says monitoring should answer two questions: what is broken, and why.

A home page check is black-box: it tells you the site answers. To know why something broke, or that a part behind the site broke while the page still loads, the app has to check its own dependencies and report on them. In practice that means one health address per app that does both.

What to watch for each app

Go through each app and list what it cannot work without. For most small SaaS products the list is short:

  • The public site. The address customers type. Check it from outside, as a user would.
  • Other hosts you run. A separate API, a worker, an admin app. Each one can go down on its own.
  • The database. The most common cause of "the site loads but nothing works". A select 1 proves the app can connect and run a query.
  • The job queue. If emails, imports, or webhooks run in the background, a stuck queue fails silently. Check that the app can reach it, and if you can, how old the oldest waiting job is.
  • Payments. A revoked or expired key stops checkout without taking anything else down. Stripe's retrieve balance call is a cheap read that proves the key works.
  • Your AI provider. If a feature calls a model, listing models is the cheap check: Anthropic's GET /v1/models needs your API key but generates nothing, so it costs no tokens.
  • Other integrations. A GitHub App, for example, can call GET /app, which needs the app's own JWT.

Check your integration, not the vendor's status page

It is tempting to watch a vendor by polling its status page or home page. Do not. A vendor's status page tells you the vendor is up for most people. It does not tell you that your key is still valid, that your account is not over a limit, or that your app can reach them. Those are the failures you can actually fix.

So each dependency check should use the app's own credentials and the cheapest authenticated call the vendor offers, like the ones above. If it passes, your integration works. If it fails, the error names the problem, whether that is an expired key or an outage on their side.

Build one health address per app

Put those checks behind one address, such as /health, and point your uptime monitor at it instead of the home page. A few rules keep it useful:

  • Mark each check critical or not. If the database fails, the app is down: answer with a 503. If the AI provider fails but the rest of the app works, it is degraded: answer 200 and say which part failed.
  • Give each check a short timeout. One slow dependency should not make the whole health address time out.
  • Cache results briefly. A monitor polling every minute should not use up a vendor's rate limit. Keep a passing result for a short while, and a failing one for less, so a recovery shows quickly.
  • Say little. The health address is usually public. Return each service's name and whether it is up, never error messages, keys, or data.

Alerts one person can live with

With several apps, alert fatigue arrives fast. A few habits help:

  • Alert on what users feel. Site down, checkout broken, sign-in failing. A slow internal job can wait for the weekly look.
  • Wait for more than one failure. Requiring two or three failed checks in a row before alerting filters out network blips, at the cost of a few minutes.
  • Hear about it three times at most. Once when it starts, once if it gets worse, once when it is fixed. Not on every failed check.
  • Decide whether you need a phone call. Email and push are enough for most small products. If an outage at 3am would cost you real money, use an on-call tool that pages you.

A status page for each app

A status page saves you answering the same email over and over during an outage. Give each app its own page, hosted somewhere other than the app itself so it stays up when the app does not. Post a short note when something breaks (what is affected, that you are on it) and another when it is fixed. Plain and calm beats detailed. A badge on your site or README and an RSS feed let customers follow along without asking.

The weekly look

Alerts cover the moment. Once a week, look back: each app's uptime over 30 days, every outage with how long it lasted and what the check saw, and any service that failed more than once. A database that drops for two minutes every night during an import is not an emergency, but it is a fix worth scheduling. The weekly review routine puts this next to revenue and traffic.

How LopeBase does it

We run several products ourselves, and LopeBase Uptime is built around the approach above. Add a site's address and it is checked every 15 minutes by default, or every 30 minutes or every hour, with no account or key needed. Each site has its own settings: how many failed checks in a row count as down, when to alert, and an optional response time above which it counts as degraded.

If an app runs the LopeBase Adapter, its health address (/api/lopebase/health by default) lists each service you declare, each checked with the app's own credentials and a cheap call like select 1, Stripe's balance.retrieve, GitHub's GET /app, or an AI provider's GET /models. A critical service failing answers 503 and the site shows as down; a non-critical one shows it degraded. Wrapping a check in cachedCheck keeps a pass for 60 seconds and a failure for 10, so frequent polls do not use up a vendor's limit. LopeBase never pings a vendor's status page. Running npx lopebase in a product's folder lists the databases, queues, and email it finds, as a starting point.

Alerts go by email and browser push, once when something starts, once if it gets worse, and once when it is fixed. A public status page for each app is free on every plan, with notes, an RSS feed, and a badge, and after real downtime the incident review drafts the note for you. What it does not do: check private addresses, follow redirects, or phone you. If you need paging, keep your on-call tool, or bring Better Stack monitors onto the same page. The uptime guide has the details.