Skip to content

Connect Matrix to OpenClaw: Setup Guide

Matrix is a bundled channel plugin for OpenClaw that brings your bot into the Matrix network. It uses the official matrix-js-sdk and supports DMs, rooms, threads, media, reactions, polls, location, and E2EE.

Matrix comes pre-installed with most OpenClaw versions, so you usually do not have to worry about extra installation steps. If you are running a custom setup or an older version that excludes it, you can easily add it using the CLI.

  1. Install from npm:
Terminal window
openclaw plugins install @openclaw/matrix
  1. Install from a local checkout:
Terminal window
openclaw plugins install ./path/to/local/matrix-plugin

You can check the Plugins documentation for more details on how plugins behave and the rules for installing them.

Getting your bot online requires connecting it to a homeserver and choosing how you want to handle authentication. You can use either an access token or a password to get things moving and decide how the bot should handle room invites.

  1. Ensure the Matrix plugin is available. Current packaged OpenClaw releases already bundle it, but older or custom installs can add it manually with the commands above.
  2. Create a Matrix account on your homeserver.
  3. Configure channels.matrix with either homeserver + accessToken, or homeserver + userId + password.
  4. Restart the Gateway.
  5. Start a DM with the bot or invite it to a room. Fresh Matrix invites only work when channels.matrix.autoJoin allows them.

You can also use these interactive setup paths:

Terminal window
openclaw channels add
openclaw configure --section channels

The Matrix wizard will ask you for:

  1. homeserver URL
  2. Auth method: access token or password
  3. User ID (password auth only)
  4. Optional device name
  5. Whether to enable E2EE
  6. Whether to configure room access and invite auto-join

There are a few key wizard behaviors to keep in mind:

  1. If Matrix auth env vars already exist and that account does not already have auth saved in config, the wizard offers an env shortcut to keep auth in env vars.
  2. Account names are normalized to the account ID. For example, Ops Bot becomes ops-bot.
  3. DM allowlist entries accept @user:server directly; display names only work when live directory lookup finds one exact match.
  4. Room allowlist entries accept room IDs and aliases directly. You should prefer !room:server or #alias:server because unresolved names are ignored at runtime by allowlist resolution.
  5. In invite auto-join allowlist mode, use only stable invite targets like !roomId:server, #alias:server, or *. Plain room names are rejected.
  6. To resolve room names before saving, use openclaw channels resolve --channel matrix "Project Room".

Warning channels.matrix.autoJoin defaults to off.

If you leave it unset, the bot will not join invited rooms or fresh DM-style invites, so it will not appear in new groups or invited DMs unless you join manually first.

Set autoJoin: "allowlist" together with autoJoinAllowlist to restrict which invites it accepts, or set autoJoin: "always" if you want it to join every invite.

In allowlist mode, autoJoinAllowlist only accepts !roomId:server, #alias:server, or *.

Here is an allowlist example:

{
channels: {
matrix: {
autoJoin: "allowlist",
autoJoinAllowlist: ["!ops:example.org", "#support:example.org"],
groups: {
"!ops:example.org": {
requireMention: true,
},
},
},
},
}

If you want the bot to join every invite:

{
channels: {
matrix: {
autoJoin: "always",
},
},
}

For a minimal token-based setup:

{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
accessToken: "syt_xxx",
dm: { policy: "pairing" },
},
},
}

For a password-based setup (the token is cached after login):

{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
userId: "@bot:example.org",
password: "replace-me", // pragma: allowlist secret
deviceName: "OpenClaw Gateway",
},
},
}

Matrix stores cached credentials in ~/.openclaw/credentials/matrix/. The default account uses credentials.json, while named accounts use credentials-<account>.json. When cached credentials exist there, OpenClaw treats Matrix as configured for setup, doctor, and channel-status discovery even if current auth is not set directly in config.

You can also use environment variable equivalents when the config key is not set:

  1. MATRIX_HOMESERVER
  2. MATRIX_ACCESS_TOKEN
  3. MATRIX_USER_ID
  4. MATRIX_PASSWORD
  5. MATRIX_DEVICE_ID
  6. MATRIX_DEVICE_NAME

For non-default accounts, use account-scoped env vars:

  1. MATRIX_<ACCOUNT_ID>_HOMESERVER
  2. MATRIX_<ACCOUNT_ID>_ACCESS_TOKEN
  3. MATRIX_<ACCOUNT_ID>_USER_ID
  4. MATRIX_<ACCOUNT_ID>_PASSWORD

For example, for an account named ops, you would use MATRIX_OPS_HOMESERVER and MATRIX_OPS_ACCESS_TOKEN. For a normalized account ID like ops-bot, use MATRIX_OPS_X2D_BOT_HOMESERVER. Matrix escapes punctuation in account IDs to keep scoped env vars collision-free, so - becomes _X2D_.

