How to Use Healthchecks: The Beginner's Guide (First Check, the Period-vs-Grace Lesson, the Ping Pattern, and the Notifications Rule)

CodexFuse Team · 2026-11-01T04:39:52.969Z · 14 min read

Healthchecks.io is the open-source dead man's switch for cron jobs: your job pings a URL on success, and Healthchecks alerts only when a ping fails to arrive. This beginner's guide covers your first check, period vs grace, the ping pattern, curl-in-cron recipes, 29 notification channels, and Docker self-hosting.

Learning how to use Healthchecks is the fastest way to stop waking up to a backup that silently failed three weeks ago. Healthchecks.io is a dead man's switch for your cron jobs and scheduled scripts: your job sends a tiny HTTP ping when it finishes, and Healthchecks raises the alarm only when a ping fails to arrive on time. This healthchecks.io tutorial for beginners runs the complete first arc in one guide: your healthchecks.io first check, the period-vs-grace lesson (the one that kills false alarms), the ping pattern (success, /start, /fail, exit codes), curl-in-cron recipes, notifications across 29 channels, and self-hosting with Docker. If containers are new to you, read our Docker beginner guide first — the self-host path below assumes you can run a compose file.

What Is Healthchecks.io?

Healthchecks.io is a cron-job monitoring service built around one idea: instead of watching your servers, it waits for your jobs to check in. Every scheduled task gets its own check with a unique ping URL; when the job finishes, it sends an HTTP request to that URL. If the next ping does not arrive within the check's period plus grace time, Healthchecks sends you an alert. Think of this page as healthchecks.io for beginners: it exists in two flavors — the hosted SaaS at healthchecks.io (free for up to 20 checks) and a self-hosted open-source app — the healthchecks/healthchecks project on GitHub, roughly 10,485 stars, with v5.0.3 released October 27, 2026.

How Do You Use Healthchecks? The 10-Step First Arc

Here is the complete beginner path this guide builds, step by step:

  1. Sign up at healthchecks.io (or decide to self-host — the Docker path is near the end).
  2. Add your first check with the Add Check button and give it a name like "Nightly DB backup".
  3. Set the period to match how often the job should run (daily backup = 1 day).
  4. Set the grace to cover the job's runtime — grace covers the finish, not just the schedule.
  5. Copy the ping URL and treat it like a password — it is one.
  6. Wire the success ping into your cron line with curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/<your-uuid>.
  7. Add /start and /fail pings once the basic heartbeat works.
  8. Run the job once and watch the check flip from "new" to "up" in the dashboard.
  9. Turn on a notification channel (email first, then Slack/Discord/PagerDuty).
  10. Test the alarm by pausing the job once — if you do not get the alert, your monitoring is decoration.

What Is a "Dead Man's Switch" in Cron Monitoring?

A dead man's switch assumes silence means trouble. Traditional monitoring asks "is the server up right now?" — but cron jobs fail differently: the server is fine, the schedule ran, and the backup script crashed on line 12 before writing anything. Nobody notices until the disk dies. Healthchecks flips the question to "did the job report success on time?" — if the check-in never arrives, something broke. This is the opposite direction from outside-in uptime monitors: Uptime Kuma (our queued sibling, opposite lane) pings your services from the outside, while Healthchecks waits for your jobs to ping it back. Cronitor is the closest SaaS cousin, but it stays a comparison member here, never its own page. This direction is why Healthchecks catches the silent failures that uptime monitors never see.

How Do You Create Your First Check?

On the hosted service, click Add Check, name it after the job ("Nightly DB backup", not "Check 1"), and choose the check kind. A healthchecks.io first check takes about two minutes: simple checks use a timeout — they expect a ping every period. Cron checks use a real cron schedule plus a timezone, which is the right choice when your job runs at 2 AM on weekdays. The dashboard then shows the check as "new" — it turns "up" after the first successful ping, sits in "grace" while it waits past the due time, and flips to "down" when grace expires. Before you self-host anything, you need a place to run it: see our guide to what is VPS hosting if you have not chosen a server yet. Defaults matter here: period defaults to 1 day (86,400 seconds) and grace defaults to 1 hour (3,600 seconds), with both adjustable from 60 seconds to 365 days.

What Is the Difference Between Period and Grace?

