Tutorial

How to Choose OpenClaw Heartbeat, Cron, or Webhook for One Recurring Task

May 9, 202613 min readUpdated September 13, 2026By OpenClawBlog Team

You have one task that should happen again and again: a morning digest, a queue check, or a message when a build finishes. The tempting part is the label. "Heartbeat" sounds periodic, "cron" sounds scheduled, and "webhook" sounds immediate. In OpenClaw, those names describe different operating boundaries.

The short rule is simple. Use a user-authored automation, managed through the cron-compatible CLI, when a clock owns the work. Use heartbeat when the agent should periodically look for something that needs attention in its main session. Use an inbound webhook when another service knows that the event has happened and can call the Gateway. OpenClaw's automation guide makes the same separation: a specific recurring job belongs to Automations, an ambient monitor belongs to Heartbeat, and an external caller belongs to Webhooks.

This is a documentation-based tutorial. The examples below are proposed verification steps, not a report of commands run against a live Gateway. That distinction matters here because a successful HTTP admission, a scheduled run, and a delivered message are separate facts.

The decision in one table

QuestionHeartbeatCron or automationInbound webhook
What starts the work?A system-owned periodic monitor tick.An interval, a cron expression, or a one-shot time.An HTTP request from an external service.
Who owns the timing?OpenClaw's monitor cadence.You, with the schedule and timezone you save.The sending service. OpenClaw does not invent an event if the sender is silent.
What is it good for?Ambient awareness and quiet alerts.A named task with its own instructions, run history, and delivery choice.Work that should begin when a build, ticket, form, or other external event arrives.
What is the awkward limit?It is not the right place for an operator-authored recurring task; runs can defer when the agent is busy.The Gateway must be available when the schedule is due, and delivery still needs its own check.Authentication, payload handling, retries, and admission are part of the integration.

The choice turns on the trigger, delay tolerance, required context, and consequence of a duplicate or missed run.

Start with a small task contract

Before editing configuration, write the job in one sentence. Include the source, the trigger, the acceptable delay, the output, the destination, and the actions that are out of bounds.

At 09:00 on weekdays in Europe/Paris, read the approved queue, prepare a short status summary, and deliver it to my private channel. Do not modify files, send follow-up messages, or act on recommendations.

That sentence already points toward a cron-style automation. It has a wall-clock time, a local timezone, a fixed destination, and a repeatable instruction. Change the first phrase to "When the CI provider reports that a build has finished" and the trigger points toward a webhook. Change it to "Every so often, tell me whether anything needs attention" and heartbeat becomes a plausible fit.

Decide whether the job may run late and whether a duplicate is harmless. Those answers affect the schedule, session mode, and retry plan.

Use heartbeat for ambient awareness

OpenClaw documents heartbeat as a system-owned monitor automation. It runs a periodic agent turn in the main session by default, and the documented default interval is 30 minutes. It can use a lightweight context, an isolated session, or active hours, but its job is still to surface things that need attention rather than to act as a private task queue. The Heartbeat reference explicitly says to edit the agent heartbeat configuration, not the generated monitor row.

This is a good shape for a monitor scratchpad such as "check for urgent follow-ups and stay quiet when there are none." It is a poor shape for "run this named report at 09:00 every weekday." The latter deserves its own definition so that you can inspect its prompt, schedule, delivery route, and history without searching through ambient turns.

A minimal configuration idea looks like this:

{
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "activeHours": {
          "start": "08:00",
          "end": "18:00",
          "timezone": "Europe/Paris"
        }
      }
    }
  }
}

This is a configuration example from the documented shape, not a recommendation to copy it unchanged. Choose an interval that matches the question. A 30-minute monitor cannot tell you that an event happened at 09:02, and active hours can make a silent period intentional. Scheduled heartbeats also depend on the automation scheduler: disabling cron.enabled or setting OPENCLAW_SKIP_CRON=1 stops scheduled heartbeat ticks. Busy queues and active target sessions can defer a scheduled turn.