The interactive wizard only offers the env-var shortcut when those auth env vars are already present and the selected account does not already have Matrix auth saved in config.

You can use this practical configuration to get your bot running with encryption and specific room rules. It is a great starting point for most users who need a balance of security and functionality.

{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
accessToken: "syt_xxx",
encryption: true,
dm: {
policy: "pairing",
sessionScope: "per-room",
threadReplies: "off",
},
groupPolicy: "allowlist",
groupAllowFrom: ["@admin:example.org"],
groups: {
"!roomid:example.org": {
requireMention: true,
},
},
autoJoin: "allowlist",
autoJoinAllowlist: ["!roomid:example.org"],
threadReplies: "inbound",
replyToMode: "off",
streaming: "partial",
},
},
}

Note that autoJoin applies to all Matrix invites, including DM-style invites. OpenClaw cannot reliably classify an invited room as a DM or group at invite time, so all invites go through autoJoin first. The dm.policy setting applies after the bot has joined and the room is classified as a DM.

You can make your bot feel more alive by enabling streaming, which shows the text as it is being generated by the model. This section explains how to set that up and how to handle notifications for these live updates.

{
channels: {
matrix: {
streaming: "partial",
},
},
}

There are several streaming modes you can choose from:

  1. streaming: "off" is the default. OpenClaw waits for the final reply and sends it once.
  2. streaming: "partial" creates one editable preview message for the current assistant block using normal Matrix text messages. This preserves legacy preview-first notification behavior.
  3. streaming: "quiet" creates one editable quiet preview notice. Use this only when you also configure recipient push rules for finalized preview edits.
  4. blockStreaming: true enables separate Matrix progress messages. With preview streaming enabled, Matrix keeps the live draft for the current block and preserves completed blocks as separate messages.

When preview streaming is on and blockStreaming is off, Matrix edits the live draft in place and finalizes that same event when the block or turn finishes. If the preview no longer fits in one Matrix event, OpenClaw stops preview streaming and falls back to normal final delivery. Media replies still send attachments normally, and if a stale preview can no longer be reused safely, OpenClaw redacts it before sending the final media reply.

Preview edits cost extra Matrix API calls. You should leave streaming off if you want the most conservative rate-limit behavior. Also, blockStreaming does not enable draft previews by itself; you must use streaming: "partial" or streaming: "quiet" for preview edits.

Self-hosted push rules for quiet finalized previews

Section titled “Self-hosted push rules for quiet finalized previews”

If you run your own Matrix infrastructure and want quiet previews to notify only when a block or final reply is done, you can set streaming: "quiet" and add a per-user push rule. This is usually a recipient-user setup, not a homeserver-global config change.

  1. Configure OpenClaw to use quiet previews in your JSON config.
  2. Make sure the recipient account already receives normal Matrix push notifications.
  3. Get the recipient user’s access token. You should use the receiving user’s token, not the bot’s token. You can log in through the standard Matrix Client-Server API:
Terminal window
curl -sS -X POST \
"https://matrix.example.org/_matrix/client/v3/login" \
-H "Content-Type: application/json" \
--data '{
"type": "m.login.password",
"identifier": {
"type": "m.id.user",
"user": "@alice:example.org"
},
"password": "REDACTED"
}'
  1. Verify the recipient account already has pushers:
Terminal window
curl -sS \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
"https://matrix.example.org/_matrix/client/v3/pushers"
  1. Create an override push rule for each recipient account. OpenClaw marks finalized text-only preview edits with a specific JSON flag.
Terminal window
curl -sS -X PUT \
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview-botname" \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"conditions": [
{ "kind": "event_match", "key": "type", "pattern": "m.room.message" },
{
"kind": "event_property_is",
"key": "content.m\\.relates_to.rel_type",
"value": "m.replace"
},
{
"kind": "event_property_is",
"key": "content.com\\.openclaw\\.finalized_preview",
"value": true
},
{ "kind": "event_match", "key": "sender", "pattern": "@bot:example.org" }
],
"actions": [
"notify",
{ "set_tweak": "sound", "value": "default" },
{ "set_tweak": "highlight", "value": false }
]
}'
  1. Verify the rule exists:
Terminal window
curl -sS \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview-botname"
  1. Test a streamed reply. In quiet mode, the room should show a quiet draft preview and the final in-place edit should notify once the block or turn finishes.

If you need to remove the rule later, delete that same rule ID:

Terminal window
curl -sS -X DELETE \
-H "Authorization: Bearer $USER_ACCESS_TOKEN" \
"https://matrix.example.org/_matrix/client/v3/pushrules/global/override/openclaw-finalized-preview-botname"

For Synapse, the setup above is usually enough by itself. No special homeserver.yaml change is required for finalized OpenClaw preview notifications. If your Synapse deployment already sends normal Matrix push notifications, the user token and pushrules call are the main setup steps. Make sure pushers are healthy if you run Synapse workers.