Period is how often the job should run; grace is how long Healthchecks waits past the due time before declaring the job down. Getting the healthchecks.io period grace time math right is the whole game: the number-one source of false alarms is setting grace from the schedule instead of the job's runtime. The official docs spell out the rule: "Set Grace Time to be above the expected duration of your cron job." If your backup starts at 2:00 AM and takes 25 minutes, a 1-hour grace means the alert fires only if no ping arrives by 3:00 AM. This table makes the decision mechanical:

Job patternPeriodGrace (must cover the finish)Why
Nightly backup, runs 20 min1 day1 hourBackup sometimes runs 40 min on full moons of data
Hourly sync, runs 2 min1 hour15 minutesShort jobs get short grace; silence is meaningful faster
Weekly report, runs 90 min1 week3 hoursLong report jobs need generous grace or every run pages you
Every-5-min heartbeat, runs 10 sec5 minutes5 minutes (minimum)Heartbeats get the 60-second floor; any gap is real

Notice the last row: grace has a 60-second floor, so sub-minute heartbeats cannot tighten below it. When in doubt, make grace generous — a late alert beats a 3 AM page for a job that was simply slow. Every alert you ignore trains you to ignore the real one.

What Is the Healthchecks Ping Pattern?

The ping pattern is three URLs per check: a success ping, an optional /start ping, and an optional /fail ping. Start every job with the success ping alone; add the other two once the heartbeat is reliable. The hosted ping base is https://hc-ping.com/<uuid>, while a self-hosted instance uses https://YOUR_DOMAIN/ping/<uuid>. Here is the full curl recipe set, straight from the official docs:

SignalCommandWhat it means
Successcurl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/<uuid>Job finished cleanly — resets the timer
Startcurl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/<uuid>/startJob began — Healthchecks now measures run time
Failcurl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/<uuid>/failJob failed explicitly — alert immediately, do not wait for grace
Exit codecurl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/<uuid>/$?Records the script's real exit code — zero means success

The curl flags are doing real work: -f fails on HTTP errors, -sS silences progress but shows errors, -m 10 caps the attempt at 10 seconds, --retry 5 retries transient network failures, and -o /dev/null discards the response body. Do not simplify this to a bare curl — a hung ping is indistinguishable from a dead job. Two limits to know: the pinging API accepts HEAD, GET, or POST, and stores the first 100 kB of any request body; and more than 5 pings per minute to one check may be dropped, so do not put a success ping inside a tight loop.

How Do You Add a Healthchecks Ping to a Cron Job?

You chain the ping onto the job so it fires only when the job actually succeeds. This is the canonical pattern from the official docs:

8 6 * * * /home/me/backup.sh && curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid-here

The && is the exit-code discipline in one character: the ping runs only if backup.sh exits zero. If the script fails, no success ping is sent, and Healthchecks raises the alarm when period plus grace expires. For jobs where you want the failure signaled instantly instead of waiting out grace, add the /fail branch:

8 6 * * * /home/me/backup.sh && curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid-here || curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid-here/fail

Long jobs deserve the /start ping too: it lets Healthchecks measure run time and show "job started X minutes ago, still running" instead of silence. If you use systemd timers instead of cron, the same curl lines go into the ExecStartPost= of the service unit — the pattern is transport-agnostic, only the scheduler changes.

How Do Healthchecks Notifications Work?

The healthchecks.io notifications model is state-change driven: notifications fire on up-to-down, down-to-up, and the weekly/monthly report digests. You attach channels per project, and each check inherits its project's channels — set up the project once, and every check you add later is already covered. The channel list is long: 29 integrations including email, Slack, Discord, Telegram, Signal, WhatsApp, ntfy, Gotify, Matrix, Mattermost, Microsoft Teams, PagerDuty, Opsgenie, Splunk On-Call (VictorOps), PagerTree, Spike, Pushbullet, Pushover, GitHub, Google Chat, Rocket.Chat, Trello, Zulip, phone calls, SMS, webhooks, and Apprise — Apprise being the meta-channel that fans one alert out to dozens more services. Three rules keep notifications useful: start with email (it is free and always works), add one loud channel for real pages (PagerDuty or a phone call), and never route "check recovered" messages to the loud channel — recovery spam is how teams start muting everything. Note the quotas: SMS, WhatsApp, and phone-call alerts carry monthly limits on hosted accounts, while email supports hourly and daily reminders plus weekly and monthly reports.

