← Back to blog
OpenClaw

The Hidden Cost of OpenClaw's Heartbeat: How Default Settings Can Silently Drain Your Credits

OpenClaw heartbeats can silently consume credits, and a HEARTBEAT.md safety net was effectively disabled by default by an upstream bug. Here is how to prevent this.

April 13, 20264 min read

If you're self-hosting OpenClaw, there's a good chance you're burning credits right now and don't know it. We found this out the hard way on our QA environment at Oslark, and it was happening on every single agent with zero user interaction.

Here's what happened, why it gets expensive, and what you can do about it.

The Problem

We noticed credits disappearing from our QA environment on a regular cadence even though nobody was using the agents. No prompts, no tasks, nothing. Just a steady bleed.

The culprit: OpenClaw's heartbeat system.

Heartbeat is a scheduled agent turn. In OpenClaw, the default interval is 30m unless you override it. If you never set agents.defaults.heartbeat.every, the agent will keep waking up on that cadence and spending tokens.

Why We Didn't Catch It Sooner

Four things made this easy to miss:

  1. No explicit config. We never set agents.defaults.heartbeat in openclaw.json, so the environment quietly used the default 30-minute cadence.
  2. The empty-file safety net was disabled in the version window we were running. Commit a775d39e64 on February 14, 2026 added emptyFilePolicy and defaulted it to "run" when unset. In that version window, the old "empty/comment-only HEARTBEAT.md skips the model call" behavior became opt-in rather than automatic.
  3. The template/docs drifted too. Commit 198de10523 on March 18, 2026 wrapped the HEARTBEAT.md template content in a fenced markdown block. In the affected runtime window, that template would not have counted as effectively empty anyway.
  4. The cost config said "free." Our custom model provider declared cost: { input: 0, output: 0 }, so OpenClaw had no reason to self-limit or show meaningful dollar estimates.
  5. In our QA environment, each heartbeat cycle made 2 API calls against claude-sonnet-4-20250514. The agent would read HEARTBEAT.md, find nothing to do, reply HEARTBEAT_OK, and the session would compact, but the tokens were already spent. That call pattern is our measured behavior in QA, not a claim that every OpenClaw deployment behaves identically.

One important caveat: upstream appears to have changed course later. Current HEAD again skips effectively empty HEARTBEAT.md, and commit 790343c4b1 on April 10, 2026 widened empty detection for comment-only files. So if you compare this post against today's docs, you may be looking at the fixed behavior rather than the version that drained our credits.

Why Cache Behavior Matters

A lot of the cost comes down to whether repeated heartbeat turns can reuse cached prompt prefixes or whether every run is effectively a cold start.

Anthropic

Anthropic prompt caching uses a 5-minute lifetime by default, with an optional 1-hour cache at additional cost.

OpenAI

OpenAI prompt caching is automatic on prompts of 1,024+ tokens, and current docs say it can reduce input-token costs by up to 90%. In-memory retention generally lasts 5 to 10 minutes of inactivity, up to a maximum of 1 hour.

Google Gemini

Gemini supports caching too, but the details differ by implicit vs explicit caching mode and by the model you use.

So Why Is 30m Still a Bad Default?

Because 30 minutes is a bad fit for the default short cache windows on Anthropic and OpenAI. In the common default case, it is frequent enough to add up and long enough to miss the short automatic cache windows.

The opposite mistake is also common: making the heartbeat much shorter to chase cache hits. A 2- or 3-minute cadence may improve hit rates on some providers, but it also increases the number of calls dramatically. The correct interval depends on your token volume, your cache TTL, and whether you actually need that frequency.

The Fix

The immediate fix is simple: disable heartbeat entirely if you are not using recurring checks.

openclaw config set agents.defaults.heartbeat.every 0m

If you do need heartbeat, make the configuration intentional:

  • Set an explicit interval. Do not leave the default in place just because it shipped that way.
  • If you are on a version affected by the empty-file regression, set emptyFilePolicy: "skip" explicitly instead of assuming the docs match your deployed build.
  • Use isolatedSession: true and lightContext: true when heartbeat does not need the full chat history.
  • Keep HEARTBEAT.md tiny, and verify the real runtime behavior on your deployed revision rather than assuming the current docs are describing the same code path.
  • Configure accurate provider costs. If you set token prices to zero, OpenClaw has no basis for cost-aware budgeting.
  • Monitor token usage at the provider level, not just inside OpenClaw.

For Oslark Users

If you're on Oslark's managed hosting, this is already handled for you. We caught this in QA before it affected customer environments, and we've applied the fix across our managed instances.

This is exactly the kind of operational footgun managed hosting should eliminate. Oslark’s does: you focus on building your agents; we handle the config landmines.

What's Next: The Oslark Agent

We're building our own agent runtime from the ground up: one that handles caching and cost control properly out of the box, avoids hidden billing traps, and is designed from day one for managed, cost-efficient operation.

If you're tired of fighting OpenClaw's defaults, join the waitlist at oslark.com to get early access.

Keep Reading

More writing from Oslark

The blog is where we publish the operational details behind the products we manage.