Configuration
Configuration
Section titled “Configuration”OpenClaw reads an optional ~/.openclaw/openclaw.json.
If the file is missing, OpenClaw uses safe defaults. Common reasons to add a config:
- Connect channels and control who can message the bot
- Set models, tools, sandboxing, or automation (cron, hooks)
- Tune sessions, media, networking, or UI
See the full reference for every available field.
Minimal config
Section titled “Minimal config”{ agents: { defaults: { workspace: "~/.openclaw/workspace" } }, channels: { whatsapp: { allowFrom: ["+15555550123"] } },}Editing config
Section titled “Editing config”openclaw onboard # full onboarding flowopenclaw configure # config wizardopenclaw config get agents.defaults.workspaceopenclaw config set agents.defaults.heartbeat.every "2h"openclaw config unset plugins.entries.brave.config.webSearch.apiKeyOpen http://127.0.0.1:18789 and use the Config tab. The Control UI renders a form from the config schema, with a Raw JSON editor as an escape hatch.
Edit ~/.openclaw/openclaw.json directly. The Gateway watches the file and applies changes automatically (see hot reload).
Strict validation
Section titled “Strict validation”When validation fails:
- The Gateway does not boot
- Only diagnostic commands work (
openclaw doctor,openclaw logs,openclaw health,openclaw status) - Run
openclaw doctorto see exact issues - Run
openclaw doctor --fix(or--yes) to apply repairs
Common tasks
Section titled “Common tasks”Set up a channel (WhatsApp, Telegram, Discord, etc.)
Each channel has its own config section under `channels.
`. See the dedicated channel page for setup steps:
- [WhatsApp](/en/channels/whatsapp) — `channels.whatsapp`- [Telegram](/en/channels/telegram) — `channels.telegram`- [Discord](/en/channels/discord) — `channels.discord`- [Slack](/en/channels/slack) — `channels.slack`- [Signal](/en/channels/signal) — `channels.signal`- [iMessage](/en/channels/imessage) — `channels.imessage`- [Google Chat](/en/channels/googlechat) — `channels.googlechat`- [Mattermost](/en/channels/mattermost) — `channels.mattermost`- [Microsoft Teams](/en/channels/msteams) — `channels.msteams`
All channels share the same DM policy pattern:
```json5{ channels: { telegram: { enabled: true, botToken: "123:abc", dmPolicy: "pairing", // pairing | allowlist | open | disabled allowFrom: ["tg:123"], // only for allowlist/open }, },}```Choose and configure models
Set the primary model and optional fallbacks:
{ agents: { defaults: { model: { primary: "anthropic/claude-sonnet-4-6", fallbacks: ["openai/gpt-5.2"], }, models: { "anthropic/claude-sonnet-4-6": { alias: "Sonnet" }, "openai/gpt-5.2": { alias: "GPT" }, }, }, },}agents.defaults.modelsdefines the model catalog and acts as the allowlist for/model.- Model refs use
provider/modelformat (e.g.anthropic/claude-opus-4-6). agents.defaults.imageMaxDimensionPxcontrols transcript/tool image downscaling (default1200); lower values usually reduce vision-token usage on screenshot-heavy runs.- See Models CLI for switching models in chat and Model Failover for auth rotation and fallback behavior.
- For custom/self-hosted providers, see Custom providers in the reference.
Control who can message the bot
DM access is controlled per channel via dmPolicy:
"pairing"(default): unknown senders get a one-time pairing code to approve"allowlist": only senders inallowFrom(or the paired allow store)"open": allow all inbound DMs (requiresallowFrom: ["*"])"disabled": ignore all DMs
For groups, use groupPolicy + groupAllowFrom or channel-specific allowlists.
See the full reference for per-channel details.
Set up group chat mention gating
Group messages default to require mention. Configure patterns per agent:
{ agents: { list: [ { id: "main", groupChat: { mentionPatterns: ["@openclaw", "openclaw"], }, }, ], }, channels: { whatsapp: { groups: { "*": { requireMention: true } }, }, },}- Metadata mentions: native @-mentions (WhatsApp tap-to-mention, Telegram @bot, etc.)
- Text patterns: safe regex patterns in
mentionPatterns - See full reference for per-channel overrides and self-chat mode.
Tune gateway channel health monitoring
Control how aggressively the gateway restarts channels that look stale:
{ gateway: { channelHealthCheckMinutes: 5, channelStaleEventThresholdMinutes: 30, channelMaxRestartsPerHour: 10, }, channels: { telegram: { healthMonitor: { enabled: false }, accounts: { alerts: { healthMonitor: { enabled: true }, }, }, }, },}- Set
gateway.channelHealthCheckMinutes: 0to disable health-monitor restarts globally. channelStaleEventThresholdMinutesshould be greater than or equal to the check interval.- Use `channels.
.healthMonitor.enabledorchannels.
.accounts.
.healthMonitor.enabled` to disable auto-restarts for one channel or account without disabling the global monitor. - See Health Checks for operational debugging and the full reference for all fields.
Configure sessions and resets
Sessions control conversation continuity and isolation:
{ session: { dmScope: "per-channel-peer", // recommended for multi-user threadBindings: { enabled: true, idleHours: 24, maxAgeHours: 0, }, reset: { mode: "daily", atHour: 4, idleMinutes: 120, }, },}dmScope:main(shared) |per-peer|per-channel-peer|per-account-channel-peerthreadBindings: global defaults for thread-bound session routing (Discord supports/focus,/unfocus,/agents,/session idle, and/session max-age).- See Session Management for scoping, identity links, and send policy.
- See full reference for all fields.
Enable sandboxing
Run agent sessions in isolated Docker containers:
{ agents: { defaults: { sandbox: { mode: "non-main", // off | non-main | all scope: "agent", // session | agent | shared }, }, },}Build the image first: scripts/sandbox-setup.sh
See Sandboxing for the full guide and full reference for all options.
Enable relay-backed push for official iOS builds
Relay-backed push is configured in openclaw.json.
Set this in gateway config:
{ gateway: { push: { apns: { relay: { baseUrl: "https://relay.example.com", // Optional. Default: 10000 timeoutMs: 10000, }, }, }, },}CLI equivalent:
openclaw config set gateway.push.apns.relay.baseUrl https://relay.example.comWhat this does:
- Lets the gateway send
push.test, wake nudges, and reconnect wakes through the external relay. - Uses a registration-scoped send grant forwarded by the paired iOS app. The gateway does not need a deployment-wide relay token.
- Binds each relay-backed registration to the gateway identity that the iOS app paired with, so another gateway cannot reuse the stored registration.
- Keeps local/manual iOS builds on direct APNs. Relay-backed sends apply only to official distributed builds that registered through the relay.
- Must match the relay base URL baked into the official/TestFlight iOS build, so registration and send traffic reach the same relay deployment.
End-to-end flow:
- Install an official/TestFlight iOS build that was compiled with the same relay base URL.
- Configure
gateway.push.apns.relay.baseUrlon the gateway. - Pair the iOS app to the gateway and let both node and operator sessions connect.
- The iOS app fetches the gateway identity, registers with the relay using App Attest plus the app receipt, and then publishes the relay-backed
push.apns.registerpayload to the paired gateway. - The gateway stores the relay handle and send grant, then uses them for
push.test, wake nudges, and reconnect wakes.
Operational notes:
- If you switch the iOS app to a different gateway, reconnect the app so it can publish a new relay registration bound to that gateway.
- If you ship a new iOS build that points at a different relay deployment, the app refreshes its cached relay registration instead of reusing the old relay origin.
Compatibility note:
OPENCLAW_APNS_RELAY_BASE_URLandOPENCLAW_APNS_RELAY_TIMEOUT_MSstill work as temporary env overrides.OPENCLAW_APNS_RELAY_ALLOW_HTTP=trueremains a loopback-only development escape hatch; do not persist HTTP relay URLs in config.
See iOS App for the end-to-end flow and Authentication and trust flow for the relay security model.
Set up heartbeat (periodic check-ins)
{ agents: { defaults: { heartbeat: { every: "30m", target: "last", }, }, },}every: duration string (30m,2h). Set0mto disable.target:last|none| `
(for examplediscord, matrix, telegram, or whatsapp) - directPolicy: allow(default) orblock` for DM-style heartbeat targets
- See Heartbeat for the full guide.
Configure cron jobs
{ cron: { enabled: true, maxConcurrentRuns: 2, sessionRetention: "24h", runLog: { maxBytes: "2mb", keepLines: 2000, }, },}sessionRetention: prune completed isolated run sessions fromsessions.json(default24h; setfalseto disable).runLog: prune `cron/runs/
.jsonl` by size and retained lines. - See Cron jobs for feature overview and CLI examples.
Set up webhooks (hooks)
Enable HTTP webhook endpoints on the Gateway:
{ hooks: { enabled: true, token: "shared-secret", path: "/hooks", defaultSessionKey: "hook:ingress", allowRequestSessionKey: false, allowedSessionKeyPrefixes: ["hook:"], mappings: [ { match: { path: "gmail" }, action: "agent", agentId: "main", deliver: true, }, ], },}Security note:
- Treat all hook/webhook payload content as untrusted input.
- Keep unsafe-content bypass flags disabled (
hooks.gmail.allowUnsafeExternalContent,hooks.mappings[].allowUnsafeExternalContent) unless doing tightly scoped debugging. - For hook-driven agents, prefer strong modern model tiers and strict tool policy (for example messaging-only plus sandboxing where possible).
See full reference for all mapping options and Gmail integration.
Configure multi-agent routing
Run multiple isolated agents with separate workspaces and sessions:
{ agents: { list: [ { id: "home", default: true, workspace: "~/.openclaw/workspace-home" }, { id: "work", workspace: "~/.openclaw/workspace-work" }, ], }, bindings: [ { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } }, { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } }, ],}See Multi-Agent and full reference for binding rules and per-agent access profiles.
Split config into multiple files ($include)
Use $include to organize large configs:
{ gateway: { port: 18789 }, agents: { $include: "./agents.json5" }, broadcast: { $include: ["./clients/a.json5", "./clients/b.json5"], },}- Single file: replaces the containing object
- Array of files: deep-merged in order (later wins)
- Sibling keys: merged after includes (override included values)
- Nested includes: supported up to 10 levels deep
- Relative paths: resolved relative to the including file
- Error handling: clear errors for missing files, parse errors, and circular includes
Config hot reload
Section titled “Config hot reload”The Gateway watches ~/.openclaw/openclaw.json and applies changes automatically — no manual restart needed for most settings.
Reload modes
Section titled “Reload modes”| Mode | Behavior |
|---|---|
hybrid (default) | Hot-applies safe changes instantly. Automatically restarts for critical ones. |
hot | Hot-applies safe changes only. Logs a warning when a restart is needed — you handle it. |
restart | Restarts the Gateway on any config change, safe or not. |
off | Disables file watching. Changes take effect on the next manual restart. |
{ gateway: { reload: { mode: "hybrid", debounceMs: 300 }, },}What hot-applies vs what needs a restart
Section titled “What hot-applies vs what needs a restart”Most fields hot-apply without downtime. In hybrid mode, restart-required changes are handled automatically.
| Category | Fields | Restart needed? |
|---|---|---|
| Channels | channels.*, web (WhatsApp) — all built-in and extension channels | No |
| Agent & models | agent, agents, models, routing | No |
| Automation | hooks, cron, agent.heartbeat | No |
| Sessions & messages | session, messages | No |
| Tools & media | tools, browser, skills, audio, talk | No |
| UI & misc | ui, logging, identity, bindings | No |
| Gateway server | gateway.* (port, bind, auth, tailscale, TLS, HTTP) | Yes |
| Infrastructure | discovery, canvasHost, plugins | Yes |
Config RPC (programmatic updates)
Section titled “Config RPC (programmatic updates)”config.apply (full replace)
Validates + writes the full config and restarts the Gateway in one step.
Params:
raw(string) — JSON5 payload for the entire configbaseHash(optional) — config hash fromconfig.get(required when config exists)sessionKey(optional) — session key for the post-restart wake-up pingnote(optional) — note for the restart sentinelrestartDelayMs(optional) — delay before restart (default 2000)
Restart requests are coalesced while one is already pending/in-flight, and a 30-second cooldown applies between restart cycles.
openclaw gateway call config.get --params '{}' # capture payload.hashopenclaw gateway call config.apply --params '{ "raw": "{ agents: { defaults: { workspace: \"~/.openclaw/workspace\" } } }", "baseHash": "”, “sessionKey”: “agent:main:whatsapp:direct:+15555550123” }’ ```
config.patch (partial update)
Merges a partial update into the existing config (JSON merge patch semantics):
- Objects merge recursively
nulldeletes a key- Arrays replace
Params:
raw(string) — JSON5 with just the keys to changebaseHash(required) — config hash fromconfig.getsessionKey,note,restartDelayMs— same asconfig.apply
Restart behavior matches config.apply: coalesced pending restarts plus a 30-second cooldown between restart cycles.
openclaw gateway call config.patch --params '{ "raw": "{ channels: { telegram: { groups: { \"*\": { requireMention: false } } } } }", "baseHash": "” }’ ```
Environment variables
Section titled “Environment variables”OpenClaw reads env vars from the parent process plus:
.envfrom the current working directory (if present)~/.openclaw/.env(global fallback)
Neither file overrides existing env vars. You can also set inline env vars in config:
{ env: { OPENROUTER_API_KEY: "sk-or-...", vars: { GROQ_API_KEY: "gsk-..." }, },}Shell env import (optional)
If enabled and expected keys aren’t set, OpenClaw runs your login shell and imports only the missing keys:
{ env: { shellEnv: { enabled: true, timeoutMs: 15000 }, },}Env var equivalent: OPENCLAW_LOAD_SHELL_ENV=1
Env var substitution in config values
Reference env vars in any config string value with ${VAR_NAME}:
{ gateway: { auth: { token: "${OPENCLAW_GATEWAY_TOKEN}" } }, models: { providers: { custom: { apiKey: "${CUSTOM_API_KEY}" } } },}Rules:
- Only uppercase names matched:
[A-Z_][A-Z0-9_]* - Missing/empty vars throw an error at load time
- Escape with
$${VAR}for literal output - Works inside
$includefiles - Inline substitution:
"${BASE}/v1"→"https://api.example.com/v1"
Secret refs (env, file, exec)
For fields that support SecretRef objects, you can use:
{ models: { providers: { openai: { apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" } }, }, }, skills: { entries: { "image-lab": { apiKey: { source: "file", provider: "filemain", id: "/skills/entries/image-lab/apiKey", }, }, }, }, channels: { googlechat: { serviceAccountRef: { source: "exec", provider: "vault", id: "channels/googlechat/serviceAccount", }, }, },}SecretRef details (including secrets.providers for env/file/exec) are in Secrets Management.
Supported credential paths are listed in SecretRef Credential Surface.
See Environment for full precedence and sources.
Full reference
Section titled “Full reference”For the complete field-by-field reference, see Configuration Reference.
Related: Configuration Examples · Configuration Reference · Doctor