# UptimeRobot Heartbeat Monitoring for Cron Jobs: Limits and Plans

By Dan Ochoa · Published 2026-10-30 · Updated 2026-10-30
Canonical: https://cronradar.com/blog/uptimerobot-heartbeat-monitoring

> How UptimeRobot heartbeat monitors watch cron jobs: interval and grace limits, which paid plans include them, alerts, a wrapper, and how CronRadar differs.

**UptimeRobot monitors cron jobs with a Heartbeat monitor, also called a cron job monitor: the job sends a GET or POST request to the monitor's unique URL, and UptimeRobot marks the monitor down when no request arrives within the interval plus the grace period.** The interval is a duration from 1 minute to 31 days, not a cron expression, and the documented request carries no result, so a failed run shows up only as a missing request. Heartbeats aren't on the Free plan; the cheapest plan with them is Solo, at $13 a month billed monthly or $12 a month billed annually, for 10 monitors.

This guide covers UptimeRobot's hosted service and its v3 API, spec version 3.0 in the [published OpenAPI file](https://cdn.uptimerobot.com/api/openapi.yaml), as documented in its [help center](https://help.uptimerobot.com/en/) and on its [pricing page](https://uptimerobot.com/pricing/) (checked October 30, 2026). For why a job needs a heartbeat at all, see [the dead man's switch guide](https://cronradar.com/blog/cron-dead-mans-switch); for what uptime checks miss, see [cron monitoring vs uptime monitoring](https://cronradar.com/blog/cron-monitoring-vs-uptime-monitoring). The comparison at the end covers UptimeRobot's heartbeat feature only, not its uptime checks or status pages.

## How a Heartbeat Monitor Decides a Job Is Down

Create the monitor with **+ Add New Monitor** and the Heartbeat type, then set a Friendly Name, the interval, the grace period, and the alert contacts. UptimeRobot generates the monitor's unique URL when you create it ([quick setup guide](https://help.uptimerobot.com/en/articles/11358364-how-to-create-your-first-monitor-on-uptimerobot-quick-setup-guide)). The help center's examples use URLs of the form `https://heartbeat.uptimerobot.com/m794yyyyyyyy-xxxxxxxxxxxxxxx` ([sending requests](https://help.uptimerobot.com/en/articles/17662754-how-to-send-http-requests-to-a-heartbeat-monitor)), and the API returns the URL as `heartbeatUrl` ([openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)).

What the documentation says about requests and deadlines:

- **Methods.** UptimeRobot receives only GET and POST requests to the heartbeat URL ([monitor status troubleshooting](https://uptimerobot.com/help/monitor-status-is-wrong/)).
- **The deadline.** If a request doesn't arrive within the interval plus the grace period, the monitor goes down and you're alerted ([cron job monitoring](https://uptimerobot.com/cron-job-monitoring/)). The API describes the grace period as the time "to wait past the expected heartbeat before alerting" ([openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)).
- **A job that never reports.** The [quick setup guide](https://help.uptimerobot.com/en/articles/11358364-how-to-create-your-first-monitor-on-uptimerobot-quick-setup-guide) says a heartbeat monitor that receives no request is marked down, so a job that was never installed is caught too.
- **What it records.** Up or down status, the time of the last heartbeat, uptime percentage, and incident history ([cron job monitoring](https://uptimerobot.com/cron-job-monitoring/)). Run duration isn't on that list.

### The Request Carries No Result

The heartbeat documentation describes one kind of request: a GET or POST to the URL. It documents no parameter for reporting a failure, a start, or a message. A job therefore reports success by sending the request and failure by not sending it, and UptimeRobot learns of a failed run at the same moment it would learn of a run that never started: when the interval plus grace runs out. The alert can't say which of the two happened or include the job's exit code.

### Interval and Grace Limits

| Setting                          | Documented range                                                                   | Source                                                                                                                                                                                      |
| -------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Interval                         | 1 minute to 31 days; the API takes seconds, at most 2,678,400                      | [cron job monitoring](https://uptimerobot.com/cron-job-monitoring/), [openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)                                                           |
| Grace period                     | 0 to 86,400 seconds (24 hours) in the API                                          | [openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)                                                                                                                                |
| Notification delay (`threshold`) | Minutes to wait after the monitor goes down before notifying a contact; paid plans | [openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml), [recurring notifications](https://help.uptimerobot.com/en/articles/11361289-recurring-postponed-notifications-in-uptimerobot) |
| Repeat (`recurrence`)            | Repeat a contact's notification every N minutes; paid plans                        | [openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml), [recurring notifications](https://help.uptimerobot.com/en/articles/11361289-recurring-postponed-notifications-in-uptimerobot) |

## An Interval, Not a Cron Schedule

The help center tells you to match the crontab entry to the monitor: replace the 5 in `*/5` "with your monitor's interval in minutes" ([sending requests](https://help.uptimerobot.com/en/articles/17662754-how-to-send-http-requests-to-a-heartbeat-monitor)). The API's heartbeat create schema has `interval` and `gracePeriod` and no schedule field ([openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)). Interval plus grace has to exceed the longest normal gap between two requests from the job, and any slack beyond that is time a missed run goes unreported. What that means for common schedules:

- **Daily jobs: the period goes in the interval, the variation in the grace.** A backup that starts at 03:00, takes 10 to 40 minutes, and sends the request when it finishes has gaps of up to 24 hours 30 minutes between requests. An interval of 1,440 minutes (24 hours) with a 45-minute grace leaves 15 minutes of headroom. On a host whose clock follows daylight saving time, the night the clocks go back adds an hour, so use a grace of 1 hour 45 minutes there. [The Uptime Kuma guide](https://cronradar.com/blog/uptime-kuma-cron-monitoring) works through the same arithmetic for a single interval, and [the grace period guide](https://cronradar.com/blog/cron-grace-period) shows how to derive the numbers from measured runs.
- **Weekday-only and other irregular schedules** need an interval that covers their longest gap, such as the weekend, which delays the alert for a run missed on any weekday; [cron monitoring vs uptime monitoring](https://cronradar.com/blog/cron-monitoring-vs-uptime-monitoring) works through the `0 6 * * 1-5` case.
- **Monthly jobs** on the 1st have gaps of up to 31 days, which is the maximum interval, so only the grace is left to cover run time and start delay.
- **Quarterly and other jobs that run less often than monthly** don't fit: a quarter's gap of roughly 90 days is longer than the 31-day maximum interval plus the 24-hour maximum grace, so the monitor would go down between every pair of runs.

Leave the notification delay at 0 on heartbeat monitors. It's added to interval plus grace on every alert, and the grace already absorbs normal variation.

## Plans and Prices for Heartbeat Monitoring

The pricing page's feature comparison marks Heartbeat monitoring as not included on Free and included on Solo, Team, and Scale, and Enterprise includes everything in Scale ([pricing](https://uptimerobot.com/pricing/), checked October 30, 2026). A heartbeat is one of the monitor types ([quick setup guide](https://help.uptimerobot.com/en/articles/11358364-how-to-create-your-first-monitor-on-uptimerobot-quick-setup-guide)), and each plan's limit counts every monitor on the account ([downgrades](https://help.uptimerobot.com/en/articles/16160088-what-happens-when-you-downgrade-or-your-subscription-ends)), so heartbeats share the count with HTTP, keyword, ping, and other monitors.

| Plan       | Monitors | Heartbeats | Billed monthly, per month | Billed annually, per month |
| ---------- | -------- | ---------- | ------------------------- | -------------------------- |
| Free       | 50       | No         | $0                        | $0                         |
| Solo       | 10       | Yes        | $13                       | $12                        |
| Solo       | 50       | Yes        | $28                       | $24                        |
| Team       | 100      | Yes        | $39 or $46                | $33 or $39                 |
| Scale      | 200      | Yes        | $83 or $98                | $67 or $79                 |
| Scale      | 500      | Yes        | $193 or $228              | $162 or $192               |
| Enterprise | Custom   | Yes        | Quote                     | Quote                      |

Team and Scale prices changed between loads of the page on October 30, 2026: from the same US connection, some loads served the lower set of figures and others the higher, while Solo's prices were the same in every load. UptimeRobot's [pricing.md](https://uptimerobot.com/pricing.md) says its anonymous pricing endpoint is geo-banded and asks for prices to be checked against the live page before they're quoted, so check the page before you choose a plan. The page's annual totals follow whichever set it serves: $144 a year for Solo with 10 monitors, $396 or $468 for Team, and $804 or $948 for Scale with 200, and the page says annual billing saves about 15%. The page's feature comparison also lists other plan differences that affect heartbeats:

- **Notification channels.** Email, SMS, voice call, Email2SMS, the mobile app, and Google Chat, Discord, Pushover, Pushbullet, and Splunk on every plan; Slack, Mattermost, Telegram, and Microsoft Teams from Solo; webhook, Zapier, and PagerDuty from Team. The mobile app is one of the personal channels, sending push notifications ([notification channels](https://help.uptimerobot.com/en/articles/11360978-understanding-notification-channels-in-uptimerobot)). Solo includes 10 to 20 SMS or voice call credits, Team 30, and Scale 50 to 200, and credits don't renew with the plan.
- **Recurring and delayed notifications, and maintenance windows,** are on paid plans, so every plan that has heartbeats has them.
- **Seats.** The table lists no included login seats on Solo, 3 on Team, and 5 on Scale.
- **Data retention.** 12 months on Solo, 24 months on Team and Scale ([data retention](https://help.uptimerobot.com/en/articles/11360873-what-is-uptimerobot-data-retention-and-how-does-it-work-in-different-plans)).

## Notifications and Maintenance Windows

- **Contacts are assigned per monitor.** A contact that isn't assigned to a monitor gets no alerts from it; assign contacts one monitor at a time or with bulk actions. Each contact can receive Up and Down alerts, both on by default ([notification channels](https://help.uptimerobot.com/en/articles/11360978-understanding-notification-channels-in-uptimerobot)).
- **Delay and repeat are set per contact on each monitor,** in minutes: the delay is how long to wait after a failure before alerting, and the repeat is how often the alert recurs ([recurring notifications](https://help.uptimerobot.com/en/articles/11361289-recurring-postponed-notifications-in-uptimerobot)).
- **Alert storm protection** is a beta on paid plans and off by default. When the number of monitors that go down within a time window (5 minutes by default) reaches your threshold, it suppresses their individual Down notifications, sends one storm notification with the number of monitors affected and a link to the incidents, and cancels pending delayed and repeat notifications while the storm lasts ([alert storm protection](https://help.uptimerobot.com/en/articles/15433157-alert-storm-protection-in-uptimerobot)). With it on, a job that stops during a wider outage gets no Down notification of its own.
- **Maintenance windows treat heartbeats differently.** Most monitor types leave the window with the status they had going in. A heartbeat monitor that is already down when a window starts stays down for the whole window, even after its job resumes, and turns up only on the first check after the window ends; the help center's advice is to start the window before you stop the job. Windows follow the account's time zone, and checks run less often inside one ([maintenance windows](https://help.uptimerobot.com/en/articles/11360884-what-is-a-maintenance-window-and-how-to-use-it-in-uptimerobot)).

## A Cron Wrapper That Sends the Heartbeat

Set up the monitor first:

1. Create a Heartbeat monitor named after the job, with the interval and grace from the sizing above, and assign at least one alert contact.
2. Save the heartbeat URL in a file owned by the job's account with mode 600, here `/etc/uptimerobot/nightly-backup.url`. The help center's examples put the URL in the crontab line and send nothing else with it, so the URL alone marks the job as having run. Keep it out of crontabs and repositories.

The wrapper runs the job and sends the heartbeat only when the job succeeds:

```bash
#!/bin/sh
# /opt/backup-uptimerobot.sh: run the backup, then send the UptimeRobot heartbeat if it succeeded.
# The file holds the monitor's heartbeat URL and is readable only by this account.
heartbeat_url=$(cat /etc/uptimerobot/nightly-backup.url 2>/dev/null)

/opt/backup.sh
rc=$?

if [ "$rc" -eq 0 ] && [ -n "$heartbeat_url" ]; then
  curl --fail --silent --show-error --max-time 5 --output /dev/null \
    "$heartbeat_url" || true
fi
exit "$rc"
```

Schedule it with `0 3 * * * /opt/backup-uptimerobot.sh`. A request means success, so a non-zero exit sends nothing and the monitor goes down once interval plus grace pass. `--max-time 5` caps the request, `|| true` ignores a failed one, and the script exits with the backup's own code, so an unreachable UptimeRobot can't fail or stall the job; `--show-error` still writes a failed request to the job's stderr. The help center's curl example passes `--insecure`, which skips TLS certificate verification ([curl manual](https://curl.se/docs/manpage.html#-k)); this wrapper leaves verification on. [Cron shell script best practices](https://cronradar.com/blog/cron-shell-script-best-practices) covers keeping the job's exit code honest.

A hung run looks the same as a missed one: no request, then an alert when interval plus grace pass, while the hung process keeps running. To end a hung run at a time you choose, put a time limit around the job; [cron job timeouts](https://cronradar.com/blog/cron-job-timeout) covers GNU `timeout` and its exit codes.

### Creating Heartbeat Monitors Through the API

For many jobs, or an AI agent setting monitors up, the v3 API creates the same monitor. `POST /v3/monitors` with the heartbeat body requires `friendlyName`, `type`, and `interval`, takes `gracePeriod` optionally, both in seconds, and returns the monitor including `heartbeatUrl`; each entry in `assignedAlertContacts` needs `alertContactId`, `threshold`, and `recurrence`, and `GET /v3/user/alert-contacts` lists contacts with their `id` ([openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)). Requests send an API key, created in the dashboard's API section ([API help](https://help.uptimerobot.com/en/articles/11620152-how-to-use-uptimerobot-s-api)), as a bearer token ([openapi.yaml](https://cdn.uptimerobot.com/api/openapi.yaml)).

```bash
# UPTIMEROBOT_API_KEY comes from your secret store.
# 12345 stands for an alert contact id returned by GET /v3/user/alert-contacts.
curl --fail-with-body --silent --show-error \
  --request POST "https://api.uptimerobot.com/v3/monitors" \
  --header "Authorization: Bearer $UPTIMEROBOT_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "friendlyName": "nightly-backup",
    "type": "HEARTBEAT",
    "interval": 86400,
    "gracePeriod": 2700,
    "assignedAlertContacts": [
      { "alertContactId": 12345, "threshold": 0, "recurrence": 1440 }
    ]
  }'
```

That is the daily backup from the sizing above: a 24-hour interval, a 45-minute grace, no notification delay, and a repeat every 1,440 minutes (24 hours). Save the returned `heartbeatUrl` in the job's URL file. Each job is still its own create call and its own URL to distribute; the URL exists only once the monitor does, so a job can't register itself with its first request.

## UptimeRobot Heartbeats and CronRadar Compared

CronRadar is a hosted monitor for scheduled jobs only. UptimeRobot facts below were checked October 30, 2026.

|                       | UptimeRobot Heartbeat monitor                                                                                                                                                                 | CronRadar                                                                                               |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| When a report is due  | Interval, 1 minute to 31 days                                                                                                                                                                 | Five-field cron schedule in UTC; each check-in sets the next expected time from the schedule            |
| Slack before alerting | Grace, 0 to 86,400 seconds, plus any per-contact delay                                                                                                                                        | Grace period in seconds, 60 minimum: `warning` inside it, `critical` after                              |
| Signals from a job    | One GET or POST request                                                                                                                                                                       | Heartbeat, or `start`, `complete`, and `fail` with a `message` of up to 1,000 characters                |
| A failed run          | No documented failure signal; seen when interval plus grace pass                                                                                                                              | `fail` opens an incident immediately                                                                    |
| Run duration          | Not among the recorded metrics                                                                                                                                                                | Recorded from a `start` and `complete` pair                                                             |
| A hung run            | Seen as a missed request once interval plus grace pass                                                                                                                                        | Stuck: a `start` with no finish once the next expected run plus grace passes                            |
| Result checks         | None documented                                                                                                                                                                               | Up to five numeric or boolean outcomes checked on `complete`                                            |
| Creating monitors     | Dashboard or v3 API, then copy the URL into the job                                                                                                                                           | A check-in that carries `schedule`, the dashboard, or Hangfire and Quartz.NET discovery                 |
| Repeat alerts         | Per-contact repeat every N minutes                                                                                                                                                            | First alert, at most one reminder every 24 hours, and a recovery message; acknowledging stops reminders |
| Alert channels        | Email, SMS, voice, Email2SMS, mobile app, Discord, Google Chat, Pushover, Pushbullet, Splunk on all plans; Slack, Teams, Telegram, Mattermost from Solo; webhook, Zapier, PagerDuty from Team | Email, Slack, webhook, Discord, PagerDuty on every plan, Free included                                  |
| History               | 12 months on Solo, 24 on Team and Scale                                                                                                                                                       | Free: 30 days of runs, 90 days of alerts. Grow: 90 and 180 days                                         |
| Cheapest plan with it | Solo: 10 monitors, $13 a month, or $12 billed annually                                                                                                                                        | Free: up to 10 active monitors                                                                          |

### What Each Costs by Job Count

Monthly list prices before tax, assuming the UptimeRobot account has no other monitors and every CronRadar job is in one schedule class. These compare job counts, not equivalent products: UptimeRobot's monitors can also be uptime checks, and CronRadar doesn't charge per seat.

| Heartbeat jobs | UptimeRobot plan | UptimeRobot, monthly / annual billing | CronRadar, daily or hourly jobs (Standard) | CronRadar, every 5 to 59 minutes (Frequent) |
| -------------: | ---------------- | ------------------------------------: | -----------------------------------------: | ------------------------------------------: |
|             10 | Solo, 10         |                             $13 / $12 |                                         $0 |                                          $0 |
|             25 | Solo, 50         |                             $28 / $24 |                                      $7.50 |                                         $15 |
|             50 | Solo, 50         |                             $28 / $24 |                                        $20 |                                         $40 |
|            100 | Team             |               $39 or $46 / $33 or $39 |                                        $45 |                                         $90 |
|            200 | Scale, 200       |               $83 or $98 / $67 or $79 |                                        $95 |                                        $190 |
|            500 | Scale, 500       |           $193 or $228 / $162 or $192 |                                       $245 |                                        $490 |

Where a cell shows two UptimeRobot prices, the pricing page served both on October 30, 2026, as described in the plans section above. For daily or hourly jobs, CronRadar's list price is lower than UptimeRobot's on both billing periods up to 50 jobs. At 100 and 200 jobs it is lower only than UptimeRobot's higher monthly price: UptimeRobot's annual billing, and its lower monthly price, cost less. At 500, UptimeRobot is lower on both. For jobs every 5 to 59 minutes, UptimeRobot is lower from 50 jobs. Above 500 monitors UptimeRobot quotes Enterprise; CronRadar has no monitor limit.

The CronRadar figures are Grow list prices: the first 10 active monitors are free, fastest schedules first, and each further monitor costs $1 a month on a Frequent schedule (5 minutes to under an hour) or $0.50 on a Standard one (hourly or less often), billed in arrears on the month's peak ([pricing](https://cronradar.com/pricing)).

### The Same Backup Reporting to CronRadar

Shell scripts have no CronRadar SDK. The Node.js, Python, Celery, PHP, and Laravel SDKs are also unavailable, so those jobs report with HTTP check-ins too, and HTTP check-ins don't discover jobs automatically. [The Uptime Kuma guide](https://cronradar.com/blog/uptime-kuma-cron-monitoring#uptime-kuma-and-cronradar-compared) has the full CronRadar wrapper for this backup: it reads the API key from a file only the job's account can read, sends it with HTTP Basic auth as the username with an empty password, reports `start` before the backup and `complete` or `fail` after it, and keeps the same `--max-time 5` and `|| true` guards as the UptimeRobot wrapper above.

Two things differ from the UptimeRobot monitor. The failure is sent, with the exit code in its `message`, and alerts immediately instead of when interval plus grace run out. And the deadline follows the schedule rather than the last request, so the grace covers only the start: with `schedule=0 3 * * *` and `gracePeriod=900`, a missed run turns the monitor `critical` once 03:15 UTC passes, however long the previous run took, where the UptimeRobot monitor above needs a 45-minute grace to absorb the variation in the backup's run time. CronRadar reads the schedule in UTC; [schedule syntax](https://docs.cronradar.com/schedules) covers converting a local schedule and one difference from Linux cron when both day fields are restricted.

The same guide covers CronRadar's limits: stuck detection works per job rather than per run, and a monitor created by its first check-in can't flag a job that never runs unless you create it in the dashboard first. The .NET packages are the only installable SDKs (CronRadar 1.0.13, CronRadar.Hangfire 0.1.0, CronRadar.Quartz 0.1.0, checked September 20, 2026): CronRadar 1.0.13 can't send outcome values, and CronRadar.Hangfire 0.1.0 can report a failure before Hangfire finishes retrying. CronRadar has no SMS or voice call alerts, offers no contractual SLA, and publishes no availability figure.

### When UptimeRobot Heartbeats Fit

- **You already pay for UptimeRobot** and your plan has spare monitors: heartbeats share the notifications and dashboard you use for uptime checks.
- **Your jobs run on a fixed interval** between 1 minute and 31 days, such as every 15 minutes or every hour, so the job's period can be the monitor's interval.
- **You want SMS or voice call alerts** for a missed job, which CronRadar doesn't offer.
- **You run many jobs,** where UptimeRobot's list price in the table above is lower: from 50 jobs on schedules every 5 to 59 minutes, from 100 daily or hourly jobs on annual billing or at the lower monthly price the page sometimes shows, and at 500 daily or hourly jobs on either billing.

### When a Schedule-Aware Cron Monitor Fits

- **Schedules an interval can't express:** weekdays only, fixed times several times a day, or anything less frequent than monthly.
- **Failures should alert when they happen,** with the job's message, instead of when the interval runs out.
- **You want start and finish signals,** for stuck runs, checks on reported results, and run duration, which isn't among UptimeRobot's recorded heartbeat metrics.
- **Monitors should appear from a job's first check-in** or from Hangfire and Quartz.NET discovery rather than one form or API call per job.
- **You need webhook or PagerDuty alerts** for a handful of jobs without moving to Team.

[Cron monitoring tools compared](https://cronradar.com/comparisons/best-cron-monitoring-tools) puts hosted options side by side.

## Frequently Asked Questions

### Does UptimeRobot monitor cron jobs?

Yes, with a Heartbeat monitor, which the product pages also call a cron job monitor. The job sends a GET or POST request to the monitor's URL, and UptimeRobot marks it down when no request arrives within the interval plus the grace period.

### Is UptimeRobot heartbeat monitoring free?

No. The Free plan doesn't include heartbeat monitors. As of October 30, 2026, the cheapest plan with them is Solo: $13 a month billed monthly, or $12 a month billed annually, for 10 monitors of any type.

### What is the longest interval for an UptimeRobot heartbeat monitor?

31 days, which the API expresses as 2,678,400 seconds, plus a grace period of up to 86,400 seconds. Jobs with longer gaps between runs, such as quarterly ones, don't fit in one heartbeat monitor.

### Can a cron job report a failure to UptimeRobot?

Not through the documented heartbeat request, which is a GET or POST to the URL with no status or message. Skip the request when the job fails, and the monitor goes down once the interval plus grace pass.

### Can an UptimeRobot heartbeat monitor use a cron expression?

No. The monitor takes an interval and a grace period, and the help center tells you to set the crontab entry to match the interval. For a schedule such as weekdays at 06:00, the interval has to cover the longest gap, the weekend.
