Your OpenClaw agent works perfectly when you ask it to do something, but its heartbeat never seems to fire on its own. You tell it to check your inbox, and it does. You set up a daily check-in, and nothing arrives. The heartbeat works manually, but not on schedule. This is one of the most common OpenClaw frustrations, and almost every time, the cause is one of a handful of configuration details that are easy to miss.
In most cases the fix is one of these: your HEARTBEAT.md file is empty or comments only (OpenClaw skips those runs), heartbeat target is set to none so runs happen but nothing is delivered, or your activeHours window is skipping your local time. Check those three first, in that order.
What “Heartbeat Not Triggering” Actually Looks Like
Before you change anything, match your symptom to the pattern. People describe this problem in a few distinct ways, and each points to a different cause:
- It never fires at all. No heartbeat runs, no alerts, no log activity. This is usually a config-level skip.
- It fires, but nothing is delivered. You can see runs happening, but no message reaches Telegram, Discord, or WhatsApp. This is a delivery target problem.
- It works manually but not on schedule. When you type “read your HEARTBEAT.md and process tasks,” it works perfectly. This is the classic sign of a scheduled-run skip or a model that ignores the heartbeat prompt.
- It worked, then stopped after an update. This points to a version regression, and the fix is usually a rollback or a config re-check.
If you are not sure whether heartbeats are even running, check the log directly. Run openclaw system heartbeat last in your terminal. It shows the last heartbeat event and the reason it ran or skipped. That single command will tell you which of the fixes below you need.
tasks: block, and no task is due at that tick, the heartbeat is skipped with no-tasks-due.showOk, showAlerts, and useIndicator are all false, OpenClaw skips the heartbeat up front.activeHours, runs outside the window are skipped until the next tick inside it. And a window where start and end are the same value, like 08:00 to 08:00, is treated as zero-width, so heartbeats are always skipped.Every one of these has a visible skip reason in the logs, which is why checking openclaw system heartbeat last first is the fastest way to diagnose.
Step-by-Step: The Complete Fix
1. Confirm heartbeats are enabled and set the interval
The default interval is 30 minutes, but it changes to 1 hour when you use Anthropic OAuth or token auth, including Claude CLI reuse. If you expected 30-minute heartbeats and see hour-long gaps, that is why. Set it explicitly in your OpenClaw config:
{
"agents": {
"defaults": {
"heartbeat": {
"every": "30m"
}
}
}
}
Use "0m" to disable heartbeats entirely, which you should never need unless you are testing. After editing the config, restart the gateway with openclaw gateway restart.
2. Give HEARTBEAT.md real content
If your HEARTBEAT.md is mostly comments, headings, or empty checklist stubs, OpenClaw skips heartbeat runs to save tokens. A comments-only file is the most common reason people think heartbeats are broken, because the file exists and looks configured. Replace it with actual instructions:
# HEARTBEAT.md
- Check my inbox for anything urgent and flag it.
- If a calendar event starts within 2 hours, notify me.
- If nothing needs attention, reply HEARTBEAT_OK.
Keep it small. A short checklist is enough, and a bloated file wastes tokens on every run. If you want multiple checks on different schedules, use a tasks: block, where each task has its own interval and only due tasks are included in the heartbeat prompt.
3. Set a delivery target
The heartbeat target defaults to none, which means the run happens but nothing is delivered anywhere. If your heartbeat is running but you never see messages, this is almost certainly it. Set it to last to deliver to the last channel you used, or point it at a specific channel:
{
"agents": {
"defaults": {
"heartbeat": {
"every": "30m",
"target": "last"
}
}
}
}
For a fixed destination, use the channel id, like "target": "telegram" plus "to": "12345678". If you use multiple accounts on a channel, add "accountId" too. Also check the channel-level visibility settings: showOk hides the HEARTBEAT_OK ack, and showAlerts controls alert delivery. If someone set showAlerts: false for your channel, alerts are suppressed even though heartbeats run.
4. Check your active hours window
If you configured activeHours, heartbeats outside the window are skipped. Two common mistakes: the window does not cover your actual active time because of timezone mismatch, or start and end are equal, which is a zero-width window that always skips. A full-day window is written as start: "00:00" and end: "24:00". If you do not need a window at all, remove the block entirely.
5. Test with a manual wake
Trigger a heartbeat on demand to confirm the whole chain works before you wait for the next scheduled tick:
openclaw system event --text "Check for urgent follow-ups" --mode now
If the manual wake delivers a message but the scheduled tick does not, the problem is the skip logic or the schedule, not the agent. If even the manual wake delivers nothing, the problem is delivery config or the model.
6. Switch or check the model
Some models are unreliable at following the heartbeat prompt, especially smaller local models. Users report heartbeats working on GLM and Gemini Flash while failing on other models, and model-specific tool-calling bugs have broken heartbeat and cron flows in specific OpenClaw versions. You can set a dedicated heartbeat model in config:
{
"agents": {
"defaults": {
"heartbeat": {
"model": "anthropic/claude-sonnet-4-6"
}
}
}
}
One warning: a heartbeat model with a small context window can leak into the main session and cause a context overflow on the next normal turn. Use isolatedSession: true if you run a small local model for heartbeats.

