At a glance
tqdml run -- ./backup.shin the crontab line gives you each run's live output, exit code and a Runpeek alert when it fails or stalls.- Healthchecks.io gives you 20 free jobs, Better Stack 10, Cronitor 5, and Dead Man's Snitch and Sentry 1 each.
- Chain a
curlping with&&to report success only, or send/$?to Healthchecks.io to report the exit code. - Uptime Kuma is self-hosted, so run it on a different machine than the jobs it watches.
- Set
PATH, escape%as\%and log the output, or the job can fail before it reports anything.
Free tiers compared
Here is how the seven tools compare on their free limits, checked on each vendor's pricing page on October 30, 2026:
| Tool | Free tier | Hosting | How a job reports |
|---|---|---|---|
| Runpeek | Live links with no account; a free account adds 7-day history and 3 alert rules | Hosted | tqdml run -- <command> wraps the job |
| Healthchecks.io | 20 jobs, 100 log entries per job | Hosted, or self-host the open-source server | curl to hc-ping.com/<uuid> |
| Better Stack | 10 monitors and heartbeats, 1 status page, personal projects | Hosted | curl to a heartbeat URL |
| Cronitor | 5 monitors, email and Slack alerts | Hosted | curl to cronitor.link with state= |
| Dead Man's Snitch | 1 snitch | Hosted | curl to nosnch.in/<token> |
| Sentry Crons | 1 cron monitor | Hosted | sentry-cli monitors run |
| Uptime Kuma | No plan limits | Self-hosted | Push monitor URL |
Runpeek watches each run from the inside; the other six are heartbeat monitors that alert you when a scheduled ping is late. Healthchecks.io has the largest hosted free tier among them.
How cron job monitoring works
You can watch a cron job in two ways: wrap the command, or have it send a heartbeat. A wrapper such as Runpeek's tqdml run starts the job itself, so it sees every line of output and the exit code.
A heartbeat, also called a dead man's switch, is an HTTP request your job makes to a unique URL when it finishes. The service expects that ping every period plus a grace period and alerts you when one is missing.
If you chain the ping with &&, the request only fires when the script exits with 0, so a failed run turns into a missing ping once the grace period runs out. Healthchecks.io and Cronitor also take a start signal to measure duration and catch hung jobs, and a fail signal so you hear about a failure right away instead of waiting for the timer.
0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid
0 4 * * * curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid/start; /usr/local/bin/report.sh; curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid/$?The first line only pings if the backup succeeds. The second sends /start before the job and then /$?, which reports the exit code (0 is success, anything else is a failure) the moment the script finishes.
The 7 options
Runpeek
With tqdml run in the crontab line, each run streams its output and tqdm bars to a live link that keeps the last 500 lines (10,000 on Pro) and ends as Finished on exit code 0 or Failed on anything else. A free account keeps runs for 7 days and adds 3 alert rules.
Healthchecks.io
The $0 Hobbyist plan monitors 20 jobs and keeps 100 log entries per job. Jobs ping https://hc-ping.com/<uuid>, and the /start, /fail and /<exit-status> suffixes record run times and failures. SMS and WhatsApp credits start on the $20 Business plan with 100 jobs, and the server is open source (BSD 3-clause) if you'd rather host it yourself.
Better Stack
Better Stack is free for personal projects: 10 monitors and heartbeats, 1 status page, and Slack and email alerts. A heartbeat waits for a request to its secret URL at the frequency you set plus a grace period, and adding /fail to the URL reports a failure right away.
Cronitor
Cronitor's free plan covers 5 monitors with email and Slack alerts but no SMS. Jobs report with curl https://cronitor.link/p/<API_KEY>/<job-name>?state=complete, and state=run and state=fail mark starts and failures. Past 5 monitors you pay $2 per monitor and $5 per user each month.
Dead Man's Snitch
Dead Man's Snitch gives you 1 snitch for free, and the $5 plan has 3. You append && curl https://nosnch.in/<token> to the job, so the check-in only happens when the script exits cleanly. One snitch covers a single backup; a second job means paying.
Sentry Crons
Sentry includes 1 cron monitor on every plan, including the free Developer plan, and charges $0.78 for each extra one on paid plans. Instead of curl, you export your project's SENTRY_DSN and wrap the job with sentry-cli monitors run, which reports missed runs and runs that exceed their maximum runtime.
export SENTRY_DSN="your-project-dsn"
sentry-cli monitors run --schedule "0 3 * * *" nightly-backup -- /usr/local/bin/backup.shUptime Kuma
Uptime Kuma 2.5.8 (October 26, 2026) is open source and self-hosted, so there are no plan limits. Its Push monitor waits for your job to call a URL, next to HTTP, TCP, ping and DNS checks, and it alerts through Telegram, Discord, Slack, email and 90+ other services.
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2Keep it on a different machine than your cron jobs: if both share a box that dies, nothing sends the alert.
Cron mistakes that look like monitoring failures
Many silent failures happen before your script or its curl ever runs. Cron runs commands with /bin/sh, sets LOGNAME and HOME, and uses a short PATH (just /usr/bin:/bin on Debian 13), so a command that works in your terminal can fail with "command not found".
- Cron turns an unescaped
%into a newline and sends the rest to the command's stdin, so writedate +\%F. - Redirect output with
>> /path/job.log 2>&1, or setMAILTOto mail it to you (MAILTO=""turns mail off). - Wrap the command in
flock -n /tmp/job.lockso a slow run makes the next one exit instead of stacking up. - On Debian and Ubuntu,
journalctl -u cronshows whether cron started the job at all.
MAILTO=you@example.com
PATH=/usr/local/bin:/usr/bin:/bin
*/5 * * * * flock -n /tmp/sync.lock /opt/jobs/sync.sh >> /var/log/sync-$(date +\%F).log 2>&1How to choose
- Each run's live output, exit code and an alert when it fails or stalls: Runpeek, with
tqdml runin the crontab line. - A hosted heartbeat for a handful of jobs: Healthchecks.io for 20 jobs, or Better Stack for 10 monitors and a status page on a personal project.
- A team already on Sentry: Sentry Crons, at $0.78 per monitor past the first on a paid plan.
- No third-party service: Uptime Kuma's Push monitor on a separate machine.
FAQ
Can I monitor cron jobs for free?
Yes. Runpeek streams each run's output and exit code with no account, and a free account adds 3 alert rules. For heartbeat pings, Healthchecks.io monitors 20 jobs for free, Better Stack 10 for personal projects, Cronitor 5, and Dead Man's Snitch and Sentry 1 each. With a spare server, you can self-host Uptime Kuma or the open-source Healthchecks server.
What is the difference between a missed run and a failed run?
A missed run means no ping arrived before the schedule plus grace period ran out, because the server was down, cron stopped or the job hung. A failed run means the job ran and reported an error through a fail signal or a non-zero exit code.
Why does my script work in a terminal but fail in cron?
Cron runs commands with /bin/sh, a short PATH and few environment variables, and it turns any unescaped % into a newline. Use absolute paths or set PATH in the crontab, call bash explicitly if the script needs it, and write \% for percent signs.
Should I self-host a cron monitor?
You don't have to. Runpeek is hosted, so a tqdml run job only needs outbound HTTPS, and a stalled alert rule still fires if the server dies mid-run. Self-hosting Uptime Kuma or Healthchecks makes sense when you have more jobs than the free tiers allow and a second server in another location. Never run the monitor on the same machine as the jobs it watches, because a crash there takes the alerts down too.
Can Runpeek tell me if a cron job never started?
No. Runpeek learns about a run when tqdml run starts it, so a job that never starts, because cron stopped or the server was down, sends nothing. Add a heartbeat ping to Healthchecks.io, Cronitor or Uptime Kuma next to tqdml run to catch that.
Check on long runs from your phone
Change one import and every tqdm bar prints a link you can open on any device. Get a Discord or Slack message when the run finishes, fails or stalls.
pip install tqdm-liveSources
- Healthchecks.io pricing healthchecks.io
- Healthchecks.io: Pinging API healthchecks.io
- Cronitor pricing cronitor.io
- Cronitor: Telemetry API cronitor.io
- Better Stack pricing betterstack.com
- Dead Man's Snitch plans deadmanssnitch.com
- Sentry docs: Cron monitoring with the Sentry CLI docs.sentry.io
- Uptime Kuma on GitHub github.com
- crontab(5) man page man7.org