Cron job monitoring: we tell you when a job does not run

Your server runs your cron jobs, but it does not tell you when one fails to run. We do, with a heartbeat – a regular sign of life: your job checks in with us after every run. If the check-in does not arrive, you get a message by email, in Slack, Teams or Discord.

  • 1 heartbeat free
  • Email alerts from €17.88 a year
  • Servers in Germany
How Cronjob.de keeps watch over your cron jobsSeveral jobs check in with Cronjob.de after every run. When the n8n workflow does not check in, alerts go to email and Slack; as soon as it checks in again, an all-clear follows.Backup scriptdaily at 3 amn8n workflowhourlyCheck-in missingLaravel schedulerevery 5 minutesSupabase cronevery 15 minutesEmailSlackTeamsDiscordWebhookCronjob.dekeeps watch How Cronjob.de keeps watch over your cron jobsSeveral jobs check in with Cronjob.de after every run. When the n8n workflow does not check in, alerts go to email and Slack; as soon as it checks in again, an all-clear follows.Backup scriptdailyn8n workflowhourlymissingSupabase cronevery 15 minEmailSlackTeamsCronjob.dekeeps watch

Animation: four jobs check in with Cronjob.de after every run. The n8n workflow stops checking in; after the grace period, alerts go to email and Slack. As soon as it checks in again, an all-clear follows.

What is a heartbeat?

A heartbeat is a short check-in your job sends to its own address with us after every successful run. We know when the next one is due – if it does not arrive, that is exactly the message.

  1. Get your address

    You create a heartbeat: a name, how often the job runs and how much leeway it gets. You receive a ping address of its own, such as https://runcheck.de/a8k3m2x9q1.

  2. Add one line at the end of the job

    A call to that address when the job is done: in the crontab, in the script or as the last step of the workflow.

  3. We alert you when the check-in is missing

    If it does not arrive in time or the job reports a failure, you get a message. The next check-in brings the all-clear.

This is the overview in your account – with sample data.

One line, right where your job ends

The address below is an example. Yours appears in your account once you create the heartbeat, with the same lines ready to copy. Every line has a short time limit and never holds up your job, even if we cannot be reached.

In the crontab (crontab -e), extend your line with the marked part. $? passes on your script's result: 0 means success, anything else a failure.

0 3 * * *  /path/to/backup.sh; curl -fsS -m 10 --retry 3 https://runcheck.de/a8k3m2x9q1/$? > /dev/null

As the last line of your script, after the actual work:

// … your code …
@file_get_contents('https://runcheck.de/a8k3m2x9q1', false, stream_context_create(['http' => ['timeout' => 5]]));

At the end of the script, standard library only:

# … your code …
import urllib.request
try:
    urllib.request.urlopen("https://runcheck.de/a8k3m2x9q1", timeout=10)
except OSError:
    pass

Node.js 18 or later, at the end of your async function:

// … your code …
await fetch('https://runcheck.de/a8k3m2x9q1', { signal: AbortSignal.timeout(10000) }).catch(() => {});

Add an “HTTP Request” node at the end of the workflow. In its settings, set “On Error” to “Continue”.

Method:   GET
URL:      https://runcheck.de/a8k3m2x9q1
Options:  Timeout 10000

As the last module in the scenario: HTTP › “Make a request”.

Method:  GET
URL:     https://runcheck.de/a8k3m2x9q1

After the work of your cron job, for example in the SQL Editor. Both run in one transaction: if the work fails, pg_net never sends the check-in.

select cron.schedule('nightly-cleanup', '0 3 * * *', $$
  delete from sessions where expires_at < now();
  select net.http_get('https://runcheck.de/a8k3m2x9q1');
$$);

In the route your vercel.json calls under “crons” – after the work, before the response:

// app/api/cron/route.ts
export async function GET() {
  // … your code …
  await fetch('https://runcheck.de/a8k3m2x9q1', { signal: AbortSignal.timeout(10000) }).catch(() => {});
  return Response.json({ ok: true });
}

There is more: https://runcheck.de/a8k3m2x9q1/start at the start measures the run time and reports a run that gets stuck. https://runcheck.de/a8k3m2x9q1/fail or an exit code from 1 to 255 reports a failure right away. Via POST we accept up to 10 KB of output, which then shows up in the log.