If It Still Does Not Work: Update and Rollback
Version regressions are a real and common cause. Multiple OpenClaw releases have broken Telegram delivery, tool profiles, and heartbeat behavior, and the community consensus is to roll back rather than fight a bad release. If heartbeats worked and then stopped after an update:
- Check the release notes and the GitHub issue tracker before upgrading in the future.
- Roll back with
npm i -g openclaw@[previous-version], or restore from your last known good backup. - Verify the config was not rewritten by the update. Some releases changed tool profiles and other settings during migration.
If you changed nothing and heartbeats stopped, do not spend hours debugging your config. Roll back first, confirm heartbeats return, then decide whether the new version is worth the fight.
Cutting Heartbeat Token Costs While You Are At It
Heartbeat runs are full agent turns, and every turn resends conversation history, system prompts, and tool schemas. If you are on a tight budget, two settings make a big difference:
isolatedSession: trueruns each heartbeat in a fresh session with no conversation history. This can drop per-run cost from around 100K tokens to a few thousand.lightContext: truekeeps only HEARTBEAT.md from the bootstrap files instead of injecting the full workspace context.
{
"agents": {
"defaults": {
"heartbeat": {
"every": "30m",
"target": "last",
"isolatedSession": true,
"lightContext": true
}
}
}
}

FAQ
My heartbeat works when I run it manually but never on its own. Why?
That pattern almost always means a scheduled-run skip. Check openclaw system heartbeat last and look for the skip reason. The most common are empty-heartbeat-file (HEARTBEAT.md has no real content), no-tasks-due (tasks block with nothing due), or alerts-disabled (delivery flags all off). Manual runs bypass the schedule checks, which is why they always work.
Heartbeats are running but I get no messages. What is wrong?
Delivery. The default target is none, so runs happen silently. Set target: "last" or a specific channel, and make sure showAlerts is not disabled for that channel.
Does the heartbeat have access to my main conversation context?
By default, heartbeat runs use the main session context. But you can set isolatedSession: true, which gives each heartbeat a fresh session with no history. If your heartbeat tasks depend on what was discussed earlier, keep the default or give the heartbeat explicit instructions in HEARTBEAT.md.
Can I use local models like Ollama for heartbeats?
Yes, but with caveats. Small local models are sometimes unreliable at following the heartbeat prompt, and a small context window can bleed into the main session and cause context overflow. If you use a local model for heartbeats, also enable isolatedSession: true so the small window does not affect your main session.
Heartbeats worked before the update and broke after. What do I do?
Roll back to the previous version and verify. Version regressions are common enough that the community default is backup, update, test, and roll back if needed. Check the release notes and GitHub issues before upgrading.
Heartbeats are just one piece. Learn how to schedule real work with cron jobs, background tasks, and sub-agents in our full OpenClaw automation guide.

