A heartbeat check has five statuses. Understanding the transitions explains exactly when an alert arrives — and why sometimes it (correctly) doesn't.
| Status | Meaning | Alerts |
|---|---|---|
| new | the check exists, no ping has arrived yet | none |
| up | pings arrive on time | the up event on recovery after down |
| late | the deadline (+ up to 30 s of slack) was missed, the grace period is running | the late event (if enabled) |
| down | grace expired, or the job explicitly reported failure | the down event + reminders |
| paused | monitoring switched off manually | none |
A check in the new status is not tracked by the scheduler: it has no deadline yet — one appears only with the first ping. So you can create checks for future jobs in advance (or roll the config out with a deploy): until the code ships and pings, there are no false downs. The first successful ping flips the check to up and sets the first deadline.
The deadline is the moment the next ping is due. It is computed from the actual time of the last ping:
period_sec. The schedule "floats": a job that starts with drift does not accumulate error;
Grace is the allowance after the deadline — insurance against
schedule jitter and long runs: cron rarely fires to the second.
The check becomes late not at the very second of the
deadline but after a small slack —
deadline + min(grace, 30 s):
otherwise the minute-precision scheduler would outrun a ping
arriving a second behind schedule, and minute-level cron jobs
would blink up↔late. The slack never moves the down
moment — that stays at
deadline + grace_sec:
up ──(deadline + min(grace, 30 s))──▶ late ──(deadline + grace)──▶ down ▲ │ └──────────────── any successful ping ◀───────────────┘
With grace ≤ 30 s the late window collapses: the late threshold coincides with the down moment and the check goes straight to down. Grace is set per check: 0 to 30 days. Time-based transitions are executed by the scheduler with minute precision. The down alert arrives within ~1–2 minutes of grace running out: the overdue check is found by the minute-precision scheduler, the delivery itself takes seconds.
An explicit failure signal bypasses grace: a ping to
/<uuid>/fail or with a
non-zero exit code (/<uuid>/42)
flips the check to down immediately — the job itself said
it failed, there is nothing to wait for.
A check that keeps bouncing between up and down ("flapping") can send dozens of identical alerts within an hour. CronAlive dampens that storm automatically:
suppressed with the reason "the check is unstable (flap damping)" — it is always clear why things went quiet;late alerts neither move the threshold nor get suppressed — they are an early signal. Manual operations (pause, resume, reset) do not count as flips. Defaults: threshold 6 changes, window 1 hour, 30 minutes of silence to exit.
Pause, resume, delete and tag assignment also work in bulk — tick the checkboxes in the list. From the check page you can clone a check (config without history) and move it to another project of the account.
Statuses are visible on the dashboard, in the API and on public badges; HTTP checks use K confirmations instead of ping timing.