WatchFor
Monitors

Heartbeat & cron jobs

Get alerted when a scheduled job or background worker doesn't check in.

Most monitors reach out and test your systems. A heartbeat monitor works the other way around: your job, script or worker pings WatchFor when it runs — and WatchFor alerts you when the ping doesn't arrive on time.

That inversion catches the failures outbound checks can't see: a nightly backup that silently stopped, a cron entry lost in a server migration, a queue worker that crashed, a certificate-renewal script that never fired.

Two schedules, one monitor type

When creating the monitor you pick how the pings are expected:

ModeUse it forYou set
Every intervalWorkers and services that check in continuously ("every 5 minutes")The interval + a grace period
Cron scheduleJobs that run at specific times ("03:00 daily")A standard 5-field cron expression, its timezone + a grace period

The grace period is how late a ping may arrive before WatchFor alerts — set it to absorb normal runtime variance (a backup that takes 10–40 minutes deserves more grace than a heartbeat that fires every minute).

The ping URL

Each heartbeat monitor gets a unique ping URL, shown on its detail page:

https://ingest.watchfor.io/p/<your-token>
  • Any HTTP method works — GET, POST, HEAD, whatever your tooling sends.
  • The URL token is the only secret — treat it like a password. Anyone with the URL can ping the monitor.
  • An optional request body (up to 10 KB — e.g. the job's last log lines) is stored with the ping.

Signal endpoints

URLMeaning
/p/<token>Success — the job completed fine
/p/<token>/<exit-code>Report the exit code: 0 = success, anything else = the run failed
/p/<token>/failExplicit failure report
/p/<token>/startThe job just started — pairs with the finish ping to measure run duration

A failure ping still counts as a check-in — it tells WatchFor your scheduling machinery is alive, so you get a "run failed" alert instead of a misleading "missed schedule" one.

Examples

At the end of a cron line — the ping only fires if the job succeeded:

0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://ingest.watchfor.io/p/<token>

Report the real exit code, whatever it is:

/usr/local/bin/backup.sh; curl -fsS https://ingest.watchfor.io/p/<token>/$?

Capture the job's output and attach it to the ping — it's stored with every ping (success or failure, up to 10 KB) and shown in the monitor's Pings log:

OUT=$(/usr/local/bin/backup.sh 2>&1)
curl -fsS --data-raw "$OUT" https://ingest.watchfor.io/p/<token>/$?

Send a start/finish pair correlated by a run ID (rid) — WatchFor measures each run's duration, shows it per ping, and charts it over time:

RID=$(uuidgen)
curl -fsS "https://ingest.watchfor.io/p/<token>/start?rid=$RID"
/usr/local/bin/backup.sh
curl -fsS "https://ingest.watchfor.io/p/<token>/$??rid=$RID"

Already using Healthchecks-style pings? The URL conventions are compatible — migrating is usually just swapping the domain in your existing curl lines.

Alerting

New heartbeat monitors come with two preset alert rules:

  • Missed schedule (critical) — no ping arrived within the expected window plus grace.
  • Run failed (warning) — a ping arrived but reported a non-zero exit code or hit the /fail endpoint.

Two more presets can be enabled on the monitor's Alerting tab:

  • Specific exit code — alert on one exact code, e.g. 137 (killed / OOM) or 124 (timeout).
  • Run duration — alert when a run takes longer than a threshold (requires start/finish ping pairs).

Incidents, notifications and status pages work exactly like any other monitor type.

Good to know

  • No locations to pick — your systems ping WatchFor, so the multi-region location selection other monitors use doesn't apply here.
  • A /start ping doesn't count as the check-in — the finish ping does. Resetting the schedule on start would make a job that hangs mid-run look healthy.
  • A failed delivery of your ping (network blip on your side) looks the same as a missed run — prefer curl -fsS --retry 3 in critical jobs.
  • Pausing the monitor stops the schedule expectation; pings received while paused are simply ignored.

On this page