Cron & Heartbeat Monitoring

The check for jobs that fail without making a sound.

Backups, queue workers, nightly crons: none of them throw a 500 when they die. They just stop. And you find out when you reach for the thing they were supposed to produce and it isn't there. Hoppla watches for the ping that was due and never came. It holds fire through a grace window so a job that's a couple of minutes late stays quiet, and pages you only when a run is genuinely missing or reports itself failed.

JOB / SAMPLE OUTPUT

POST /api/ping/4f2a... state=fail · last ok 23h ago · DOWN

Fictional values. Not a live measurement.

01 / What it does

Monitoring for the work that runs when nobody's looking

Your job hits a public ping URL when it runs. A bare ping says "I ran." A POST with state=fail says "I ran, and I broke." You tell Hoppla the cron schedule the job follows and how many minutes late is still fine. Inside that window a late job shows as overdue, but no alert fires. Miss the window with no ping, or send a fail, and it goes down.

What’s included

  • Public ping endpoint /api/ping/{uuid}, no auth, GET or POST
  • GET confirms a run; a POST with state=fail reports a failed run
  • state=start and state=complete accepted as check-ins (run duration isn't timed)
  • Grace windows: a cron schedule plus allowed lateness in minutes, per job
  • Next expected ping computed from the last ping and the schedule
  • Alerts on a missed window or a fail ping, not on lateness inside the grace window
  • Strict UUID-only path: malformed or unknown IDs return 404
02 / How it works

Under the hood.

01

Your job pings when it runs

At the end of a run the job calls /api/ping/{uuid} over GET or POST. No auth, no account token in the request. The UUID in the path is the secret. A plain ping confirms the run, and that's all the smallest cron needs.

02

A fail ping reports the bad runs

POST state=fail and Hoppla records the run as a failure, not a success. So a job that fires on schedule but errors out still trips the alert, instead of looking healthy because it 'ran'. state=start and state=complete are accepted too, but each simply counts as a check-in: Hoppla doesn't time the run between them.

03

You set the cron schedule and grace

Give Hoppla the cron expression the job follows and a grace time in minutes. A 02:00 nightly backup with 15 minutes of grace is quiet at 02:12 and down at 02:16. Inside the window, ordinary lateness shows as overdue but sends no alert.

04

Hoppla waits for the ping that's due

From the last ping and the schedule, Hoppla works out when the next run is expected. When that time plus the grace window passes with no ping, the check goes down and your alert fires. The silence becomes the signal.

03 / Why it matters

The part that actually moves the needle.

01no auth

Drops into any crontab

The ping is one unauthenticated URL. A curl line appended to a cron entry works from Bash, Python, Go or a Kubernetes CronJob, anything that can make an HTTP request. Nothing to install on the box.

02state=fail

It reports failure, not just silence

A GET tells you a job ran. A fail ping tells you it ran and broke. You catch the cron that fires on time but exits dirty, the kind a silence-only monitor would happily report as healthy.

03grace window

Late means late, not jittery

Schedule plus a grace time in minutes means an alert is a real miss, not a job that started 90 seconds behind. The noise that trains people to mute cron alerts rarely gets going.

04 / For every team

Whoever you are, this lands differently.

Solo SaaS founder

Your nightly database dump is one line in one crontab. The day it silently stops is the day you'd only find out when a customer asks for their data back. Append a curl ping to that line. The morning the backup goes missing, the alert lands on the phone next to your bed, which is the entire ops rotation you have.

Small agency

Spread across 5 to 30 client sites you've got a backup here, a wp-cron there, an invoice sync somewhere else, and nobody whose job is to watch them. Put a heartbeat on each, including the wp-cron that quietly dies the moment a low-traffic site stops getting hits. You usually hear the task stopped before the client emails asking why the newsletter never went out.

Large agency

At hundreds of sites, "did the export run?" turns into "show me it ran." Every ping is timestamped against its schedule, so when an account manager needs to prove a client's nightly job fired on time all month, the run history answers it. No grepping cron logs, no taking a developer's word for it.

Reseller / hosting provider

Backup monitoring is a line item your customers will pay for. Under your own brand and domain, give each customer heartbeats on their backup and maintenance jobs and sell it as a tier. The ping is unauthenticated HTTP, so it drops into whatever stack the customer runs without you touching their code.

Switching tools

Monitoring somewhere else? Bring your setup with you.

Import the monitors you already run in another tool. What comes across depends on the provider. Run both side by side for 24 hours or 7 days before you switch.

  • Guided import
  • Shadow run before you switch
  • Coverage varies by provider
Import from
  • Oh Dear
  • Uptime Robot
  • Better Stack
  • Pingdom
  • StatusCakeBeta
  • CronitorBeta
  • Healthchecks.ioBeta
  • Statuspage

The importer opens in your workspace once you have access.

Get early access
FOR HOSTERS & RESELLERS

Backup and job monitoring is a line item customers will pay for. Heartbeats on every customer's crons, sold as a tier under your brand.

See the reseller program
05 / FAQ

Straight answers.

How is this different from Cronitor?

The mechanics are familiar: a ping URL, a schedule, a grace window, a fail state. What's different is where it lives. Your cron checks sit in the same Hoppla account as your uptime, SSL, DNS and broken-link monitoring, on one bill and one alert config, not a separate tool you only open after something's already broken.

Do I need to install anything on my server?

No. The endpoint is plain HTTP, so a single curl line at the end of a cron entry reports a run from any language. There's no agent and no library to add to your project.

What stops it alerting when a job just runs a little late?

The grace window. You set a cron schedule and how many minutes of lateness is acceptable, and the check only goes down once that window closes with no ping. A job that lands a couple of minutes behind schedule, inside that window, doesn't trip it.

Can it tell me a job failed, not just that it's missing?

Yes: POST state=fail in the request body. A job that runs on schedule but errors gets recorded as a failure and alerts, instead of looking healthy because it ran. A GET, or state in the query string, only confirms the run, so a leaked URL can't fake a failure.

Your next step

Put a heartbeat on the jobs you only notice once they're gone.

Checks, alerts and status pages in one workspace. Now in early access: join the list for an invite.