Back to blog

Guides · Dec 8, 2025

Healthchecks.io and Crontap: pair them or replace one?

Topics:Monitoring
Crontap now has native heartbeats. Healthchecks.io still offers deeper lifecycle signals and an independent failure domain. Here is how to choose one or run both.
crontap.com / blog
Crontap now has native heartbeats. Compare Crontap alone, Healthchecks.io alone, and both together when the scheduler and watcher must stay independent.

Updated September 2026: Crontap now ships native heartbeats. You no longer need two tools for period plus grace, /fail, connected notification channels, generic webhook Integrations, and 90-day heartbeat history. The two-vendor setup in this guide remains useful when the scheduler and the alerter must fail independently.

You set up a weekly sales report on Crontap. Every Monday at 5am Europe/London, the schedule fires the work and the report reaches your manager before their first coffee. One Monday, the email does not arrive. There may be a loud failure, such as a 500, or a silent one where the job never starts. Heartbeats cover the silent case by expecting the job to phone home.

Crontap can now hold that heartbeat itself. Healthchecks.io remains a mature specialist with self-hosting, cron-expression expectations, /start plus duration, /fail, and log signals. This guide helps you choose Crontap alone, Healthchecks alone, or both, then keeps the original pairing walkthrough for teams that want operational separation.

You no longer need two tools for this

The native setup takes three steps:

  1. Open Crontap Heartbeats and create a heartbeat with the job's expected period and grace.
  2. Put the secret ping URL at the end of the job's success path.
  3. Send /fail when the job knows it failed.

For the weekly report, choose a seven-day period and 30-minute grace. If no success ping arrives by 5:30am the following Monday, Crontap detects the miss within one minute after grace. Notification delivery follows asynchronously through connected email, Slack, Discord, or Telegram channels. Generic JSON webhooks remain separate Integrations.

/path/to/weekly-report.sh
status=$?
ping_url="https://ping.crontap.com/YOUR-TOKEN"
[ "$status" -eq 0 ] || ping_url="$ping_url/fail"
curl -fsS -m 10 --retry 3 "$ping_url" > /dev/null
exit "$status"

Use native Notification channels for human alerts. Keep a generic webhook Integration when another machine should process the event.

Healthchecks alone, Crontap alone, or both

SetupRuns the jobHeartbeat modelBest fit
Healthchecks.io aloneNoPeriod or cron expectation, grace, /start, duration, /fail, logsYou already trust your scheduler, need deeper lifecycle signals, or want self-hosting
Crontap aloneYes, for HTTP cronPeriod plus grace, success, /fail, connected alert channels, 90-day historyYou want schedules, uptime, and heartbeats in one product
BothCrontap runs HTTP cronEither or both services receive the job's pingThe scheduler and alerter must live in separate failure domains

Crontap Heartbeats v1 does not support /start, duration tracking, or cron-expression expectations. Those are meaningful reasons to keep Healthchecks.io, not footnotes to hide.

The independent-watcher pattern

The setup has two systems. The first is your normal Crontap schedule. The second is a Healthchecks.io check that listens for a heartbeat from the job's success path.

Crontap (Mon 05:00 Europe/London)  →  HTTPS  →  your job runs  →  curl https://hc-ping.com/<uuid>


                                                          Healthchecks.io (expects a ping every 7 days)


                                                  If no ping in 7 days + 30min: page on-call

The contract:

  • Crontap holds the clock.
  • Your job holds the work and pings on success.
  • Healthchecks.io holds the absence detector.

If the job runs and pings, both systems are happy. If the HTTP call fails, the Crontap schedule alerts after its retries. If the job does not run at all, Healthchecks alerts independently. You can also send /fail to either heartbeat receiver for a known failure.

Setup: create the Healthchecks.io check

Healthchecks.io is the canonical hosted dead-man service. It has a free tier (20 checks at the time of writing; see the pricing page). The setup is a few minutes.

  1. Sign up at healthchecks.io (free tier, no credit card).
  2. Click Add Check. Give it a name that matches the schedule ("weekly-sales-report").
  3. Set the Schedule type. Two options:
    • Simple. Period 7 days, grace 30 minutes. Use this for the weekly report case.
    • Cron. Paste the cron expression 0 5 * * 1, set the timezone to Europe/London, set the grace window. Use this if your cadence is irregular (every weekday but not weekends, last day of the month, and so on).
  4. Save the check. Healthchecks generates a ping URL like https://hc-ping.com/<uuid>. Copy it.

That is the independent dead-man side done. The check now expects a ping at the cadence you specified, and will page you (via email, Slack, Discord, Telegram, PagerDuty, OpsGenie, webhooks, or the other integrations Healthchecks supports) if no ping arrives in the window.

For the worked example below, Healthchecks is configured to expect a ping by 5:30am Monday in Europe/London. If 5:30am rolls around with no ping, the on-call rotation gets a Slack alert and an email.

Add the ping to the end of your job

The ping is a one-line curl at the end of the success path. The placement matters: the ping should fire only if the job actually completed the work.

For the WordPress weekly sales report case, drop it in the plugin or the cron handler:

function my_weekly_sales_report() {
  $report = generate_sales_report();
  if (! send_report_email($report)) {
    error_log('Failed to send sales report');
    return; // do not ping on failure
  }
  wp_remote_get('https://hc-ping.com/<uuid>', ['blocking' => false]);
}

For a bash cron handler the equivalent is generate-and-send-report.sh && curl -fsS https://hc-ping.com/<uuid>. The && matters: if the report script fails, the ping is not sent, Healthchecks does not see a heartbeat, and the alert fires. Healthchecks also supports /start and /fail endpoints for richer reporting; Crontap's built-in alerts cover the failure case, so you usually do not need them. See the Healthchecks docs for details.

Setup: create the Crontap schedule

Head to Crontap and create the schedule the same way you would for any other job.

  1. URL. The work URL: for the WordPress case, https://yoursite.com/wp-cron.php?doing_wp_cron=1; for a Node backend, https://api.yourapp.com/jobs/weekly-report.
  2. Method. GET for wp-cron, POST for a custom backend route.
  3. Headers. If your endpoint has a bearer (it should, for non-WordPress), set Authorization: Bearer <secret>.
  4. Cadence. "Every Monday at 5:00am" or 0 5 * * 1. Crontap previews the next 5 fires inline.
  5. Timezone. Europe/London. Crontap stores timezone per schedule and handles DST automatically.
  6. Failure alerts. Add email, Slack, Discord, Telegram, or a generic webhook integration. If the final attempt fails after any configured retries, the failed wp-cron tick or report endpoint lands in your channel. Healthchecks still covers the separate case where Crontap itself cannot deliver the run or alert.

Press Perform test to confirm the URL works and the response is what you expect. The first real fire is whichever Monday at 5:00am rolls around next.

Fix this in 60 seconds with Crontap. Free forever tier. No credit card. Schedule your first job →

That is both systems wired up. From here, every Monday at 5am: Crontap fires, the job runs, the job pings Healthchecks, and both stay green. If anything breaks the chain, the alert source tells you which part lost contact.

Worked example: a UK restaurant on WordPress sending a weekly sales report

Take a UK restaurant on WordPress sending a weekly sales report at 5am Monday in Europe/London. WordPress runs a custom reporting plugin that queries the WooCommerce orders table for the previous week, formats a summary, and emails it to the manager. wp-cron is disabled (the WordPress Plugin Handbook explains why; the sibling post replace WordPress wp-cron with a real scheduler walks through the full setup). Crontap fires https://restaurant.example.co.uk/wp-cron.php?doing_wp_cron=1 every Monday at 5:00am Europe/London. The reporting plugin pings https://hc-ping.com/<uuid> at the end of its success path. Healthchecks expects a ping every 7 days with a 30-minute grace.

Four scenarios:

  1. Happy Monday. Crontap fires at 05:00:00. WordPress runs the plugin. The report is emailed. The plugin pings Healthchecks. The manager reads it at 06:30 with their espresso. Both monitors stay green.
  2. The report endpoint returned 500. The plugin threw an exception (the WooCommerce table had a stuck migration). Crontap retries automatically with exponential backoff, then alerts if the retries are used up. The SRE fixes the migration, next week is green. Healthchecks does not alert (absence is shorter than the 7-day window).
  3. The Crontap schedule was paused. A teammate "tidied up" last Tuesday and paused the weekly report. By 5:30am Monday, the native Crontap heartbeat and the independent Healthchecks check can both detect that no ping arrived. The team finds the paused schedule, unpauses it, and runs the report manually.
  4. Crontap outage at exactly 05:00 Monday. Rare, but possible. By 5:30am, Healthchecks has not seen a ping; the alert lands. The team waits 15 minutes, sees Crontap come back, fires the schedule manually for that missed Monday, the report goes out at 5:55am.

In scenario 3, a native Crontap heartbeat is enough to catch the missing run. Scenario 4 is why some teams pay the complexity cost of an independent watcher: Healthchecks can alert even when the scheduler vendor is unavailable.

Why this is a different failure mode from Crontap's failure alerts

