A self-hosted Cronitor alternative

Cronitor’s ping URL looks like this:

https://cronitor.link/p/API_KEY/nightly-backup?state=complete

Central Logging’s looks like this:

https://logs.example.com/p/API_KEY/nightly-backup?state=complete

That is not a coincidence worth reading into — it is a shape several tools settled on. But it does mean that if you are weighing a move, the crontab edit is a hostname and one state name, not a rewrite.

This page is about whether the move is worth making, and it starts with what Cronitor does better.

Start with the honest part

Cronitor is a much broader product. Cron monitoring is one piece of it. The docs also cover synthetic website and API monitoring, heartbeat monitors, cookie-free web analytics, status pages, and team management with roles and permissions.

Central Logging has no status pages, no analytics, no synthetic checks beyond a plain HTTP GET, and one admin login with no roles at all. If more than one person needs an account, this is the wrong tool and the rest of the page will not change that.

Cronitor is hosted, and that is a feature. Someone else keeps it running, and it is watching from outside your infrastructure. A self-hosted monitor that lives on the same rack as the jobs it watches goes down with the rack. That is a real argument and it does not have a rebuttal.

Cronitor’s alerting is more configurable. It has failure tolerance for consecutive failures, schedule tolerance for missed runs, and grace periods so a job can start late without firing. Central Logging has one rule, derived automatically, and no knobs.

So: if you want a monitoring product, buy Cronitor. The case here is narrower than that.

The interesting difference: declared schedule vs learned schedule

This is a genuine design split, not a feature-list difference.

Cronitor asks you to declare the schedule. Cron syntax, an interval like every 2 hours, or a time of day like at 13:37. It knows the job should have run at 03:00 before the job has ever run once.

Central Logging works it out from the pings. It keeps the last 100 complete pings for a job, takes the median gap between them, and expects the next one at the last ping plus that median. Drift past that by more than 20% and the job is unhealthy. The check runs every minute.

Neither is strictly better.

A declared schedule is precise, and it covers the first run. Central Logging needs two completed pings before it has any idea what normal looks like; a job that has pinged once is never considered late. A job with genuinely irregular timing gives it a wobbly baseline, and there is no way to tighten the window for a job that needs it.

A learned schedule means there is nothing to keep in sync. A cron expression in a monitoring tool is a second copy of a fact that lives in your crontab, and second copies drift. A job moved from daily to hourly, with a monitor still expecting daily, is a false-alarm generator until someone remembers. Add the ping, and the monitor exists and stays correct.

If your jobs run on a regular clock, the learned approach saves configuration and cannot drift. If they are irregular, or the first missed run has to page someone, declare the schedule.

Side by side

Cronitor Central Logging
Hosting SaaS Self-hosted, one binary
Watches from Outside your infrastructure Your own server
Schedule Declared: cron, interval or time of day Learned from ping history
First-run coverage Yes Needs 2+ completions
Grace and tolerances Failure tolerance, schedule tolerance, grace periods 20% drift, not adjustable
Ping states run, complete, fail, ok start, complete, fail
Ping methods GET, POST, HEAD GET, POST, HEAD
Message with a ping Up to 2000 characters Up to 500 bytes
Metrics with a ping count, duration, error_count Any name you like, 20 per ping
Other ping fields env, host, series, status_code status_code
Rate limits 10/s per monitor, 50/s per IP, then 429 None documented
Log aggregation No Yes
Uptime monitoring Yes, synthetic checks HTTP GET only, no status-code alerts
Status pages Yes No
Analytics Yes No
Teams and roles Yes No — one admin login
Pricing model Per-monitor subscription $187 once

What migrating actually involves

Three changes, if you decide to.

The hostname, from cronitor.link to your own server.

state=run becomes state=start. Same meaning, different word. complete and fail are the same on both.

Metric names. Cronitor’s metrics are a fixed vocabulary — count, duration, error_count. Central Logging takes any name you invent, up to twenty per ping, parsed at the last colon so the names themselves may contain colons:

curl "https://logs.example.com/p/API_KEY/nightly-backup?state=complete&status_code=0&metric=duration:418.44&metric=tables:3319&metric=bytes:9914223"

Each numeric metric gets its own chart over the last hundred runs. That is how you notice a backup getting slower months before it starts timing out.

There is no env, host or series parameter. If you were using env to separate staging from production, use distinct job names instead.

One deliberate behaviour worth knowing: a malformed metric is dropped, not rejected. The ping still succeeds. A ping is the tail of a shell command, and failing it over a typo would cause the outage it is supposed to be monitoring.

What a full setup looks like

Fire only on success, so a failed job stays silent and gets caught by the missed check-in:

0 3 * * * /usr/local/bin/backup.sh && curl -fsS "https://logs.example.com/p/API_KEY/nightly-backup?state=complete"

Tell it directly when the job knows it failed. The notification goes out within a minute:

/usr/local/bin/backup.sh || curl -fsS "https://logs.example.com/p/API_KEY/nightly-backup?state=fail&status_code=$?&message=backup+failed"

A job that fails every run does not message you every run. The first failure notifies; the next stays quiet until the job completes successfully or a day has passed.

For a job that can die partway, send start first so the attempt is on record:

curl -fsS "https://logs.example.com/p/API_KEY/nightly-backup?state=start"
/usr/local/bin/backup.sh
curl -fsS "https://logs.example.com/p/API_KEY/nightly-backup?state=complete"

Ping history is kept for 90 days.

The argument for one tool

Here is what a cron monitor on its own cannot do, hosted or not.

A job fails. You get the alert. Now you want to know why — and the output of that job is somewhere else. Another tab, another login, and you are matching timestamps by hand.

Cronitor takes a 2000-character message with the ping, which is more than Central Logging’s 500 bytes, and for many jobs that is enough. For the ones where it is not, the fix is to send the output somewhere searchable:

/usr/local/bin/backup.sh 2>&1 | curl -fsS -X POST --data-binary @- \
    https://logs.example.com/api/v1/ingest_logs/YOUR-SOURCE-TOKEN

Then the alert, the run history and the actual error output are one search apart, on the same clock and in the same tool. Sending logs with curl covers the error handling that stops that pipe failing quietly, and monitoring cron jobs covers the whole setup.

Things Cronitor does that this does not

  • Watch from outside your infrastructure. A self-hosted monitor cannot alert on its own outage.
  • Teams, roles and permissions. Central Logging has one admin login.
  • Status pages and web analytics.
  • Synthetic website and API monitoring, properly. Central Logging does a 5-second HTTP GET and does not alert on status codes at all.
  • Per-job tolerances and grace periods, and schedules that work from run one.
  • 2000-character messages attached to a run.
  • Email, and the integration list generally. Central Logging notifies over Slack, Telegram and Pushover only.

Things Central Logging adds

  • Your logs, in the same tool. SQL and full-text search over everything you ship it.
  • Metrics with names you choose, charted per job.
  • No cron expressions to maintain, and no monitor that can drift out of sync with the crontab.
  • Host check-ins, TLS expiry monitoring, and Prometheus scraping, in the same binary.
  • One fixed cost rather than a per-monitor subscription, and no job data leaving your network.

Who should choose which

Use Cronitor if you want a hosted service watching from outside, if more than one person needs an account, if you need precise grace periods or first-run coverage, or if you want the status pages and analytics too.

Use Central Logging if you are already going to run a log server, if your jobs run on a regular clock, if one admin login is fine, and if you would rather the job’s health and the job’s output lived in the same place.

Comparing against the open-source option instead? Healthchecks.io is free to self-host and the closer comparison on price. For uptime specifically, see Uptime Kuma and Uptime Robot.

Try it

The free download is the complete product, not a trial. Point one job’s ping at it and see whether the learned schedule does what you want.

14-day refund if you buy and it does not fit.

💌 Get notified on new features and updates

Only sent when a new version is released. Nothing else.