Skip to main content

Uptime Monitoring

StorePilot already tells you when your storefront is broken. Uptime monitoring tells you when it is not there at all — which is the failure your error tracking cannot report, because a site that is down runs no JavaScript and sends nothing.

Nothing is probed until you add a target.

Adding a monitor​

Settings → Monitoring → Uptime monitors → Add a monitor.

A monitor is one address, with a name you choose — the name is what an alert says, so "Storefront" and "Checkout API" beat "monitor 4". A site can have several, each keeping its own history and its own incidents, which is what a shop with a storefront and a payment API needs: one falling over should not be reported as the other.

The first probe runs within five minutes. If you do not want to wait, press Check now on the Uptime page.

Web page, or API endpoint?​

The kind decides how your answer is read. It changes nothing about how the request is sent except the method, and everything about what counts as healthy.

Web pageAPI endpoint
MethodHEAD, retried as GET on 405/501GET
Counts as up200–3992xx, or exactly your expected status
A bot-protection challengeUp — your edge answeredDown — a 403 is a refusal
Ports80, 443, 8080, 8443those, plus 3000, 4000, 5000, 5678, 8000, 8081, 8888, 9000
The answer's bodyNever readRead only if you add a body check

Expected status exists because an API can legitimately answer 401 or 404 at the address you want watched. Set it and only that exact status counts as up — including instead of 200, because "we expect 401" and "any 2xx will do" are different statements and only you know which you meant. Leave it empty for "any 2xx".

The port lists differ for the same reason: a storefront lives on a web port, and your own service does not have to. Neither kind can reach a private address, a loopback address or a cloud metadata endpoint — that rule is identical for both and is not something a monitor can be configured past.

Checking what an API answers​

A status code is not always the whole answer. A health endpoint commonly answers 200 both when everything is fine and when part of the service is failing, and says which in its body:

{ "status": "degraded", "release": "2026.10.13", "failing": ["pricing"] }

An API endpoint monitor can check the body as well as the status. Both checks are optional, and you can use either or both:

  • Response must contain — the check fails unless the body contains this text, exactly as typed (case matters). Up to 200 characters.
  • JSON field and must equal — a dotted path into a JSON body and the value found there. status reads the top-level status; checks.pricing reads pricing inside checks; failing.0 reads the first item of the list failing. Letters, digits, _ and - in each part, up to 10 parts. A text value is compared exactly; a number or true/false is compared as JSON writes it, so checks.db must equal true works. A list or an object never equals a value. The field and the value go together — set both, or neither.
  • Add JSON field adds another row. A monitor can check up to 10 fields, and it is up only when every one of them matches — status = ok and checks.db = true together. One field can be checked once: two values for the same field could never both match.

With JSON field = status and must equal = ok, the example above is down, and the monitor's last error reads JSON field status is "degraded", expected "ok" — which is also what the alert says. When several fields fail, the error names the first one in your list and counts the rest: JSON field checks.db is false, expected "true" (and 1 more JSON check failed).

How the checks run:

  • Only after the status passes. An answer that is not a 2xx (or not your expected status) is down on its status, and the error is the status — the body is not read.
  • At most 64 KB of the body is read, within the same ten-second timeout as the request. A longer body is a failed check that says so, not a verdict over its first 64 KB: half a JSON document does not parse, and a match in the part we read would be a pass over a body nobody read. A body that is not valid JSON fails a JSON field check with that sentence.
  • Always with GET — an answer to HEAD has no body, so a monitor with a body check cannot be saved with HEAD.
  • A failed body check counts as a failed probe like any other: two in a row open an incident, and the first passing probe closes it.

Body checks are for API endpoints only. A web page is checked by its status alone, and moving a monitor from API endpoint to web page removes its body checks. They change nothing about which addresses can be probed: the body is read only from an answer that already came through the rules below.

What a probe is​

Every five minutes, StorePilot sends one request to each of your monitors and waits up to ten seconds.

  • Down is a status that does not qualify, a timeout, a refused connection, or a name that does not exist.
  • Not checked is the third answer, and it is not a softer "down": our own DNS resolver could not answer for the address, so the site was never asked. A DNS failure is two different facts wearing one error — "this name does not exist" is the resolver answering, which is what an expired domain looks like and is scored down; "the resolver did not answer" says nothing about your site. The probe tells the two apart by asking the same resolver a question it must be able to answer, and only when that fails too is the check marked not checked: it does not count towards uptime, it opens no incident and it closes none. The next probe runs five minutes later as usual.
  • A monitor can be switched off without being deleted — during a migration, say. Deleting it takes its probe history and its incidents with it.

Redirects are followed, up to three hops. Your domain is what you typed when you added the site, so an apex that sends everything to www. is the ordinary case, and a check that stopped at the redirect would be scoring your redirector rather than your shop. Every hop is re-checked against the same address rules as the first — a redirect into a private address is refused, not followed, and the probe stops there with the answer it already had.

Sites behind bot protection​

Our probes come from a datacentre address, which is exactly what Cloudflare, Sucuri, Imperva and friends are built to challenge. When one of them answers instead of your site, that is not recorded as an outage: your own edge answered, in milliseconds, and reporting a permanent outage on a shop that is serving every visitor normally is how a monitor stops being read. With no bypass key configured the check is marked up and the page says who answered, because the state of your origin genuinely is not visible from outside in that case. With a bypass key configured a challenge means the key did not reach your origin, and the check is marked can't verify instead — not up, because nothing was verified, and not down, because nothing failed. The page names the one step that fixes it.