There is a tendency to look at this and ask "is this not redundant?" It is not. The two alert types catch genuinely different things:

Failure modeWhat is brokenWho alerts
Job ran, returned 5xxThe work logicCrontap (4xx/5xx alert)
Job ran, returned 4xxThe auth, the URL, the request shapeCrontap (4xx/5xx alert)
Job timed outThe downstream is slow or stuckCrontap (timeout alert)
Job did not run (paused)The schedule itselfCrontap Heartbeat or Healthchecks
Job did not run (deleted)The schedule itselfCrontap Heartbeat or Healthchecks
Job did not run (Crontap outage)The scheduler serviceHealthchecks (dead-man)
Job did not run (account suspended)The scheduler accountHealthchecks (dead-man)

The split is now a choice. Crontap can run the HTTP job and monitor its heartbeat. Healthchecks can own the heartbeat separately when vendor independence matters.

For workloads where the schedule itself is critical (customer-facing reports, regulatory exports, end-of-day rollups), this split is what teams reach for. For low-stakes background work where a missed week is fine, Crontap's alerts alone are usually plenty.

Pricing: how much does the pair cost

Both products have free tiers, and for most small-to-medium teams the combination stays free or close to free.

  • Crontap. Starter includes 2 combined schedules, uptime monitors, and heartbeats. One heartbeat can run hourly or slower. Pro starts at $2.99/mo and unlocks one-minute heartbeat periods plus a higher combined cap.
  • Healthchecks.io. Free tier covers 20 checks (see the pricing page). Paid tiers add more checks and team features.

For the weekly-sales-report case, both halves are free. Even a team running 20 critical schedules can usually fit them all into Crontap Pro (Pro 20 is $7.99/mo) plus the Healthchecks free tier, for the on-time guarantee plus the dead-man coverage.

When to use one heartbeat receiver

Not every Crontap schedule warrants two heartbeat receivers. Use only the native heartbeat for hobby projects, background work that catches up on the next fire, and ordinary production jobs where one dashboard is a reasonable operational trade-off.

Pair Crontap and Healthchecks for customer-facing schedules where a scheduler-vendor outage must still page somebody, compliance or finance schedules with independent-control requirements, and regulated environments where the watcher must be operationally separate. Rule of thumb: if one vendor owning the clock and the alarm violates the risk model, pair them.

FAQ

Can I use Healthchecks alone instead of Crontap?

Healthchecks is a monitor, not a scheduler. It listens for pings; it does not fire requests. You need something to actually run the job (Crontap for HTTP cron with automatic retries with exponential backoff and IANA timezones, or system cron, or any other scheduler). Healthchecks complements; it does not replace.

Can I use Crontap's failure alerts alone, no Healthchecks?

Use a Crontap Heartbeat when "the run did not happen" matters. Add Healthchecks only when that watcher must remain independent from the Crontap scheduler or when you need its deeper lifecycle features.

What grace window should I set?

Slightly larger than the cadence period plus a comfortable margin. For a weekly report at 5am Monday, a 30-minute grace is standard. For an hourly cache rebuild, 5-10 minutes. For a per-minute health probe, 1-2 minutes. Too tight gives false positives; too loose makes the alert late.

Does the ping count against my Healthchecks rate limits?

The ping is a single GET to hc-ping.com. Healthchecks does not throttle pings on the free tier within reasonable cadence; the Healthchecks docs describe the per-second limits.

Where does the Healthchecks ping URL go for a WordPress job?

The UUID in the URL is the auth, so treat the ping URL like a bearer (do not commit it to a public repo, do not log it). For the WordPress case, store it as a constant in the plugin or in wp-config.php.

Does Healthchecks support timezones in the cron mode?

Yes. The "Cron" schedule type takes a cron expression and a timezone. Set them to match the Crontap schedule (0 5 * * 1 and Europe/London for the weekly report case) so both halves agree on the calendar.

References

Related on Crontap

From the blog

Read the blog

Guides, patterns and product updates.

Tutorials on scheduling API calls, webhooks and automations, plus deep dives into cron syntax, timezones and reliability.

Product Updates

Introducing AI Integrations

Transform a schedule's HTTP response with a plain-English prompt, return text or JSON, and forward it to Slack, Make, n8n, or your own endpoint. Test on any tier; saving is a Pro feature.

Alternatives

Vercel cron jobs: the Hobby once-per-day limit and how to beat it

Vercel Cron caps Hobby at one run per day, only guarantees timing within the hour, is UTC only, and ties every schedule change to a redeploy. Here is the external cron pattern teams use to ship per-minute, timezone-aware schedules and one dashboard across projects without paying $20/mo per user for Pro.