For a proposed smoke test, validate the configuration, request one harmless event-driven wake, and inspect the last heartbeat:

openclaw config validate
openclaw system event --text "Check the heartbeat monitor scratch" --mode now
openclaw system heartbeat last

This tests an immediate wake, not recurring cadence. If you need proof that a named job ran, heartbeat starts from the wrong observability model.

Use cron or Automations for the task's clock

OpenClaw now calls its stored scheduler "Automations." The openclaw cron command remains an alias, so existing terminology and job syntax can continue to work. The scheduler supports one-shot times, fixed intervals, and five- or six-field cron expressions. The schedule reference also documents the timezone rules: a cron expression without --tz uses the Gateway host timezone, while an offset-less --at timestamp is treated as UTC unless you supply a timezone. --tz is not valid with --every.

That gives you a practical split. Use --every when a fixed interval is the requirement. Use --cron with --tz for a local calendar rule such as weekday mornings. The docs say recurring top-of-hour cron expressions may be staggered by up to five minutes to reduce load spikes. If the job really must start at the specified minute, add --exact.

Here is a proposed definition for the task contract above:

openclaw automations add \
  --name "Weekday queue summary" \
  --cron "0 9 * * 1-5" \
  --tz "Europe/Paris" \
  --exact \
  --session isolated \
  --message "Read only the approved queue. Return a concise status summary with links. Do not modify files, send follow-up messages, or act on recommendations." \
  --announce

This is documentation-derived. Replace the delivery options with your configured route, keep the first run read-only, and remember that isolation is not a permission control.

After creating the job, inspect the stored definition before waiting for the clock:

openclaw automations list
openclaw automations show <job-id>
openclaw automations run <job-id> --wait
openclaw automations runs <job-id> --limit 20

The management reference documents these operations. Run history is the main reason to prefer an explicit automation for a named recurring task, but it does not prove recipient delivery.

Use a webhook when the event comes from outside

Here, "webhook" means OpenClaw's inbound Gateway HTTP hook. It is different from an automation's outbound webhook delivery mode, which sends a finished event somewhere after a scheduled job runs. The delivery reference documents that outbound mode; this section is about an external service calling OpenClaw.

An inbound webhook is the right trigger when the outside system has the useful fact. A CI service can report that a build completed. A form service can report that a submission arrived. A monitoring system can report that an alert opened. OpenClaw does not need to wake up every 30 minutes and ask whether the event exists.

HTTP hooks are disabled by default. The documented setup requires a running Gateway, an enabled hook configuration, and a dedicated token. A narrow starting point is:

{
  "hooks": {
    "enabled": true,
    "token": "<long-random-hook-token>",
    "path": "/hooks",
    "allowedAgentIds": ["main"],
    "allowRequestSessionKey": false
  }
}

Use the hook configuration reference to check the full contract. The token should be different from the Gateway authentication secret. Requests use Authorization: Bearer <token> or x-openclaw-token; query-string tokens are rejected. Keep the endpoint behind loopback, a tailnet, or a trusted reverse proxy while you are proving the flow. Restrict the allowed agent and treat the event body as untrusted data. A hook token identifies an allowed caller, not a trustworthy payload.

For an event that needs a model-backed turn, the documented endpoint is POST /hooks/agent. A harmless proposed local test is:

curl --include http://127.0.0.1:18789/hooks/agent \
  -H 'Authorization: Bearer <long-random-hook-token>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: queue-event-test-001' \
  --data '{"message":"Summarize this test event: the sample import completed.","name":"Webhook smoke test","agentId":"main","deliver":false}'

The expected admission response is HTTP 200 with an ok value and a runId. That means the run was admitted. It does not mean the model finished, a tool succeeded, or a channel message was delivered. Add "waitForCompletion": true when the caller needs terminal execution and delivery facts in the same response, then still inspect the logs and the intended recipient.

The idempotency key matters when a caller loses the response and retries. Reuse the same key for the same request. The current webhook documentation also warns that mapped hooks are not a durable exactly-once delivery system, and repeated wake events can be coalesced. That is a reason to design the receiver and the sender together. If the external service can retry, decide what makes a duplicate safe before connecting a real account.