Cloudflare's 520–527 are the opposite and stay down: those are the edge saying it could not reach your server, which is the outage this feature exists to catch.

To have the probe see your real site, set a bot-protection bypass key in Settings → Monitoring → Bot protection. Every check we make on that site then carries

X-StorePilot-Bypass: <your value>

and you let it through in your WAF — in Cloudflare, a Custom Rule matching (http.request.headers["x-storepilot-bypass"][0] eq "your value") with the action Skip. Use a long random value: it is a credential. It is stored encrypted, never shown back to you, and it is sent only to your site's own domain — never to a host your site redirects to. The same key is used by the installation check on the Installation tab, so one WAF rule covers both.

A Skip rule does not cover Cloudflare's Under Attack Mode, which is a Security Level rather than a WAF component. While it is on, allow our prober's address directly (IP Access Rules → Allow) or add a Configuration Rule setting Security Level to Essentially Off for the header above — until then the check reads can't verify.

Incidents​

An incident opens on the second consecutive failure, not the first. One failed probe is packet loss, and a monitor that pages on packet loss gets muted, which is worse than no monitor. Further failures extend the open incident rather than starting new ones.

The first success closes it. Recovery is not debounced — if your site is answering, you want to be told immediately.

Both transitions notify every notification destination subscribed to Uptime. The recovery message carries how long the outage lasted.

Reading the page​

Dashboard → Uptime.

  • Status — up, down or can't verify, since when, and the percentage of verified probes that succeeded in the window, above a 90-day strip of one bar per day. Can't verify says why: a bot wall our probe could not see past, or our own resolver failing to answer. Only the first is something you can fix, and only for the first does the page tell you how.
  • Today — every probe of the current day on a 00:00 → 24:00 track, so a brief outage this morning is visible in place rather than averaged away.
  • Response time — how long your site took to answer, over the recent probes. Once the series crosses midnight the labels carry a date, so two points an hour apart on screen are never a day apart in fact.
  • Incidents — when each started, how long it lasted, how many checks failed, and the diagnosis: the HTTP status, or the error if there was no response at all. The start time is a link: it opens that day.

Click a day​

Every day in the strip that has something behind it opens. You get that day's probes on the same 00:00 → 24:00 track, on the shop's clock — the strip is keyed by the shop's day, and a panel answering about a different twenty-four hours than the square you pressed would be worse than no panel. Under it: every incident that touched the day, and every probe that failed, was slow, or could not verify the site. Not a sample of them — this is the screen you open because something happened.

The open day is in the address, so "what happened on the 14th" is a link you can send.

Individual probes are kept for 30 days. Opening an older day says so, and still shows any incident from that day, because incidents are kept for two years. "We no longer keep the probes" is not "nothing happened" — the same reason grey and green are different colours.

The colours​

ColourMeaning
GreenThe day has probes and none of them failed
RedAn outage covers the day — the site was unreachable for at least two probes running
Pale redIsolated failures, and no outage: probes were lost, your site never went down
Dark amberEvery probe answered, and the day was slow — over the threshold for this target
AmberThe day has probes and not one of them could verify the site — every one was a bot wall or a resolver failure
GreyNo data — monitoring was off, or the site is newer than that day

Red and pale red are the distinction worth knowing. An incident opens on the second consecutive failure, for the reason above; a single lost probe is packet loss. Until this split existed, one lost probe out of 288 painted the day the same red as a real outage, so a week could show six red squares for a shop that never went down. Pale red says this happened and you can look at it, not you were down.

Slow is measured against this monitor's own threshold, which is the one on its settings row — an API endpoint is expected to answer faster than a page, and the day strip counts it that way rather than against one number for everything.

Grey exists because "no data" and "down" must never share a colour, and amber because "we could not look" and "we looked and it was fine" must not either. Days 31–90 of the strip are drawn from incident history alone, so a day that nothing covers is honestly grey rather than quietly green.

:::note DNS failures we caused If an incident's diagnosis is DNS lookup failed across several of your sites at the same minute, that is our resolver rather than your domain — sites cannot fail together like that and a shared resolver can. We detect this and record such a probe as can't verify rather than as your outage; an older incident from before that change may still read as down. :::

The HTTPS certificate​

Once a day every enabled https:// monitor's certificate is read — its own connection to the same address the probe is allowed to reach, with the hostname named the way a browser names it. The Uptime page shows when it runs out, in amber once fewer than 14 days are left and in red once it has expired.

You are told twice: when 14 days are left, and again when 3 days are left — each once for that certificate, through the monitor's notification destinations (the Uptime event). A renewed certificate starts over. A certificate that could not be read is shown as such, never as valid, and opens no incident: whether the shop answers is the probe's question.

A webhook receives this as uptime.cert_expiring, on the version 2 contract only.

Addresses that will not be probed​

The URL is yours to type and the request is made from inside our hosting network, so it is checked before it is fetched. A refusal is recorded as a failed check with the reason, so you can see it on the page rather than wondering why nothing happens.

  • Only http: and https:, and only on ports 80, 443, 8080 and 8443.
  • No localhost, no *.internal.
  • No private or reserved address — including link-local 169.254.x.x, which is where cloud metadata services live. Every address a hostname resolves to is checked, not just the first.

What it does not do​

There is one probe location, not a global network, so this answers "is the site reachable from our host" rather than "is the site reachable from Ohio". A web page's content is never read — only an API endpoint's body, and only when you add a body check — and nothing here can tell whether a page rendered correctly: for that, error tracking is the tool, and it only works while the site is up.