Cronheart
WP-Cron is request-driven. On a low-traffic site no requests arrive, no events fire, and a scheduled backup can be stalled for weeks before anyone notices. Uptime monitors do not catch this — the site responds to HTTPS just fine, it just is not running its jobs. Cronheart turns WP-Cron into a dead-m
About this tool.
WP-Cron is request-driven. On a low-traffic site no requests arrive, no events fire, and a scheduled backup can be stalled for weeks before anyone notices. Uptime monitors do not catch this — the site responds to HTTPS just fine, it just is not running its jobs.
Cronheart turns WP-Cron into a dead-man switch : the plugin pings cronheart.com every five minutes and on every individual event you register. If the pings stop, cronheart alerts you via email, Telegram, Slack, Discord, or a custom webhook.
What it does
- Site heartbeat. A 5-minute custom WP-Cron event whose only job is to ping cronheart. Proves WP-Cron itself is alive on this site.
- Per-event monitoring. Register any scheduled hook for start / success / fail pings with one PHP one-liner: cronheart_monitor( 'my_nightly_report', 'xxxxxxxx-…' );
- PHP fatal-error capture. When a scheduled callback fatals or throws, the fail-ping body includes the error_get_last() summary — the cronheart dashboard shows the cause without you tailing debug.log .
- Settings page. A read-only “Monitored events” table at Settings → Cronheart shows every hook the plugin is watching and where its UUID came from (constant, option, filter).
- Monitor picker. Save a cronheart.com API token and the site heartbeat field becomes a dropdown of your account’s monitors instead of a hand-typed UUID. Entirely optional — without a token you paste the UUID as before, and any API hiccup falls back to that field. The token is write-only and never leaves wp-admin.
- Account overview and monitor management. With a token configured, Settings → Cronheart shows your plan and monitor budget, and a “Your monitors” table listing each monitor with its status and any active snooze. From that table you can pause, resume, snooze (1 hour, 4 hours, 1 day, or 1 week), or unsnooze a monitor; the change applies on cronheart.com immediately. Every action is an authenticated administrator request — nothing happens without your click.
- Per-event monitoring UI. A new Settings → Cronheart Events screen lists the recurring WP-Cron events on your site and lets you, per event, either assign one of your monitors from a dropdown or auto-create an interval monitor for it in one click — no code required. This is the point-and-click alternative to the cronheart_monitor() helper and CRONHEART_EVENT_<HOOK>_UUID constants, which still work. A constant overrides an assignment made on this screen; an assignment made on this screen overrides the helper.
- Channel management. A Settings → Cronheart Channels screen lists your cronheart.com notification channels and lets you, per channel, send a real test alert through it or — for webhook channels — rotate the signing secret (revealed once). Creating channels stays on cronheart.com; this screen tests and maintains the ones you already have.
- Ping & alert history. A Settings → Cronheart History screen shows the most recent pings (kind, time, runtime) and alerts (kind, time, channels notified) for a monitor you pick (the picker lists up to 200 monitors) — a read-only at-a-glance log without leaving WordPress.
Never breaks WP-Cron
The plugin’s hard contract: a broken cronheart backend, an unreachable network, a misbehaving PSR-18 HTTP client — none of them may cause WP-Cron to fail. Every network / HTTP error is swallowed into a logged warning. If cronheart goes down for a day, your wp_schedule_event callbacks still run normally; you just stop seeing pings on the dashboard.
External services
This plugin sends HTTP requests to cronheart.com in two distinct situations: the monitoring pings your scheduled jobs send, and the account-management calls the admin settings page makes. Both are opt-in: without configuration the plugin loads and does nothing — no telemetry, no usage statistics, no anonymous reports.
1. Monitoring pings (front end / WP-Cron). Sent on every scheduled WP-Cron run, but only when you supply a monitor UUID . The exact data sent per ping:
- The per-monitor UUID you configured (path segment).
- A short body excerpt — capped at 10 KB — containing either an exception summary (for fail pings) or nothing (for start / success / heartbeat ).
- The plugin / SDK version in a User-Agent header.
2. Account management (wp-admin only). When — and only when — you save a cronheart.com API token, the Cronheart admin screens (Settings → Cronheart, Settings → Cronheart Events, Settings → Cronheart Channels, and Settings → Cronheart History) talk to the cronheart.com management API at https://cronheart.com/api/v1/... . Every such request carries the token as an Authorization: Bearer header and runs only while a logged-in administrator is on one of those screens — and, for the write actions below, only when that administrator clicks the control. Never on the front end, during WP-Cron, or in any other context. No token, no request. The calls are:
- Read your monitors — GET /api/v1/monitors — to populate the heartbeat picker, the “Your monitors” table, the per-event assignment dropdowns, and the Cronheart History monitor picker. Sends nothing beyond the token and paging parameters.
- Read your account — GET /api/v1/account — to show your plan, monitor budget, and API rate-limit standing. Sends nothing beyond the token.
- Lifecycle actions — POST /api/v1/monitors/<uuid>/pause (or /resume , /snooze , /unsnooze ) — sent when you click a pause / resume / snooze / unsnooze button. Sends the monitor’s UUID (in the path) and the action; snooze also sends the chosen duration (1 hour, 4 hours, 1 day, or 1 week).
- Create a monitor — POST /api/v1/monitors — sent when you click “Auto-create & assign” for a recurring event on the Cronheart Events screen. Sends the event’s hook name (as the monitor name), its schedule as an interval in seconds, the site timezone, and a grace period — all derived from the WP-Cron schedule.
- Read your channels — GET /api/v1/channels — to populate the Cronheart Channels screen. Sends nothing beyond the token.
- Send a test alert — POST /api/v1/channels/<id>/test — sent when you click “Send test” on a channel. This delivers a real notification to that channel’s destination (your configured email, Telegram, Slack, Discord, or webhook), so it is the one management call with an effect outside cronheart.com. Sends only the channel id (in the path).
- Rotate a webhook secret — POST /api/v1/channels/<id>/rotate-secret — sent when you click “Rotate secret” on a webhook channel. cronheart.com mints a new signing secret (shown to you once) and invalidates the previous one. Sends only the channel id (in the path); the new secret is shown in the page and never stored by the plugin.
- Read ping & alert history — GET /api/v1/monitors/<uuid>/pings and GET /api/v1/monitors/<uuid>/alerts — to populate the Cronheart History screen for the monitor you select. Reads the most recent page only. Sends the monitor’s UUID (in the path) and paging parameters.
The lifecycle, create, test, and rotate-secret calls are the only requests that change anything — and “Send test” additionally delivers a real notification to the channel’s destination, while “Rotate secret” invalidates the old webhook secret — but each is one deliberate administrator click. The token is optional: without it the plugin makes none of these management calls — you assign monitors by hand (or via the constants / helper) and only the monitoring pings above are ever sent.
Cronheart.com Terms of Service · Privacy policy
Open source
Source code and issue tracker: github.com/alexander-po/cronheart-wp .
The plugin wraps the cron-monitor/php-sdk PHP package (also open source, MIT-licensed). Both projects are maintained independently.
Getting started.
- 01Install the plugin: WP Admin → Plugins → Add New → search for “Cronheart” → Install Now → Activate. Or upload cronheart.zip from a GitHub release.
- 02Sign up at cronheart.com and create a monitor for your site’s heartbeat. Copy the monitor UUID from the dashboard.
- 03Configure the UUID. Either add it to wp-config.php with define( 'CRONHEART_HEARTBEAT_UUID', 'xxxxxxxx-…' ); (recommended), or paste it under Settings → Cronheart in the WP admin.
- 04Done. Within five minutes you should see the first heartbeat ping on the cronheart dashboard.
- 05(Optional) To choose a monitor from a dropdown instead of pasting its UUID, create a Personal Access Token at cronheart.com ( Account → API tokens ) and save it under Settings → Cronheart . Every plan, the free one included, can use the API; the account email must be verified before a token can be created. The plugin works fully without a token. For production, prefer define( 'CRONHEART_API_TOKEN', 'cmk_…' ); in wp-config.php to keep the account credential out of the database.
For per-event monitoring (a specific scheduled hook, not just the site heartbeat), register the hook from a plugin / theme / mu-plugin:
add_action( 'plugins_loaded', function () { cronheart_monitor( 'my_nightly_report', 'xxxxxxxx-…' ); }, 1 );
The hook then emits start / success (or fail on a fatal / thrown exception) pings on every scheduled run.
Frequently asked questions.
Does this work when WP-Cron is disabled (system-cron mode)?
Yes. If you set define( 'DISABLE_WP_CRON', true ); and trigger wp-cron.php from a real system cron, the plugin’s heartbeat_tick action still fires on each run — the trigger mechanism is different, the action chain is the same.
What if my host blocks outgoing HTTPS?
The plugin will retry once (built-in retry budget) and then log a warning to debug.log . Your scheduled callbacks still run normally — the plugin never raises an exception that could break the cron runner. To diagnose, check wp-content/debug.log for entries beginning with “cron-monitor”.
Do I need a paid cronheart.com account?
No. Cronheart’s free tier covers 20 monitors per account — enough for a typical site’s heartbeat plus several per-event monitors. Every tier, the free one included, gets all notification channels (email, Telegram, Slack, Discord and signed webhooks). The REST API, which the optional token features in wp-admin use, is included on every tier, the free one too. Paid tiers (Starter / Growth / Scale) raise the monitor cap and the API rate limit.
Do I need an API token?
No — it is entirely optional. Paste a monitor UUID under Settings → Cronheart (or define it in wp-config.php ) and the plugin works on any plan, including the free tier. A token only adds convenience: the settings page can then list your monitors and let you pick one from a dropdown instead of copying a UUID by hand. The token is an account-level credential, so for production prefer defining CRONHEART_API_TOKEN in wp-config.php over storing it in the database. The token features work on every plan, the free one included, but cronheart.com only lets an account with a verified email address create a token. If the token is refused or cronheart.com cannot be reached, the page shows a notice and falls back to manual UUID entry.
Where do I find my monitor UUID?
Sign in at cronheart.com , open the monitor you created, and copy the UUID from the address bar or the “Ping URL” block on the monitor page.
What happens to my scheduled jobs if cronheart.com is unreachable?
Nothing. The plugin catches every network / HTTP error from the SDK and logs a warning — your wp_schedule_event callbacks continue to run. You will stop seeing pings on the cronheart dashboard, and after the configured grace period cronheart sends you the down-alert. When cronheart comes back the next successful ping resolves the incident automatically.