For Tuwunel, use the same setup flow and push-rule API call shown above. No Tuwunel-specific config is required for the finalized preview marker itself. If notifications seem to disappear while the user is active on another device, check whether suppress_push_when_active is enabled, as this can intentionally suppress pushes to other devices.

When you’re setting up OpenClaw for Matrix, you might want to enable Bot-to-bot communication between your agents. By default, the system ignores messages from other configured accounts to prevent infinite loops, but you can customize this behavior easily.

Use allowBots when you intentionally want inter-agent Matrix traffic:

{
channels: {
matrix: {
allowBots: "mentions", // true | "mentions"
groups: {
"!roomid:example.org": {
requireMention: true,
},
},
},
},
}
  1. allowBots: true accepts messages from other configured Matrix bot accounts in allowed rooms and DMs.
  2. allowBots: "mentions" accepts those messages only when they visibly mention this bot in rooms. DMs are still allowed.
  3. groups.<room>.allowBots overrides the account-level setting for one room.
  4. OpenClaw still ignores messages from the same Matrix user ID to avoid self-reply loops.
  5. Matrix does not expose a native bot flag here; OpenClaw treats “bot-authored” as “sent by another configured Matrix account on this OpenClaw Gateway”.

Use strict room allowlists and mention requirements when enabling bot-to-bot traffic in shared rooms.

Keeping your conversations private is a top priority, and OpenClaw handles E2EE rooms with a lot of automation. It automatically detects if a room is encrypted and adjusts how it handles things like image thumbnails.

In encrypted (E2EE) rooms, outbound image events use thumbnail_file so image previews are encrypted alongside the full attachment. Unencrypted rooms still use plain thumbnail_url. No configuration is needed — the plugin detects E2EE state automatically.

Enable encryption:

{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
accessToken: "syt_xxx",
encryption: true,
dm: { policy: "pairing" },
},
},
}

Check verification status:

Terminal window
openclaw matrix verify status

Verbose status (full diagnostics):

Terminal window
openclaw matrix verify status --verbose

Include the stored recovery key in machine-readable output:

Terminal window
openclaw matrix verify status --include-recovery-key --json

Bootstrap cross-signing and verification state:

Terminal window
openclaw matrix verify bootstrap

Verbose bootstrap diagnostics:

Terminal window
openclaw matrix verify bootstrap --verbose

Force a fresh cross-signing identity reset before bootstrapping:

Terminal window
openclaw matrix verify bootstrap --force-reset-cross-signing

Verify this device with a recovery key:

Terminal window
openclaw matrix verify device "<your-recovery-key>"

Verbose device verification details:

Terminal window
openclaw matrix verify device "<your-recovery-key>" --verbose

Check room-key backup health:

Terminal window
openclaw matrix verify backup status

Verbose backup health diagnostics:

Terminal window
openclaw matrix verify backup status --verbose

Restore room keys from server backup:

Terminal window
openclaw matrix verify backup restore

Verbose restore diagnostics:

Terminal window
openclaw matrix verify backup restore --verbose

Delete the current server backup and create a fresh backup baseline. If the stored backup key cannot be loaded cleanly, this reset can also recreate secret storage so future cold starts can load the new backup key:

Terminal window
openclaw matrix verify backup reset --yes

All verify commands are concise by default (including quiet internal SDK logging) and show detailed diagnostics only with --verbose. Use --json for full machine-readable output when scripting.

In multi-account setups, Matrix CLI commands use the implicit Matrix default account unless you pass --account <id>. If you configure multiple named accounts, set channels.matrix.defaultAccount first or those implicit CLI operations will stop and ask you to choose an account explicitly. Use --account whenever you want verification or device operations to target a named account explicitly:

Terminal window
openclaw matrix verify status --account assistant
openclaw matrix verify backup restore --account assistant
openclaw matrix devices list --account assistant

When encryption is disabled or unavailable for a named account, Matrix warnings and verification errors point at that account’s config key, for example channels.matrix.accounts.assistant.encryption.

OpenClaw treats this Matrix device as verified only when it is verified by your own cross-signing identity. In practice, openclaw matrix verify status --verbose exposes four trust signals:

  1. Locally trusted: this device is trusted by the current client only.
  2. Cross-signing verified: the SDK reports the device as verified through cross-signing.
  3. Signed by owner: the device is signed by your own self-signing key.
  4. Verified by owner: this becomes yes only when cross-signing verification or owner-signing is present. Local trust by itself is not enough for OpenClaw to treat the device as fully verified.

openclaw matrix verify bootstrap is the repair and setup command for encrypted Matrix accounts. It performs the following actions in order:

  1. bootstraps secret storage, reusing an existing recovery key when possible.
  2. bootstraps cross-signing and uploads missing public cross-signing keys.
  3. attempts to mark and cross-sign the current device.
  4. creates a new server-side room-key backup if one does not already exist.

