Beginner’s Guide to OpenClaw Heartbeats: Never Lose Agent Context
Beginner’s Guide to OpenClaw Heartbeats: Never Lose Agent Context

Let me be real with you: if you've run an OpenClaw agent for more than a few hours, you've experienced The Silence. That gut-dropping moment when you check on a long-running task and realize your agent stopped doing anything forty-five minutes ago. No error. No crash log. No dramatic farewell. It just… stopped. And you have absolutely no idea why.
I spent my first two weeks with OpenClaw losing work to this exact problem. A document processing pipeline that was supposed to run overnight? Dead by 2 AM, and I didn't notice until I grabbed my coffee at 8. A web scraping job across 200 pages? Hung on page 73 while I assumed it was happily chugging along.
The fix is heartbeats. And once you understand how they work in OpenClaw, you'll never go back to running agents blind.
The Actual Problem: Agents Fail Silently
Here's what nobody tells you when you start building AI agents: the hard part isn't getting them to work. It's knowing when they stop working.
Traditional software crashes loudly. You get a stack trace, an error code, a 500 response. AI agents are different. They can enter weird states — infinite retry loops, context window overflow, hanging on an API call that will never return — where they're technically "running" but functionally dead. The process is alive. The heartbeat of the machine is fine. But your agent is doing absolutely nothing useful.
This is especially painful with long-running tasks. If your agent takes two minutes to complete a job, you'll notice a failure quickly. If it's supposed to run for six hours processing a batch of documents, you might not realize something went wrong until the deadline has passed.
OpenClaw heartbeats solve this by giving your agents a way to continuously signal not just "I'm alive" but "I'm alive and here's exactly what I'm doing right now."
What OpenClaw Heartbeats Actually Are
Think of heartbeats like a dead man's switch. Your agent periodically sends a signal that says, "Still here, still working." If that signal stops, something went wrong, and you can react immediately instead of discovering the failure hours later.
But OpenClaw heartbeats go way beyond a simple ping. Each heartbeat carries context — what task the agent is working on, how far along it is, how many resources it's consumed, and what it plans to do next. It's the difference between a light on a server rack blinking green and a detailed dashboard showing you everything happening inside.
Here's the most basic setup:
from openclaw import Agent, HeartbeatConfig
agent = Agent(
heartbeat=HeartbeatConfig(
interval=30, # Send heartbeat every 30 seconds
include_metrics=True,
on_failure=lambda: notify_slack("Agent down!")
)
)
That's it for the basics. Every 30 seconds, your agent reports in. If it misses a check-in, your Slack channel lights up. You go from "discover failures hours later" to "know within 30 seconds."
But the real power is in what you do with heartbeats once they're running.
Setting Up Your First Heartbeat: Step by Step
Let's walk through a real scenario. You have an agent that scrapes product data from a list of URLs, processes the results, and stores them in a database. This job takes anywhere from 20 minutes to 2 hours depending on the list size.
Step 1: Basic Heartbeat Configuration
from openclaw import Agent, HeartbeatConfig
agent = Agent(
id="product-scraper-01",
heartbeat=HeartbeatConfig(
interval=30,
include_progress=True,
include_current_step=True,
include_metrics=True
)
)
The include_progress and include_current_step flags are crucial. Without them, you know your agent is alive but not what it's doing. With them, every heartbeat tells you exactly where things stand.
Step 2: Update Progress Within Your Task
@agent.task
async def scrape_products(urls):
results = []
for i, url in enumerate(urls):
# Update the heartbeat with current progress
agent.update_progress(i / len(urls))
agent.heartbeat.update_step(f"Scraping {url}")
data = await scrape(url)
results.append(data)
agent.heartbeat.update_step("Processing complete, saving to database")
await save_to_database(results)
Now each heartbeat payload looks like this:
{
"timestamp": "2026-01-15T10:30:45Z",
"agent_id": "product-scraper-01",
"status": "WORKING",
"current_task": "scrape_products",
"progress": 0.65,
"current_step": "Scraping https://example.com/product/130",
"steps_completed": 130,
"steps_total": 200,
"estimated_time_remaining": 480
}
If you see progress stuck at 0.65 for ten minutes when it was previously advancing every few seconds, you know the agent is hung on a specific URL. You can investigate that URL specifically instead of restarting the entire job and guessing.
Step 3: Set Up Monitoring
from openclaw import HeartbeatMonitor
monitor = HeartbeatMonitor(agents=[agent])
monitor.alert_if_silent(
threshold_seconds=90, # Alert if no heartbeat for 90 seconds
notification=SlackWebhook("https://hooks.slack.com/...")
)
I set my threshold to 3x the heartbeat interval. If heartbeats come every 30 seconds, alert after 90 seconds of silence. This gives enough buffer for network hiccups without letting real failures go unnoticed.
Scaling Up: Monitoring Multiple Agents
Running one agent with heartbeats is useful. Running a fleet of agents with centralized heartbeat collection is transformative.
Say you've got a pipeline: three scrapers feed data to two processors, which feed results to one analyzer. Without centralized monitoring, when the analyzer isn't producing output, you have to manually check every upstream agent to find the bottleneck.
from openclaw import HeartbeatCollector, Agent
collector = HeartbeatCollector(
storage="redis://localhost:6379",
dashboard_port=8080
)
scraper_1 = Agent(id="scraper-1", heartbeat_to=collector)
scraper_2 = Agent(id="scraper-2", heartbeat_to=collector)
scraper_3 = Agent(id="scraper-3", heartbeat_to=collector)
processor_1 = Agent(id="processor-1", heartbeat_to=collector)
processor_2 = Agent(id="processor-2", heartbeat_to=collector)
analyzer = Agent(id="analyzer-1", heartbeat_to=collector)
Now open localhost:8080 and you see:
scraper-1: ✓ HEALTHY (2s ago) Processing batch 5
scraper-2: ✓ HEALTHY (1s ago) Processing batch 6
scraper-3: ✗ SILENT (65s ago) Last: "Starting batch 7"
processor-1: ✓ HEALTHY (3s ago) Waiting for input
processor-2: ✓ HEALTHY (1s ago) Processing batch 4
analyzer-1: ✓ HEALTHY (4s ago) Waiting for input
Immediately obvious: scraper-3 died while starting batch 7. The processors and analyzer are fine — they're just waiting because one scraper isn't producing data. You fix scraper-3, and the pipeline resumes. Total time to diagnosis: about ten seconds.
Compare that to the old way: check the analyzer logs, see it's waiting, check each processor, see they're waiting, check each scraper one by one, finally find the dead one. Twenty minutes of investigation compressed to a glance.
Preventing Runaway Costs
Here's a scenario that's cost real people real money: an agent hits a retry loop on an API call and burns through your entire token budget before you notice.
OpenClaw heartbeats can track resource consumption and enforce limits:
agent = Agent(
heartbeat=HeartbeatConfig(
include_metrics=True,
metrics={
"api_calls": Counter(),
"tokens_used": Counter(),
"cost_usd": Counter()
},
limits={
"tokens_per_hour": 100000,
"cost_per_hour": 10.0
}
)
)
When your agent approaches 80% of any limit, the heartbeat system can automatically throttle it:
if agent.heartbeat.approaching_limit("cost_per_hour"):
agent.slow_down(factor=2)
And if you're running multiple agents sharing a quota:
quota_manager = QuotaManager(
max_tokens_per_hour=1_000_000,
max_cost_per_day=100.0
)
for agent in agents:
agent.heartbeat.register_quota(quota_manager)
The quota manager watches aggregate heartbeat metrics across all agents and throttles the heaviest consumers when you're approaching limits. No more surprise bills.
Graceful Shutdowns and Checkpointing
The other massive quality-of-life improvement heartbeats enable is graceful shutdown with state preservation. Instead of killing an agent and losing everything, you can tell it to wrap up cleanly:
agent = Agent(
heartbeat=HeartbeatConfig(
enable_shutdown_signals=True,
checkpoint_on_heartbeat=True,
checkpoint_interval=5 # Save state every 5 heartbeats
)
)
@agent.on_shutdown_signal
async def cleanup():
await agent.checkpoint.save()
await agent.finish_current_task()
await agent.close_connections()
agent.heartbeat.send_final(status="STOPPED_CLEANLY")
Later, when you restart:
agent = Agent.resume_from_checkpoint("product-scraper-01")
# Picks up at page 131/200 instead of starting over
This is especially critical if you're running agents in Kubernetes or any environment where pods get recycled. Your agent gets a SIGTERM, checkpoints its state in the preStop window, and the replacement pod resumes seamlessly.
Health Checks That Actually Mean Something
A binary alive/dead check is nearly useless for AI agents. An agent can respond to pings perfectly while being completely stuck in a useless state. OpenClaw lets you define application-level health checks:
agent = Agent(
heartbeat=HeartbeatConfig(
health_checks=[
SystemHealthCheck(),
QueueHealthCheck(max_backlog=100),
ResponseTimeCheck(max_latency=5.0),
CustomCheck(lambda: db.is_connected()),
],
health_levels=["HEALTHY", "DEGRADED", "UNHEALTHY"]
)
)
A "DEGRADED" status is gold for operational awareness. It means "this agent is working but struggling, and if you don't intervene it'll probably fail soon." You can set up load balancers to route less traffic to degraded agents, or trigger automatic restarts before a total failure occurs.
I use a custom memory check to catch leaks before they become crashes:
class MemoryLeakCheck(HealthCheck):
def check(self):
mem_usage = get_memory_usage()
if mem_usage > 0.9:
return "UNHEALTHY", "Memory exhausted"
elif mem_usage > 0.7:
return "DEGRADED", f"Memory high: {mem_usage:.0%}"
return "HEALTHY", ""
The heartbeat progression tells the whole story: memory at 45%, then 58%, then 72% with a DEGRADED alert, then automatic restart at 85% before the agent ever actually crashes. Proactive instead of reactive.
Adaptive Heartbeat Intervals
One thing I love about OpenClaw's implementation is adaptive intervals. A fixed 30-second heartbeat is fine, but it's wasteful when the agent is idle and potentially too slow when it's processing critical tasks:
agent = Agent(
heartbeat=HeartbeatConfig(
adaptive=True,
min_interval=10, # Fast when active
max_interval=60 # Slow when idle
)
)
When the agent is actively processing tasks, heartbeats come every 10 seconds for maximum visibility. When it's waiting for work, they slow to every 60 seconds so you're not drowning in noise. When the agent detects it's approaching a timeout or resource limit, it speeds back up automatically. Smart defaults that you don't have to think about.
Skip the Setup: Felix's OpenClaw Starter Pack
Now, everything I've described above works and works well. But I'll be honest — wiring up all these heartbeat configurations, health checks, collectors, and monitoring dashboards from scratch takes time. I spent the better part of a weekend getting my first multi-agent pipeline fully instrumented.
If you don't want to set all of this up manually, Felix's OpenClaw Starter Pack on Claw Mart includes pre-built skills with heartbeat monitoring already configured. For $29, you get a bundle of pre-configured agent skills that handle the health checks, progress tracking, graceful shutdown, and centralized monitoring patterns I've described here. It's genuinely the fastest way I've found to go from zero to properly instrumented agents. I wish it had existed when I started — would've saved me that entire weekend plus the handful of silent failures I dealt with while figuring things out.
Best Practices I've Learned the Hard Way
Set your alert threshold to 3x your heartbeat interval. If heartbeats come every 30 seconds, alert at 90 seconds. This prevents false alarms from network blips while still catching real failures quickly.
Always include progress information. A heartbeat that just says "alive" is barely better than no heartbeat at all. Include what the agent is doing, how far along it is, and what it plans to do next.
Use the DEGRADED health level. Don't wait for total failure. A degraded agent is a warning sign — act on it before it becomes an incident.
Store heartbeat history. You'll want it for post-mortems. When something goes wrong at 3 AM, being able to replay the exact sequence of heartbeats leading up to the failure is invaluable.
Checkpoint aggressively for long-running tasks. If a task takes more than 10 minutes, you should be checkpointing state on every heartbeat. The overhead is trivial compared to the cost of losing hours of work.
Start simple, then layer on complexity. Begin with basic heartbeats and failure alerts. Add progress tracking once that's solid. Then add resource monitoring, health checks, and historical analytics as your needs grow.
What to Do Next
Here's my recommended path:
- Add basic heartbeats to one agent today. Just interval + failure alerts. Takes five minutes.
- Add progress tracking to your longest-running task. Even just a percentage complete transforms your visibility.
- Set up a HeartbeatCollector if you have more than two agents. Centralized monitoring becomes essential fast.
- Add resource tracking before your next production run. Especially cost tracking. Trust me on this one.
- Implement checkpointing for any task over 10 minutes. Future you will be grateful the first time a deploy doesn't cost you hours of work.
Heartbeats aren't glamorous. They don't make your agents smarter or faster. But they're the difference between confidently running agents in production and anxiously refreshing logs hoping nothing broke. Once you've got them set up, you'll wonder how you ever ran agents without them.
Recommended for this post
