---
title: "Thirty-one checks, one grid"
description: "HarpyWatch runs thirty-one distinct kinds of check against a site — not thirty-one variations on an HTTP request. Here is the full list, what each one is actually for, and why they share a single screen."
url: https://staging.harpywatch.com/blog/thirty-one-checks-one-grid
kind: news
author: "The HarpyWatch team"
published: 2026-09-02T07:08:16.055480+00:00
tags: ["Product", "Reliability"]
publisher: HarpyWatch
---

# Thirty-one checks, one grid

Most uptime monitoring answers one question: does the front page return a 200?
That is a real question and it is worth answering. It is also the smallest
possible fraction of the ways a website is broken while returning a 200.

HarpyWatch runs **thirty-one distinct kinds of check**. Each one is a separate
executable with its own idea of what it is looking at, its own configuration,
and its own way of being wrong. This is the complete list.

## Is it there at all

- **`http-uptime`** — the classic. A request, a status code, a response time.
- **`availability-sample`** — repeated probes over a window, so a flapping
  endpoint is distinguishable from a down one. One request cannot tell those
  apart, and they need different responses from you.
- **`tcp-port`** — a connection, no protocol assumed. For the things that are
  not web servers.
- **`ttfb-budget`** — time to first byte against a budget you set. Slow is a
  kind of down, on a long enough timescale.
- **`dns-resolution`** — resolution itself, which is upstream of everything
  else here and fails independently of your servers.

## Is the connection trustworthy

- **`ssl-cert-expiry`** — the certificate actually presented on the wire, not
  the one on disk.
- **`cert-chain-trust`** — the whole chain, in order, to a trusted root. A
  missing intermediate works in the browser you tested and fails in the client
  that matters.
- **`tls-handshake`** — protocol versions and cipher suites, in both
  directions: too old is a compliance finding, too new is an outage for an
  embedded client.
- **`domain-expiry`** — the registration underneath the certificate, on a much
  longer clock, with reminders going to a mailbox somebody has left.
- **`mixed-content`** — HTTPS pages loading HTTP subresources, which browsers
  block silently and which nothing in your logs will mention.

## Does it say what it should

- **`dom-content`** — the rendered content, for the case where the page is up
  and the content is a database error.
- **`browser-render`** — a real browser, for pages that are only assembled once
  JavaScript runs.
- **`json-api`** — an endpoint's response body, not just its status.
- **`json-schema`** — that body against a schema, so a field quietly changing
  type is caught where it happens rather than three services downstream.
- **`feed-freshness`** — an RSS or Atom feed that has stopped updating, which
  is a pipeline failure wearing a 200.
- **`broken-links`** — links that no longer resolve.

## Will a search engine and a crawler see it

- **`robots-policy`** — the robots file, because a `Disallow: /` shipped by
  accident is an outage that takes weeks to show up and months to recover from.
- **`sitemap-health`** — the sitemap parses, and points at pages that exist.
- **`redirect-chain`** — the full chain of hops, its length, and whether it
  terminates. A redirect loop is invisible to a check that follows redirects
  and reports the final status.
- **`open-redirect`** — a redirect that will send a visitor wherever a query
  parameter says. A phishing vector and a ranking problem at once.
- **`page-weight`** — total transferred bytes.
- **`core-web-vitals`** — the metrics that are actually a ranking input.

## Is it configured safely

- **`security-headers`** — the standard set, present and sane.
- **`csp-policy`** — Content-Security-Policy specifically, which is long enough
  and subtle enough to deserve its own check.
- **`cors-policy`** — who your API says may call it from a browser. A
  wildcard here is a bad afternoon.
- **`cookie-flags`** — `Secure`, `HttpOnly`, `SameSite`.
- **`http-headers`** — arbitrary header assertions, for the ones specific to
  you.
- **`cache-policy`** — cache headers, where the two failures are opposites: an
  asset that cannot be cached is slow forever, and an HTML document that *is*
  cached serves last week's deploy.
- **`compression`** — whether responses are actually compressed.
- **`third-party-data-flow`** — which third parties a page contacts. This one
  is a privacy and compliance check as much as a technical one: the answer
  changes when a marketing tag is added by someone who does not deploy.
- **`websocket-handshake`** — the upgrade, for products where the interesting
  traffic is not request/response.

## Why one grid

Thirty-one checks across a fleet of sites is a large number of facts, and the
temptation is to give each kind its own screen. We do not, for one reason: **the
question you have during an incident is never about one check.**

It is "what else changed at the same time". A certificate warning next to a
redirect chain that got longer next to a TTFB that doubled is not three
findings — it is one deploy, and the shape is only visible if they are drawn
together. Split across three tabs, they are three separate mild concerns that
nobody correlates until afterwards.

So every asset is a row, every check is a cell, and the whole fleet is one
picture. When something moves, the things that moved with it are adjacent.

A note on the number, because we would rather be exact than round. Writing this
piece turned up our own documentation saying "thirty checks" while the registry
that actually runs them held thirty-one. The registry wins, the prose has been
corrected, and the count on our `/llms.txt` and in the site's structured data is
now read from the registry itself rather than typed out — so the next check to
land will update it without anybody remembering to.