How Do You Self-Host Healthchecks with Docker?

The healthchecks.io self hosted path is Docker-first. Self-hosting is a compose file and five environment variables. Copy docker/.env.example to docker/.env, set ALLOWED_HOSTS, DEFAULT_FROM_EMAIL, EMAIL_HOST (plus user and password), a random SECRET_KEY, and SITE_ROOT (for example https://hc.example.org), then run docker compose up and open port 8000. The healthchecks.io Docker image is healthchecks/healthchecks (tags latest and v5.0.3, published October 27, 2026, for amd64 and arm64), it runs database migrations on startup, and it ships PostgreSQL and MySQL drivers plus the Apprise library preinstalled. So the healthchecks.io install story has two halves: the SaaS sign-up for instant monitoring, and this compose file for full control. Two gotchas from real deployments: first, the database defaults to SQLite, which is fine for a personal instance — switch with the DB env var (postgres, mysql, or mariadb) when you outgrow it. Second, the SUPERUSER_EMAIL and SUPERUSER_PASSWORD variables do nothing on the official image — create your admin account with docker compose run web /opt/healthchecks/manage.py createsuperuser (those variables only work on the third-party linuxserver image). Two more for production: the image does no TLS termination, so put it behind a reverse proxy and set X-Forwarded-Proto; and the sample ships REGISTRATION_OPEN=True — flip it to false on any internet-facing instance or strangers will register on your monitor.

Healthchecks vs Uptime Kuma vs Cronitor: Which Fits?

These three look similar and solve different problems. Pick by monitoring direction:

HealthchecksUptime KumaCronitor
DirectionInside-out: jobs ping itOutside-in: it pings servicesInside-out: jobs ping it
Best forCron jobs, backups, scheduled scriptsWebsites, APIs, ports, certificatesCron jobs with a polished SaaS UI
Self-hostYes — official Docker imageYes — single containerNo
Free tier20 checks on hosted SaaSUnlimited, self-hosted onlyLimited free tier
Needs both?Yes, usually — Uptime Kuma proves the server is reachable; Healthchecks proves the 2 AM backup actually ran. They cover each other's blind spots.

The draw-the-line rule: if nothing runs on a schedule, you need Uptime Kuma, not Healthchecks. If your question is "did the page change?" rather than "did the job run?", that is our Changedetection.io beginner guide — a different monitoring lane entirely, never a rival. The healthchecks.io vs Cronitor question comes down to SaaS polish versus self-host control: Cronitor is the managed-service alternative, but for open-source self-hosters, Healthchecks is the lane.

How Do You Keep Your Ping URLs Secret?

A ping URL is a credential: the UUID in it is the entire authentication, and anyone holding it can fake your jobs' health. Never commit ping URLs to git, never paste them into tickets or chat logs, and never let them appear in process listings — put the URL in an environment variable or a secrets file and reference it from your cron line. Serve everything over HTTPS so the URL cannot be sniffed in transit. If a URL leaks, rotate it: generate a new UUID for the check and update the job. For human-friendly URLs, Healthchecks supports slug URLs (https://hc-ping.com/<ping-key>/<slug>) so your cron lines read nightly-db-backup instead of a UUID — same secrecy rules apply.

Why Is My Check Alerting When the Job Ran Fine?

Almost always, one of three things. First, grace is shorter than the job: the job ran fine but took 70 minutes with a 60-minute grace — raise grace above the job's worst-case duration, not its average. Second, the ping never left the machine: a firewall rule, a proxy, or a DNS outage between your server and hc-ping.com — add --retry 5 (already in the recipes above) and check the job's own logs for curl errors. Third, the cron schedule and the check's schedule disagree: you moved the job from 2 AM to 3 AM but left the cron-kind check at the old schedule, so it waits for a ping that was never due. The debugging order is always the same: check the job's logs first, then the check's ping log in the dashboard (it shows every received ping with timestamps), then the period/grace math. A check with a clean ping log and correct math does not false-alarm.

Sources

  • Healthchecks official docs — "Monitoring Cron Jobs" (the canonical curl ping pattern, grace-time rule: "Set Grace Time to be above the expected duration of your cron job"): healthchecks.io
  • Healthchecks official docs — "Measuring Script Run Time" (/start, /fail, /exit-code ping semantics): healthchecks.io
  • Healthchecks official docs — "HTTP API" (HEAD/GET/POST accepted, first 100 kB of body stored, 5 pings/min rate guidance): healthchecks.io
  • Healthchecks official docs — Management API v3 (timeout default 86400s, grace default 3600s, 60s–365d range, 20 free checks): healthchecks.io
  • Healthchecks official docs — "Running with Docker" (docker/.env.example flow, createsuperuser command, Apprise preinstalled, no TLS termination, gunicorn from v5.0): healthchecks.io
  • Healthchecks official docs — "Configuring Notifications" (SMS/WhatsApp/phone quotas, email reminders, weekly/monthly reports): healthchecks.io
  • GitHub API — healthchecks/healthchecks releases (v5.0.3 published 2026-10-27, ~10,485 stars): api.github.com
  • GitHub raw — hc/api/models.py (DEFAULT_TIMEOUT = 1 day, DEFAULT_GRACE = 1 hour): raw.githubusercontent.com
  • GitHub raw — hc/api/migrations/0123_alter_channel_kind.py (29 notification channels, Feb 2026): raw.githubusercontent.com
  • GitHub raw — docker/.env.example (no SUPERUSER_EMAIL/SUPERUSER_PASSWORD entries; REGISTRATION_OPEN=True; PING_ENDPOINT): raw.githubusercontent.com
  • Docker Hub API — healthchecks/healthchecks tags (latest + v5.0.3, 2026-10-27): hub.docker.com
  • Healthchecks blog — "New Feature: Slug URLs" (UUID is the auth, rotate on leak, slug URL format): blog.healthchecks.io
  • dev.to/serverkueche — "Healthchecks: Monitor Cron Jobs, Backups & Dead Man's Switch" (Oct 2026, self-hosted v4.4 behind Traefik, createsuperuser flow): dev.to
  • spike.sh blog — "Introduction to Cron Job Monitoring with Healthchecks" (updated 2026-07-29, beginner how-to arc): spike.sh
  • runwisp.com — two-layer cron alerting with Healthchecks (Oct 2026, exit-code ping pattern): runwisp.com

Frequently Asked Questions

Is Healthchecks.io free?

Yes, for most personal use. The hosted service gives you 20 checks per account for free, which covers a homelab's backups, syncs, and certificate renewals comfortably. The self-hosted version is fully open source and free with no check limit — you pay only for the server it runs on.

What is the difference between period and grace in Healthchecks?

Period is how often your job should check in (for example, 1 day for a nightly backup); grace is how long Healthchecks waits past the due time before alerting (default 1 hour). The critical rule: set grace above the job's expected duration, not from its schedule — grace covers the job's finish, and most false alarms come from grace being shorter than a slow run.

Can I self-host Healthchecks?

Yes. The official Docker image (healthchecks/healthchecks) needs a compose file with five environment variables — ALLOWED_HOSTS, DEFAULT_FROM_EMAIL, EMAIL_HOST, SECRET_KEY, and SITE_ROOT — then an admin account created with docker compose run web /opt/healthchecks/manage.py createsuperuser. Put it behind a reverse proxy for TLS, and close registration on internet-facing instances. SQLite is the default database; PostgreSQL or MySQL via the DB variable for larger setups.

What is the difference between Healthchecks and Uptime Kuma?

Direction. Uptime Kuma is outside-in monitoring: it pings your websites, APIs, and ports from the outside. Healthchecks is inside-out: your cron jobs and scripts ping it when they finish. A server can be perfectly reachable while its 2 AM backup silently fails — that is the failure Healthchecks catches and Uptime Kuma cannot. Most setups run both.

What happens if someone finds my ping URL?

They can fake your job's health by pinging it themselves, since the UUID is the entire authentication. Rotate the check's UUID immediately, update the job's cron line, and treat the new URL like a password: environment variables, never git, HTTPS only. Slug URLs make the URLs readable but do not make them less secret.

Featured on Twelve Tools Launch Llama Tools Launch your MCP