For a short, controlled notification, POST /hooks/wake can enqueue text for the main session and optionally request an immediate heartbeat. Do not put raw email, documents, or arbitrary user content into a wake message. Use an agent action with a restricted reader when the payload needs to be processed as untrusted input.

Try the same task in three shapes

Suppose the task is "tell me about build failures." The wording alone does not choose the mechanism.

Heartbeat shape

Use a heartbeat when you want the assistant to look for anything that needs attention at a relaxed cadence. It may be quiet most of the time, and a late check is acceptable. The information lives in the monitor's context, not in a separately named job that must produce a report at a fixed minute.

Automation shape

Use an automation when you want a weekday 09:00 digest of the build system. The schedule, timezone, prompt, isolated session, and run history are all part of the job definition. If the digest is the requirement, this is the default choice I would make.

Webhook shape

Use a webhook when the CI provider can call OpenClaw as soon as a build ends and include the build identifier or status in the payload. The agent can then work on the event that actually occurred. If the provider stops sending requests, there is no webhook run to inspect; add a separate reconciliation schedule only if you genuinely need one.

These are three versions of one task, not three interchangeable product features. A heartbeat optimizes for ambient attention, an automation for operator-owned timing, and a webhook for external event arrival.

Failure paths and a safe rollback

When a heartbeat is late or silent, check whether the Gateway is running, whether automations are disabled, whether active hours exclude the current time, and whether the main queue is busy. Use openclaw system heartbeat last to check the last recorded event. Setting heartbeat.every to "0m" disables the recurring cadence while leaving targeted event-driven wakes available. If the work has become a named recurring job, move it into an automation rather than adding more instructions to the monitor scratch.

When an automation does not fire, follow the documented ladder: check Gateway status, the automation status and list, the job's run history, logs, and then Doctor. Confirm cron.enabled and OPENCLAW_SKIP_CRON, confirm that the Gateway stays up, and check the schedule timezone. Use openclaw automations list --all to find a disabled job. Inspect it with show, correct the cause, and re-enable it with openclaw automations enable <job-id>. Disabling a job is a reversible first rollback; keep the definition while you are still diagnosing instead of removing it.

When a webhook returns an error, read the status before retrying. A 401 points to the hook token or a missing forwarded header. A 400 can mean invalid JSON, routing, session policy, or delivery coordinates. Repeated authentication failures can produce 429, so fix the credential and honor Retry-After. A 503 can mean that single-run admission did not happen within the documented window. A 200 still requires log and session checks because admission is not completion.

To stop an inbound integration, set hooks.enabled to false, restart the Gateway, and rotate the dedicated hook token at the sender. Preserve the last request identifier and logs if you need to explain what happened. Do not paste tokens into the article, a ticket, or a shell history that other operators can read.

The recommendation

Write the trigger in plain language. If it starts with a clock, choose an explicit automation and make the timezone visible. If it starts with "keep an eye on this," heartbeat may fit, provided delay and main-session context are acceptable. If it starts with "when another system tells me," use an inbound webhook and design authentication, payload handling, and duplicate behavior before opening the endpoint.

For the common recurring report, the answer is cron-compatible Automations: one named job, one isolated session, one explicit timezone, and a manual run followed by separate execution and delivery checks. Heartbeat remains useful for ambient awareness. Webhooks remain useful when the clock is outside OpenClaw. Keeping those roles separate makes a missed run easier to explain and a rollback easier to perform.

Sources

Reference Trail

Sources and further reading

  1. automation guidedocs.openclaw.ai
  2. Heartbeat referencedocs.openclaw.ai
  3. schedule referencedocs.openclaw.ai
  4. delivery referencedocs.openclaw.ai
  5. hook configuration referencedocs.openclaw.ai
Back to ArchiveMore: TutorialsNext: OpenClaw v2026.5.9-beta.1: Chat commands, for maintainers