In detail, step by step: BackupWordPressn8nSupabaseVercelNetlify

Heartbeat monitoring for everything that runs on a schedule

Anywhere an address can be called at the end of a run.

Your own server

Crontab, systemd or the Windows Task Scheduler: the check-in goes after the command, and the exit code tells us whether it worked.

Backups

rsync, restic or borg: you learn the morning after whether the backup ran – not when you need a file back.

n8n and Make

One HTTP step at the end of the workflow. If the workflow does not start at all, you still find out.

Laravel

The scheduler already ships ->pingOnSuccess(): put in your ping address, done.

WordPress

A small must-use plugin that checks in every hour shows whether WP-Cron is really running.

Apps built with Lovable, Bolt and v0

Their scheduled jobs run on Supabase, Vercel or Netlify. One line at the end tells you whether they ran today.

And if the cronjob runs with us?

Then we call your script on schedule – and with the success check you also know whether it did its job. Calling and monitoring stay with one provider, in one account.

  • End signalYour script reports at the end that it has finished. If the signal does not arrive within the deadline, the run counts as failed – so you know even for long scripts whether they completed.
  • Response checkIf an expected “OK” is missing or “Fatal error” appears in the reply, the run counts as a failure – even if the server answered with status 200.

Both in the Unlimited plan. Typical error messages from PHP, Python, Node.js, WordPress and Laravel are recognised from Plus.

Sample data

What it costs

Heartbeats are part of the Cronjob.de plans – cronjobs and monitoring in one account, on one invoice.

Heartbeats per plan
Feature Free0 € Plus€1.49 a month, €17.88 a year Unlimited€3.99 a month, €47.88 a year
Price 0 € €17.88 a year €47.88 a year
Heartbeats 1 up to 10 up to 50
Alert when the check-in is missing Status in your account Email Email, Slack, Teams, Discord, webhook
Cronjobs we call 5 unlimited unlimited
Success check for cronjobs not included detect typical error messages End signal and response check

Every new sign-up starts with 14 days of Unlimited, no payment details needed. After that the account continues on the free plan. All prices and plans

Frequently asked questions

What does monitoring cost?
One heartbeat is free; you see its status in your account. With Plus for €17.88 a year you monitor up to 10 heartbeats and get an email when a check-in is missing. Unlimited for €47.88 a year brings 50 heartbeats and also alerts in Slack, Microsoft Teams, Discord or via webhook. Every new sign-up starts with 14 days of Unlimited, no payment details needed.
When exactly do you alert me?
You set how often your job runs and how much leeway it gets – for a daily backup, one hour for example. If no check-in has arrived by then, we alert you once; the next check-in brings the all-clear. If your job reports a failure, for example through an exit code other than 0, we alert you right away.
What happens if runcheck.de cannot be reached?
Your job keeps running. Every line on this page has a short time limit and ignores errors while checking in. And if no heartbeat at all checks in during a period, the problem is on our side – then we do not alert you for that period.
What happens to my data?
Check-ins arrive on our servers in Germany. We store the time of each check-in, the IP address it came from and – only if your job sends it via POST – up to 10 KB of output. It is kept like the call log of your cronjobs. Do not put personal data into the output; it is meant for short status messages.
Is this a dead man’s switch?
Yes. A heartbeat works like a dead man’s switch: as long as your job checks in, nothing happens. If the check-in does not arrive, we trigger the alert. Other services call this cron job monitoring or heartbeat monitoring.
Do I need to install anything?
No. Checking in is an ordinary call to an address – with curl, with what PHP, Python or Node.js bring along, or as an HTTP step in n8n and Make. Laravel can do it out of the box.
Can I report run times and failures too?
Yes. https://runcheck.de/a8k3m2x9q1/start at the start measures the run time and reports a run that gets stuck. https://runcheck.de/a8k3m2x9q1/fail or an exit code from 1 to 255 reports a failure right away. Via POST we accept up to 10 KB of output, which shows up in the log.

Your first heartbeat is set up in two minutes

Free, no payment details. Cronjobs we call and heartbeats for the ones that run on your side: everything with one provider, from Germany since 2003.

Set up a heartbeat for free