Dead Man's Snitch more or less named this category. Since 2012 the pitch has been exactly right: a scheduled job's worst failure is silence β the backup that nobody is even trying to run anymore β so instead of a monitor calling your job, your job checks in with a "snitch" URL, and when the check-ins stop, the alarm fires. Simple, correct, and it's been quietly saving nightly backups for well over a decade.
If you already pay for Dead Man's Snitch, there's little reason to move. The tool is mature, the model is right, and their Field Agent CLI does something we don't: it wraps your command, so a check-in can carry the job's exit status and captured output β when a job starts failing, you see why in the alert, not just that it went quiet. Higher plans add smart alerts and error notices on top.
What this page is for is the pricing wall in front of all that (from their own plans page, September 2026):
For a company cron fleet, fine β $19/mo is cheap insurance. But "I have one script and I want the switch armed right now, alerting my Slack, without creating an account" is not a plan they sell. It's the whole product here, free.
curl -X POST https://mockbird.mockbird.workers.dev/api/status/heartbeat \
-H 'content-type: application/json' \
-d '{"name":"nightly backup","period_minutes":1440,"notify":"https://hooks.slack.com/services/T000/B000/XXXX"}'
period_minutes is how often the job is supposed to run; notify is a Slack incoming webhook, a Discord webhook, or any HTTPS endpoint you control. The response arrives with everything you need β a secret ping_url your job will curl, a management secret, and a public status page + badge + Atom feed. A confirmation delivery hits your webhook immediately so you know the channel works, and creation counts as the first check-in: the clock is already running.
No webhook handy? Omit notify and you get a pollable heartbeat instead: the create response includes a poll URL that returns any missed-check-in / checked-in-again transitions since your last poll plus the current ping age — no endpoint to host. How poll mode works.
| Dead Man's Snitch | Here |
|---|---|
| Create a snitch in the dashboard (after signup) | One POST /api/status/heartbeat β no account |
Check-in URL (https://nosnch.in/β¦) | ping_url (/ping/p-β¦) β same idea: hit it from the job |
| Interval (hourly / daily / weekly / monthly) | period_minutes 30β10080, any value in between |
| Alert email (integrations from $19/mo) | notify webhook β Slack / Discord / signed JSON, free |
Field Agent (dms wraps the command, reports exit status + output) | && curl suffix β success-only check-in, but no output capture (their genuine win) |
| Snitch history dashboard | Public status page + badge + Atom feed per heartbeat; GET β¦?secret= for recent evaluations |
# crontab: run backup at 03:00, check in only on success
0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 https://mockbird.mockbird.workers.dev/ping/p-XXXX
The && means a crashing job doesn't check in β so one line covers the job failing, the job never starting, and the machine being gone entirely. The same line works in a systemd timer's ExecStartPost, a GitHub Actions scheduled workflow's last step, or at the end of an agent's recurring task. When the pings stop arriving within period_minutes + grace (default: half the period, clamped 5mβ24h), your webhook gets one service.down event; when they resume, one service.up. No nagging. Formats are sniffed from the URL β hooks.slack.com gets {"text": β¦}, Discord gets {"content": β¦}, anything else gets JSON signed with your secret (x-mockbird-signature, verification snippet here).
Every heartbeat gets a public, unguessable-URL status page (/status/hb-β¦), a live README badge (/status/hb-β¦/badge.svg), and an Atom feed of missed/resumed events. The ping URL is a separate secret from the page URL β embed the badge in a public README and nobody who sees it can fake a check-in. Dead Man's Snitch keeps snitch state inside the dashboard; here "is the nightly backup alive?" is a link you can hand to anyone.
Facts checked September 2026 against each vendor's own pricing pages β verify current numbers yourself:
| Free tier | Pick it when | |
|---|---|---|
| Dead Man's Snitch | 1 snitch, account required; $5/mo β 3 snitches; integrations from $19/mo; smart alerts/error notices at $49/mo | You want Field Agent's exit-status + output capture in the alert, or you want their first-class Heroku Scheduler monitoring. |
| healthchecks.io | 20 checks, cron-expression schedules, ~1-min granularity, many integrations; open source, self-hostable | You're monitoring a fleet and want a dashboard + log history β the generous-free-tier default (our page on it). |
| Cronitor | 5 monitors free | Cron monitoring plus performance metrics in one commercial tool (our Cronitor page). |
| Mockbird heartbeat | No account: 5 live heartbeats/IP (deleting frees the slot), 100 total, periods 30 minβ7 days, webhook alerts + public status page/badge/feed | You want the switch armed this minute with one curl β or a script/CI job/agent is arming it for itself. |
Where Dead Man's Snitch wins, plainly: Field Agent's output/exit-status capture (an alert that says what broke beats an alert that says "went quiet"), email alerts without any webhook setup, smart alerts and error notices on higher plans, first-class Heroku Scheduler support, a browsable per-snitch history, and fourteen years of production trust. We do: one curl, no account, webhooks free from the first dollar you don't spend, a public status page + badge + feed, and periods anywhere from 30 minutes to 7 days rather than fixed interval tiers.
# info + ping URL + recent evaluations
curl "https://mockbird.mockbird.workers.dev/api/status/heartbeat/hb-XXXX?secret=YOUR_SECRET"
# disarm
curl -X DELETE "https://mockbird.mockbird.workers.dev/api/status/heartbeat/hb-XXXX?secret=YOUR_SECRET"
The endpoint is self-documenting β GET /api/status/heartbeat returns full usage as JSON. If what you want to watch is a URL rather than a job, the same alert machinery does classic uptime monitoring: see the uptime-monitoring guide.
period_minutes 30β10080 (evaluation runs every 30 minutes β this is for jobs on human schedules, not sub-minute liveness), grace defaults to period/2 (5mβ24h), 5 live heartbeats per IP (deleting one frees the slot immediately), 100 total (small free capacity β if you hit the cap, try later), best-effort webhook delivery, 5 consecutive failed deliveries auto-remove the heartbeat.