View as Markdown

Website changes

Website and API monitors watch three things beyond uptime, and alert the monitor's contacts as soon as one changes:

Watch Plan How often On by default
Security headers grade Every plan With the website scan: weekly on Free, daily on Pro and Business Yes
DNS record changes Every plan Hourly Yes
Page changes and defacement Business Hourly No

Like domain and certificate expiry alerts, these alerts never mark the website down, open an incident or show on its status pages. The first look at anything only records it: alerts come when it changes. All three show under Website changes on the monitor's page, and turn on or off in the monitor's settings under Also alert on.

Security headers

UpHeron grades the security headers of the monitor's page from A to F, and explains each one that is missing or weak in a sentence, with how to fix it:

  • HTTPS redirect: the http:// address moves visitors to https://, or nothing answers on plain HTTP.
  • Strict-Transport-Security: browsers remember to use HTTPS, for at least six months (max-age=15552000).
  • Content-Security-Policy: limits where scripts may come from. A policy that is only reported, allows 'unsafe-inline' scripts without nonces or hashes, or allows any host counts as weak.
  • Framing protection: X-Frame-Options: DENY or SAMEORIGIN, or frame-ancestors in the Content-Security-Policy.
  • X-Content-Type-Options: nosniff.
  • Referrer-Policy: anything but unsafe-url and no-referrer-when-downgrade.
  • Permissions-Policy: present.
  • Cookie flags: Secure on an HTTPS site, SameSite, and HttpOnly on cookies that look like sessions.

The page is the one the website scan for vulnerability alerts already reads (weekly on Free, daily on Pro and Business), so the grade costs no extra request but a quick look at the plain-HTTP address. Monitors without vulnerability alerts get the same single fetch on the same schedule, and a monitor never graded is graded within the hour.

An alert goes out when a check gets worse than at the last grade: a header that was there is gone or weaker, or HTTP stops moving visitors to HTTPS. A site that never had a header just shows it in its grade. Cookie flags count toward the grade but never alert on their own, because a site sets different cookies on different visits.

DNS records

Every hour the backend looks up, on public resolvers (1.1.1.1 and 8.8.8.8):

  • the host's A, AAAA and CNAME records;
  • its zone's NS (name servers), MX (mail servers), SPF (the v=spf1 TXT record) and DMARC (_dmarc). The zone is the nearest name up from the host with name servers, so www.example.com reads them at example.com.

An alert names the record and its old and new values. Changed name servers, or addresses on another network, are marked serious: they can send every visitor and every email somewhere else.

Why addresses are compared by network

Sites behind a CDN or a load balancer get a different set of addresses every few minutes. Alerting on every one would mean an alert an hour that says nothing. So by default addresses are compared by the network that announces them, its autonomous system (for example AS13335 Cloudflare), looked up with Team Cymru's IP-to-ASN service over DNS. A rotation inside Cloudflare, AWS or Fastly does not alert; the site moving to another provider, or someone pointing it at a server elsewhere, does.

Choose what addresses alert on in the monitor's settings (dns_address_changes):

  • Any address change (address): for a site on fixed addresses of its own.
  • A move to another network (network, the default).
  • Never (none).

Avoiding false alerts

A record that looks different on 1.1.1.1 is asked again of 8.8.8.8, and only a change both give counts, so a resolver that has not caught up yet does not alert. A lookup that fails or times out keeps the last value: a bad minute at a resolver never reads as a removed record. If an address's network cannot be read, its addresses are compared again the next hour.

Page changes and defacement

On Business, turn on Page changes and defacement to have the page looked at every hour. It alerts when:

  • more of the page's text changed than the share you set (25% by default),
  • the page's title changed,
  • a script from a new external host was added, or
  • known defacement phrases appeared (such as "hacked by" or "defaced by").

Smaller text changes quietly become the new baseline, so a page that changes a little every day, such as a list of recent posts, does not add up to an alert.

What is fetched

One request an hour, from the backend in Germany, never from the monitoring locations. When the last answer carried an ETag or Last-Modified, the request is conditional (If-None-Match or If-Modified-Since), and a 304 Not Modified ends the look there. At most 1 MB of the page is read.

What is kept

Never the page itself. The page is reduced, in one pass, to a fingerprint:

  • the visible text, with scripts, styles, comments, tags and attributes left out, and every word with a digit in it dropped (times, dates, counters, nonces, CSRF tokens), kept only as a hash and 32 numbers that estimate how much of it changed;
  • the title, the meta description, the first <h1> and the canonical address (without its query string);
  • the hosts of external scripts, without their cache-busting query strings;
  • any defacement phrases found.

Only two fingerprints are kept for each monitor: the baseline and the latest changed page, with when it changed, what kind of change it was and roughly how much. There is no history: the alert is the record of an earlier change. Because no text is kept, an alert says what changed in these terms: the title from one to another, about how much of the text changed, the new script host, the defacement phrase.

After an alert

The change waits on the monitor's page. If you made it, press Accept as the new baseline (POST /api/v1/monitors/{id}/changes/accept): later looks compare with the page as it is now. If the page goes back to its baseline, the change closes by itself; it is still remembered, so a page that flips between two versions alerts only once.

Content, not appearance

UpHeron has no browser. It compares the HTML the server sends, not how the page looks: a change made only through CSS, images, or JavaScript that runs after the page loads is not seen. A new script host is often how such a change starts, and that does alert.

On a smaller plan

A monitor that had page changes on keeps the setting when its workspace moves to Pro or Free, but its page is not fetched until the workspace is on Business again.

API and MCP

Set the watches on the monitor (POST or PATCH /api/v1/monitors): header_watch, dns_watch, dns_address_changes, content_watch (Business; 422 with plan_required on other plans) and content_threshold (1 to 100). GET /api/v1/monitors/{id}/changes returns the grade with each check, the DNS records and networks, the page's baseline and latest fingerprint, and the last five header and DNS changes. Webhooks receive these alerts with "event": "changed", the watch (headers, dns or content) in watch, and what changed in items.

MCP clients have get_website_changes and accept_page_change, and set the watches with update_monitor.