If the homeserver requires interactive auth to upload cross-signing keys, OpenClaw tries the upload without auth first, then with m.login.dummy, then with m.login.password when channels.matrix.password is configured. Use --force-reset-cross-signing only when you intentionally want to discard the current cross-signing identity and create a new one.

If you intentionally want to discard the current room-key backup and start a new backup baseline for future messages, use openclaw matrix verify backup reset --yes. Do this only when you accept that unrecoverable old encrypted history will stay unavailable and that OpenClaw may recreate secret storage if the current backup secret cannot be loaded safely.

If you want to keep future encrypted messages working and accept losing unrecoverable old history, run these commands in order:

Terminal window
openclaw matrix verify backup reset --yes
openclaw matrix verify backup status --verbose
openclaw matrix verify status

Add --account <id> to each command when you want to target a named Matrix account explicitly.

When encryption: true, Matrix defaults startupVerification to "if-unverified". On startup, if this device is still unverified, Matrix will request self-verification in another Matrix client, skip duplicate requests while one is already pending, and apply a local cooldown before retrying after restarts. Failed request attempts retry sooner than successful request creation by default. Set startupVerification: "off" to disable automatic startup requests, or tune startupVerificationCooldownHours if you want a shorter or longer retry window.

Startup also performs a conservative crypto bootstrap pass automatically. That pass tries to reuse the current secret storage and cross-signing identity first, and avoids resetting cross-signing unless you run an explicit bootstrap repair flow. If startup still finds broken bootstrap state, OpenClaw can attempt a guarded repair path even when channels.matrix.password is not configured. If the homeserver requires password-based UIA for that repair, OpenClaw logs a warning and keeps startup non-fatal instead of aborting the bot. If the current device is already owner-signed, OpenClaw preserves that identity instead of resetting it automatically.

See Matrix migration for the full upgrade flow, limits, recovery commands, and common migration messages.

Matrix posts verification lifecycle notices directly into the strict DM verification room as m.notice messages. This includes:

  1. verification request notices.
  2. verification ready notices (with explicit “Verify by emoji” guidance).
  3. verification start and completion notices.
  4. SAS details (emoji and decimal) when available.

Incoming verification requests from another Matrix client are tracked and auto-accepted by OpenClaw. For self-verification flows, OpenClaw also starts the SAS flow automatically when emoji verification becomes available and confirms its own side. For verification requests from another Matrix user/device, OpenClaw auto-accepts the request and then waits for the SAS flow to proceed normally. You still need to compare the emoji or decimal SAS in your Matrix client and confirm “They match” there to complete the verification. OpenClaw does not auto-accept self-initiated duplicate flows blindly. Startup skips creating a new request when a self-verification request is already pending. Verification protocol/system notices are not forwarded to the agent chat pipeline, so they do not produce NO_REPLY.

Old OpenClaw-managed Matrix devices can accumulate on the account and make encrypted-room trust harder to reason about. List them with:

Terminal window
openclaw matrix devices list

Remove stale OpenClaw-managed devices with:

Terminal window
openclaw matrix devices prune-stale

Matrix E2EE uses the official matrix-js-sdk Rust crypto path in Node.js, with fake-indexeddb as the IndexedDB shim. Crypto state is persisted to a snapshot file (crypto-idb-snapshot.json) and restored on startup. The snapshot file is sensitive runtime state stored with restrictive file permissions.

Encrypted runtime state lives under per-account, per-user token-hash roots in ~/.openclaw/matrix/accounts/<account>/<homeserver>__<user>/<token-hash>/. This directory contains the sync store (bot-storage.json), crypto store (crypto/), recovery key file (recovery-key.json), IndexedDB snapshot (crypto-idb-snapshot.json), thread bindings (thread-bindings.json), and startup verification state (startup-verification.json). When the token changes but the account identity stays the same, OpenClaw reuses the best existing root for that account/homeserver/user tuple so prior sync state, crypto state, thread bindings, and startup verification state remain visible.

Making your bot look the part is important for a good user experience. You can update your bot’s name and avatar directly from the CLI without digging into complex settings.

Update the Matrix self-profile for the selected account with:

Terminal window
openclaw matrix profile set --name "OpenClaw Assistant"
openclaw matrix profile set --avatar-url https://cdn.example.org/avatar.png

Add --account <id> when you want to target a named Matrix account explicitly. Matrix accepts mxc:// avatar URLs directly. When you pass an http:// or https:// avatar URL, OpenClaw uploads it to Matrix first and stores the resolved mxc:// URL back into channels.matrix.avatarUrl (or the selected account override).

