Hooks are one of OpenClaw's most powerful and least-documented features. They let you intercept events in the agent lifecycle and trigger any action you want — without going through the AI at all.
How Hooks Work
OpenClaw emits events at key points in its operation. You register hooks that fire when those events occur.
# ~/.openclaw/config/hooks.yml
hooks:
- event: "message.received"
action: "shell"
command: "echo 'New message received' >> /tmp/openclaw.log"
- event: "action.completed"
action: "http"
url: "https://your-webhook.com/notify"
method: "POST"
Hooks execute asynchronously — they don't block OpenClaw's main response flow unless you configure them to.
Available Hook Events
Message Events
| Event | Fires When |
|---|---|
message.received | Any new incoming message (any platform) |
message.sent | OpenClaw sends a reply |
message.from.{platform} | Message from a specific platform (e.g. message.from.telegram) |
message.from.{contact} | Message from a specific contact |
Action Events
| Event | Fires When |
|---|---|
action.started | AI begins executing a tool/integration |
action.completed | Tool/integration call completes successfully |
action.failed | Tool/integration call fails |
action.{type} | Specific action type (e.g. action.gmail.send) |
Session Events
| Event | Fires When |
|---|---|
session.start | OpenClaw process starts |
session.shutdown | OpenClaw is shutting down |
memory.stored | A new memory is written |
memory.recalled | A memory is retrieved |
Scheduled Events
| Event | Fires When |
|---|---|
schedule.{name} | A named scheduled task fires |
Hook Action Types
Shell Command
hooks:
- event: "message.received"
action: "shell"
command: "notify-send 'OpenClaw' 'New message received'"
# On Linux with libnotify — desktop notification
Pass event data to the command with template variables:
- event: "message.received"
action: "shell"
command: "python3 /home/user/scripts/log-message.py '{{message.text}}' '{{message.from}}'"
Security note: Sanitise any user-provided content before passing to shell commands. Never pass raw message text directly to shell without escaping.
HTTP Webhook
hooks:
- event: "action.completed"
action: "http"
url: "https://hooks.zapier.com/hooks/catch/your-zap-id/"
method: "POST"
headers:
Content-Type: "application/json"
body:
event: "{{event.type}}"
action: "{{action.name}}"
timestamp: "{{event.timestamp}}"
Internal OpenClaw Action
hooks:
- event: "message.from.telegram"
action: "internal"
function: "log_to_memory"
params:
key: "telegram_activity"
value: "{{message.text}}"
Practical Hook Examples
Desktop Notification on New Message (Linux/macOS)
hooks:
- event: "message.received"
action: "shell"
command: "notify-send 'OpenClaw' 'Message from {{message.from}}'"
platform_filter: ["whatsapp", "telegram"]
Log All LLM Calls to a File
hooks:
- event: "llm.request"
action: "shell"
command: |
echo "$(date): {{llm.model}} — {{llm.token_count}} tokens" >> ~/.openclaw/llm-usage.log
Useful for tracking token consumption and model usage over time.
Alert When Actions Fail
hooks:
- event: "action.failed"
action: "http"
url: "https://your-slack-webhook/notify"
body:
text: "OpenClaw action failed: {{action.name}} — {{error.message}}"
Daily Activity Summary to a File
hooks:
- event: "schedule.daily_wrap"
action: "shell"
command: "openclaw memory export --date today >> ~/openclaw-daily-log.txt"
Pair with a schedule:
scheduled_tasks:
- name: "daily_wrap"
cron: "0 22 * * *" # 10pm daily
Auto-Archive Completed Tasks to Notion
hooks:
- event: "action.notion.page_updated"
action: "shell"
command: "python3 ~/scripts/notion-archive.py '{{action.page_id}}' '{{action.status}}'"
Sync Memory to Git
hooks:
- event: "memory.stored"
action: "shell"
command: |
cd ~/.openclaw/memory && git add . && git commit -m "Memory update $(date)" --quiet
async: true
max_frequency: "5m" # Rate-limit to max once every 5 minutes
Hook Filters
Narrow which events trigger a hook with filters:
hooks:
- event: "message.received"
filters:
platform: "whatsapp" # Only WhatsApp messages
contains: "urgent" # Only if message contains "urgent"
from: "+1234567890" # Only from specific contact
action: "shell"
command: "afplay /System/Library/Sounds/Glass.aiff" # Play a sound on Mac
Debugging Hooks
# See hook execution logs
openclaw logs --filter hooks
# Test a hook manually
openclaw hooks test message.received --payload '{"text": "test", "from": "test@test.com"}'
# List all registered hooks
openclaw hooks list
Hook Ordering and Error Handling
By default, hooks run asynchronously and don't affect OpenClaw's main operation if they fail. For critical hooks:
hooks:
- event: "action.gmail.send"
action: "shell"
command: "~/scripts/log-email-sent.sh"
sync: true # Block until hook completes
on_failure: "abort" # Abort the action if hook fails
timeout: 5 # Seconds before hook times out
Use sync: true and on_failure: "abort" sparingly — a slow or failing hook will block OpenClaw's response.
Related reading: