DOCS

Heartbeats

Understand passive checks: how heartbeats monitor cron jobs, background workers, and scheduled tasks.

What is a heartbeat?

A heartbeat is a passive check. Instead of the platform actively probing your service, your service probes the platform. At the end of each scheduled job run, your script sends an HTTP POST to a unique ping URL. The platform records the ping and resets the timer. If no ping arrives within interval + grace_period, an alert opens.

This inverted model is ideal for monitoring things that cannot be reached from outside your network: cron jobs, internal workers, batch processes, or any task that runs on a schedule.


How the timing works

DAILY BACKUP JOB
UP
Last ping 6 minutes ago — next expected in 24 minutes

The grace period is an intentional buffer to absorb jobs with variable runtime. Set it to at least 20–30% of the expected runtime variance.

A heartbeat is marked down (and an alert opens) when any of these holds:

  • the last ping is older than interval + grace_period, or
  • it was never pinged and is older than twice its interval, or
  • a cron-scheduled heartbeat missed its scheduled time plus grace.

Alerts are idempotent: while one alert is open, missing again does not open another.


Heartbeat statuses

StatusMeaning
NewCreated, no pings received yet
UpLatest ping arrived within interval + grace_period
DownGrace period exceeded, alert opened and sent

Ping URL format

Each heartbeat gets a unique URL of the form:

POST https://api.howlops.com/api/v1/hb/{slug}

The {slug} is the URL-safe identifier shown on the heartbeat detail page. The endpoint is public and requires no authentication (the secret is the unguessable slug itself). POST is recommended, but GET and HEAD are also accepted — handy for uptime tools or browsers that can only issue a GET. The response body and any request body are ignored, only the URL matters. A 200 OK response confirms the ping was recorded.

The ping URL is a secret. If it is ever exposed (committed to a public repo, logged in a public place), delete the heartbeat and create a new one to get a fresh slug, then update your job to use the new URL.


History retention

Heartbeat ping history is retained according to your plan's data-retention window (from 7 days on Free up to 365 days on the top Uptime plan — see tier limits). The heartbeat detail page surfaces a recent ping-timeline chart (the last 24 hours) plus a log table; it does not render the entire retention window at once.


Common patterns

Job success only

bash
/path/to/job.sh && curl -sS -X POST "$PING_URL"

Separate success from failure

bash
if /path/to/job.sh; then
  curl -sS -X POST "$PING_URL"
else
  echo "Job failed, skipping heartbeat ping" >&2
  exit 1
fi

Python context manager

python
import contextlib, requests

@contextlib.contextmanager
def heartbeat(ping_url: str):
    yield
    requests.post(ping_url, timeout=5)

with heartbeat("$PING_URL"):
    run_my_job()

Was this page helpful?