Keeping track of multiple conversations in a single room can get messy fast. OpenClaw supports native Matrix threads to keep your agent’s replies organized and context-aware.

  1. dm.sessionScope: "per-user" (default) keeps Matrix DM routing sender-scoped, so multiple DM rooms can share one session when they resolve to the same peer.
  2. dm.sessionScope: "per-room" isolates each Matrix DM room into its own session key while still using normal DM auth and allowlist checks.
  3. Explicit Matrix conversation bindings still win over dm.sessionScope, so bound rooms and threads keep their chosen target session.
  4. threadReplies: "off" keeps replies top-level and keeps inbound threaded messages on the parent session.
  5. threadReplies: "inbound" replies inside a thread only when the inbound message was already in that thread.
  6. threadReplies: "always" keeps room replies in a thread rooted at the triggering message and routes that conversation through the matching thread-scoped session from the first triggering message.
  7. dm.threadReplies overrides the top-level setting for DMs only. For example, you can keep room threads isolated while keeping DMs flat.
  8. Inbound threaded messages include the thread root message as extra agent context.
  9. Message-tool sends auto-inherit the current Matrix thread when the target is the same room, or the same DM user target, unless an explicit threadId is provided.
  10. Same-session DM user-target reuse only kicks in when the current session metadata proves the same DM peer on the same Matrix account; otherwise OpenClaw falls back to normal user-scoped routing.
  11. When OpenClaw sees a Matrix DM room collide with another DM room on the same shared Matrix DM session, it posts a one-time m.notice in that room with the /focus escape hatch when thread bindings are enabled and the dm.sessionScope hint.
  12. Runtime thread bindings are supported for Matrix. /focus, /unfocus, /agents, /session idle, /session max-age, and thread-bound /acp spawn work in Matrix rooms and DMs.
  13. Top-level Matrix room/DM /focus creates a new Matrix thread and binds it to the target session when threadBindings.spawnSubagentSessions=true.
  14. Running /focus or /acp spawn --thread here inside an existing Matrix thread binds that current thread instead.

OpenClaw ACP conversation bindings allow you to turn Matrix rooms, DMs, and existing threads into durable workspaces without changing where you chat. This keeps your workflow in one place while giving you the power of a full session.

  1. Run the CLI command /acp spawn codex --bind here inside the Matrix DM, room, or thread you want to use.
  2. If you are in a top-level DM or room, the current surface stays active and future messages route to the spawned session.
  3. If you are inside a thread, the --bind here flag binds that specific thread in place.
  4. Use /new and /reset to clear the bound session in place.
  5. Use /acp close to end the session and remove the binding.

Note that --bind here does not create a child Matrix thread. You only need threadBindings.spawnAcpSessions for /acp spawn --thread auto|here where OpenClaw creates or binds a child thread. Matrix inherits global defaults from session.threadBindings, and also supports per-channel overrides like threadBindings.enabled, threadBindings.idleHours, threadBindings.maxAgeHours, and threadBindings.spawnSubagentSessions. Matrix thread-bound spawn flags are opt-in. You should set threadBindings.spawnSubagentSessions: true to allow top-level /focus to create and bind new Matrix threads. Set threadBindings.spawnAcpSessions: true to allow /acp spawn --thread auto|here to bind sessions to Matrix threads.

Matrix supports outbound reaction actions, inbound notifications, and automated ack reactions to keep you informed. You can configure how OpenClaw handles these interactions through the channel settings.

  1. Control outbound reaction tooling via channels[“matrix”].actions.reactions.
  2. Use react to add a reaction to a specific Matrix event.
  3. Use reactions to list the current summary for an event.
  4. Set emoji="" to remove the bot account’s own reactions.
  5. Set remove: true to remove a specific emoji.

Ack reactions follow a resolution order starting from channels[“matrix”].accounts.<accountId>.ackReaction, then channels[“matrix”].ackReaction, then messages.ackReaction, and finally the agent identity emoji. The scope also resolves from the specific account down to the global message settings using ackReactionScope. For notifications, the default is own, which forwards m.reaction events targeting the bot’s messages. You can set reactionNotifications to off to disable these system events. Reaction removals are not synthesized into system events because Matrix surfaces those as redactions rather than standalone removals.

OpenClaw Matrix history settings determine how many recent messages are sent to the agent as context. This ensures the bot understands the conversation flow before it was triggered.

  1. Use channels.matrix.historyLimit to set the number of recent room messages included as InboundHistory.
  2. If this is unset, it falls back to messages.groupChat.historyLimit, or defaults to 0.
  3. Remember that Matrix room history is room-only, while DMs use normal session history.
  4. History is pending-only; OpenClaw buffers messages that haven’t triggered a reply and snapshots them when a mention occurs.

The trigger message itself is not in InboundHistory but stays in the main inbound body. If an event is retried, OpenClaw reuses the original history snapshot to prevent context drift. Setting the limit to 0 will disable this feature entirely.

The contextVisibility setting gives you control over supplemental room context like reply text and pending history. This is useful for maintaining privacy or focus within a shared Matrix room.

  1. Set contextVisibility: “all” to keep all supplemental context as received.
  2. Use contextVisibility: “allowlist” to filter context so it only includes senders who pass allowlist checks.
  3. Use contextVisibility: “allowlist_quote” to filter like the allowlist but keep one explicit quoted reply.

This setting only changes what the agent sees in the context, not whether a message can trigger a response. Authorization for triggers is still handled by groupPolicy, groups, groupAllowFrom, and DM policy settings. This ensures that while the agent might see less context, the security rules for who can talk to it remain strict.

Managing your OpenClaw DM and room policy helps you stay in control of who can reach you and how notifications behave. You can define specific allowlists and mention requirements directly in your configuration JSON to keep your workspace organized.

{
channels: {
matrix: {
dm: {
policy: "allowlist",
allowFrom: ["@admin:example.org"],
threadReplies: "off",
},
groupPolicy: "allowlist",
groupAllowFrom: ["@admin:example.org"],
groups: {
"!roomid:example.org": {
requireMention: true,
},
},
},
},
}
  1. You should check out the Groups documentation to understand how mention-gating and allowlist behaviors work in practice.
  2. When you deal with Matrix DMs, you can manage the pairing process through the CLI.
  3. To see your current pairings or approve a new one, use these commands:
Terminal window
openclaw pairing list matrix
openclaw pairing approve matrix <CODE>
  1. If an unapproved Matrix user keeps messaging you before you grant approval, OpenClaw is smart enough to reuse the same pending pairing code. It might send a reminder reply again after a short cooldown instead of generating a brand new code every time.
  2. You can find more details about how the shared DM pairing flow and storage layout work in the Pairing section.

Repair Matrix direct room mappings with OpenClaw CLI

Section titled “Repair Matrix direct room mappings with OpenClaw CLI”

Sometimes your Matrix state can get out of sync, leading OpenClaw to use stale m.direct mappings that point to old solo rooms. If your direct messages aren’t going to the live DM, you can use the CLI to inspect and fix the mapping.

  1. Start by inspecting the current mapping for a specific user to see where messages are being routed:
Terminal window
openclaw matrix direct inspect --user-id @alice:example.org
  1. If the mapping is incorrect, you can trigger a repair with this command:
Terminal window
openclaw matrix direct repair --user-id @alice:example.org
  1. The repair flow follows a specific logic to find the best room:
  • It first looks for a strict 1:1 DM that is already mapped in your m.direct settings.
  • If that doesn’t work, it falls back to any strict 1:1 DM that you are currently joined in with that user.
  • If no healthy DM exists at all, it creates a fresh direct room and rewrites the m.direct entry for you.
  1. This repair process does not delete your old rooms automatically. It focuses on picking a healthy DM and updating the mapping so that new Matrix sends, verification notices, and other direct-message flows target the correct room again.

You can use Matrix as a native approval client to manage your account’s permissions directly from your chat app. This setup lets you route OpenClaw exec approvals to specific DMs or channels using the native routing engine.

The native DM/channel routing knobs live under the following exec approval configuration keys:

  1. channels.matrix.execApprovals.enabled
  2. channels.matrix.execApprovals.approvers (optional; falls back to channels.matrix.dm.allowFrom)
  3. channels.matrix.execApprovals.target (dm | channel | both, default: dm)
  4. channels.matrix.execApprovals.agentFilter
  5. channels.matrix.execApprovals.sessionFilter

Approvers must be Matrix user IDs such as @owner:example.org. Matrix auto-enables native approvals when enabled is unset or “auto” and at least one approver can be resolved. Exec approvals use execApprovals.approvers first and can fall back to channels.matrix.dm.allowFrom. Plugin approvals authorize through channels.matrix.dm.allowFrom. Set enabled: false to disable Matrix as a native approval client explicitly. Approval requests otherwise fall back to other configured approval routes or the approval fallback policy.

Matrix native routing supports both approval kinds:

  1. channels.matrix.execApprovals.* controls the native DM/channel fanout mode for Matrix approval prompts.
  2. Exec approvals use the exec approver set from execApprovals.approvers or channels.matrix.dm.allowFrom.
  3. Plugin approvals use the Matrix DM allowlist from channels.matrix.dm.allowFrom.
  4. Matrix reaction shortcuts and message updates apply to both exec and plugin approvals.

Delivery rules:

  1. target: “dm” sends approval prompts to approver DMs.
  2. target: “channel” sends the prompt back to the originating Matrix room or DM.
  3. target: “both” sends to approver DMs and the originating Matrix room or DM.
  4. These rules help you control where the notifications appear.

Matrix approval prompts seed reaction shortcuts on the primary approval message:

  1. ✅ = allow once.
  2. ❌ = deny.
  3. ♾️ = allow always when that decision is allowed by the effective exec policy.
  4. These reactions make it easy to respond quickly.

Approvers can react on that message or use the fallback slash commands:

  1. /approve <id> allow-once
  2. /approve <id> allow-always
  3. /approve <id> deny
  4. These commands provide an alternative to reactions.

Only resolved approvers can approve or deny. For exec approvals, channel delivery includes the command text, so only enable channel or both in trusted rooms. If you need to customize settings

Connect OpenClaw to Private or LAN Matrix Homeservers

Section titled “Connect OpenClaw to Private or LAN Matrix Homeservers”

By default, OpenClaw blocks private or internal Matrix homeservers to protect your system from SSRF attacks. You must explicitly opt in for each account if your server is hosted on a local or private network.

  1. Check if your homeserver runs on localhost, a LAN IP, a Tailscale IP, or an internal hostname.
  2. Enable the network.dangerouslyAllowPrivateNetwork setting for that specific Matrix account in your JSON configuration.
{
channels: {
matrix: {
homeserver: "http://matrix-synapse:8008",
network: {
dangerouslyAllowPrivateNetwork: true,
},
accessToken: "syt_internal_xxx",
},
},
}
  1. Alternatively, you can use the CLI to set up a new account with the private network flag enabled.
Terminal window
openclaw matrix account add \
--account ops \
--homeserver http://matrix-synapse:8008 \
--allow-private-network \
--access-token syt_ops_xxx

This opt-in configuration only permits connections to trusted private or internal targets. Public cleartext homeservers like http://matrix.example.org:8008 will remain blocked by OpenClaw, so you should prefer https:// whenever possible.

Configure Proxy Settings for Matrix Traffic

Section titled “Configure Proxy Settings for Matrix Traffic”

If your specific network environment requires an outbound HTTP(S) proxy to reach your Matrix deployment, you can define this in the channels.matrix.proxy field. This ensures that OpenClaw routes all necessary communication through your proxy server.

  1. Open your configuration file and locate the Matrix channel settings.
  2. Add the proxy key with your proxy server address.
{
channels: {
matrix: {
homeserver: "https://matrix.example.org",
accessToken: "syt_bot_xxx",
proxy: "http://127.0.0.1:7890",
},
},
}
  1. If you have multiple accounts, you can override the global default by setting channels.matrix.accounts.<id>.proxy for a specific named account.

OpenClaw uses these proxy settings for both standard runtime Matrix traffic and routine account status probes.

When you need to point OpenClaw to a specific room or user, you have several flexible options for Matrix target resolution. Matrix handles these targets across different contexts to ensure your messages reach the right destination.

  1. Users: @user:server, user:@user:server, or matrix:user:@user:server
  2. Rooms: !room:server, room:!room:server, or matrix:room:!room:server
  3. Aliases: #alias:server, channel:#alias:server, or matrix:channel:#alias:server

Live directory lookup uses the logged-in Matrix account:

  1. User lookups query the Matrix user directory on that homeserver.
  2. Room lookups accept explicit room IDs and aliases directly, then fall back to searching joined room names for that account.
  3. Joined-room name lookup is best-effort. If a room name cannot be resolved to an ID or alias, it is ignored by runtime allowlist resolution.

Setting up your Matrix integration requires a few key parameters to handle authentication and behavior. You can customize everything from encryption to how the bot handles direct messages using these configuration options.

  1. enabled: enable or disable the channel.
  2. name: optional label for the account.
  3. defaultAccount: preferred account ID when multiple Matrix accounts are configured.
  4. homeserver: homeserver URL, for example https://matrix.example.org.
  5. network.dangerouslyAllowPrivateNetwork: allow this Matrix account to connect to private/internal homeservers. Enable this when the homeserver resolves to localhost, a LAN/Tailscale IP, or an internal host such as matrix-synapse.
  6. proxy: optional HTTP(S) proxy URL for Matrix traffic. Named accounts can override the top-level default with their own proxy.
  7. userId: full Matrix user ID, for example @bot:example.org.
  8. accessToken: access token for token-based auth. Plaintext values and SecretRef values are supported for channels.matrix.accessToken and channels.matrix.accounts.<id>.accessToken across env/file/exec providers. See Secrets Management.
  9. password: password for password-based login. Plaintext values and SecretRef values are supported.
  10. deviceId: explicit Matrix device ID.
  11. deviceName: device display name for password login.
  12. avatarUrl: stored self-avatar URL for profile sync and profile set updates.
  13. initialSyncLimit: maximum number of events fetched during startup sync.
  14. encryption: enable E2EE.
  15. allowlistOnly: when true, upgrades open room policy to allowlist, and forces all active DM policies except disabled (including pairing and open) to allowlist. Does not affect disabled policies.
  16. allowBots: allow messages from other configured OpenClaw Matrix accounts (true or "mentions").
  17. groupPolicy: open, allowlist, or disabled.
  18. contextVisibility: supplemental room-context visibility mode (all, allowlist, allowlist_quote).
  19. groupAllowFrom: allowlist of user IDs for room traffic. Full Matrix user IDs are safest; exact directory matches are resolved at startup and when the allowlist changes while the monitor is running. Unresolved names are ignored.
  20. historyLimit: max room messages to include as group history context. Falls back to messages.groupChat.historyLimit; if both are unset, the effective default is 0. Set 0 to disable.
  21. replyToMode: off, first, all, or batched.
  22. markdown: optional Markdown rendering configuration for outbound Matrix text.
  23. streaming: off (default), "partial", "quiet", true, or false. "partial" and true enable preview-first draft updates with normal Matrix text messages. "quiet" uses non-notifying preview notices for self-hosted push-rule setups. false is equivalent to "off".
  24. blockStreaming: true enables separate progress messages for completed assistant blocks while draft preview streaming is active.
  25. threadReplies: off, inbound, or always.
  26. threadBindings: per-channel overrides for thread-bound session routing and lifecycle.
  27. startupVerification: automatic self-verification request mode on startup (if-unverified, off).
  28. startupVerificationCooldownHours: cooldown before retrying automatic startup verification requests.
  29. textChunkLimit: outbound message chunk size in characters (applies when chunkMode is length).
  30. chunkMode: length splits messages by character count; newline splits at line boundaries.
  31. responsePrefix: optional string prepended to all outbound replies for this channel.
  32. ackReaction: optional ack reaction override for this channel/account.
  33. ackReactionScope: optional ack reaction scope override (group-mentions, group-all, direct, all, none, off).
  34. reactionNotifications: inbound reaction notification mode (own, off).
  35. mediaMaxMb: media size cap in MB for outbound sends and inbound media processing.
  36. autoJoin: invite auto-join policy (always, allowlist, off). Default: off. Applies to all Matrix invites, including DM-style invites.
  37. autoJoinAllowlist: rooms/aliases allowed when autoJoin is allowlist. Alias entries are resolved to room IDs during invite handling; OpenClaw does not trust alias state claimed by the invited room.
  38. dm: DM policy block (enabled, policy, allowFrom, sessionScope, threadReplies).
  39. dm.policy: controls DM access after OpenClaw has joined the room and classified it as a DM. It does not change whether an invite is auto-joined.
  40. dm.allowFrom: allowlist of user IDs for DM traffic. Full Matrix user IDs are safest; exact directory matches are resolved at startup and when the allowlist changes while the monitor is running. Unresolved names are ignored.
  41. dm.sessionScope: per-user (default) or per-room. Use per-room when you want each Matrix DM room to keep separate context even if the peer is the same.
  42. dm.threadReplies: DM-only thread policy override (off, inbound, always). It overrides the top-level threadReplies setting for both reply placement and session isolation in DMs.
  43. execApprovals: Matrix-native exec approval delivery (enabled, approvers, target, agentFilter, sessionFilter).
  44. execApprovals.approvers: Matrix user IDs allowed to approve exec requests. Optional when dm.allowFrom already identifies the approvers.
  45. execApprovals.target: dm | channel | both (default: dm).
  46. accounts: named per-account overrides. Top-level channels.matrix values act as defaults for these entries.
  47. groups: per-room policy map. Prefer room IDs or aliases; unresolved room names are ignored at runtime. Session/group identity uses the stable room ID after resolution.
  48. groups.<room>.account: restrict one inherited room entry to a specific Matrix account in multi-account setups.
  49. groups.<room>.allowBots: room-level override for configured-bot senders (true or "mentions").
  50. groups.<room>.users: per-room sender allowlist.
  51. groups.<room>.tools: per-room tool allow/deny overrides.
  52. groups.<room>.autoReply: room-level mention-gating override. true disables mention requirements for that room; false forces them back on.
  53. groups.<room>.skills: optional room-level skill filter.
  54. groups.<room>.systemPrompt: optional room-level system prompt snippet.
  55. rooms: legacy alias for groups.
  56. actions: per-action tool gating (messages, reactions, pins, profile, memberInfo, channelInfo, verification).

You can find more information about how OpenClaw handles different communication patterns in these related guides. These resources cover everything from security to group chat management.

  1. Channels Overview — all supported channels
  2. Pairing — DM authentication and pairing flow
  3. Groups — group chat behavior and mention gating
  4. Channel Routing — session routing for messages
  5. Security — access model and hardening
{
channels: {
matrix: {
streaming: "quiet",
},
},
}
{
"com.openclaw.finalized_preview": true
}
{
channels: {
matrix: {
enabled: true,
defaultAccount: "assistant",
dm: { policy: "pairing" },
accounts: {
assistant: {
homeserver: "https://matrix.example.org",
accessToken: "syt_assistant_xxx",
encryption: true,
},
alerts: {
homeserver: "https://matrix.example.org",
accessToken: "syt_alerts_xxx",
dm: {
policy: "allowlist",
allowFrom: ["@ops:example.org"],
threadReplies: "off",
},
},
},
},
},
}
OpenClaw

OpenClaw Expert

Still stuck?

If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.