Connect OpenClaw to Signal: Quick Setup Guide
Prerequisites
Section titled “Prerequisites”Before you get started, make sure you have these items ready:
- OpenClaw installed on your server (the Linux steps below were tested on Ubuntu 24).
signal-cliavailable on the host where your gateway runs.- A phone number that can receive a verification SMS (if you choose the SMS registration path).
- Browser access for the Signal captcha (
signalcaptchas.org) during the registration process.
Quick setup (beginner)
Section titled “Quick setup (beginner)”Setting this up is straightforward. Just follow these steps:
- Use a separate Signal number for the bot.
- Install
signal-cli. Note that you will need Java if you are using the JVM build. - Choose one setup path:
- Path A (QR link): Run
signal-cli link -n "OpenClaw"and scan the resulting code with your Signal app. - Path B (SMS register): Register a dedicated number using the captcha and SMS verification process.
- Path A (QR link): Run
- Configure OpenClaw and restart the gateway.
- Send a first DM and approve the pairing by running
openclaw pairing approve signal <CODE>.
Minimal config:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}Field reference:
| Field | Description |
|---|---|
account | Bot phone number in E.164 format (+15551234567) |
cliPath | Path to signal-cli (signal-cli if on PATH) |
dmPolicy | DM access policy (pairing recommended) |
allowFrom | Phone numbers or uuid:<id> values allowed to DM |
What it is
Section titled “What it is”This is a Signal channel that works via signal-cli instead of an embedded libsignal. It uses deterministic routing, which ensures that replies always go back to Signal correctly. Direct messages share the main session of the agent, while groups are kept isolated using the format agent:<agentId>:signal:group:<groupId>.
Config writes
Section titled “Config writes”By default, Signal can write config updates triggered by /config set|unset. This requires commands.config: true to be active.
If you want to disable this behavior, use the following configuration:
{ channels: { signal: { configWrites: false } },}The number model (important)
Section titled “The number model (important)”You need to know how the gateway handles numbers before you start. The gateway connects to a Signal device, which is basically your signal-cli account.
If you decide to run the bot on your personal Signal account, keep in mind that it will ignore your own messages to prevent loop protection. If you want the “I text the bot and it replies” experience, you should use a separate bot number.
Setup path A: link existing Signal account (QR)
Section titled “Setup path A: link existing Signal account (QR)”If you want to link an account you already have, follow these steps:
- Install
signal-cli(you can use the JVM or native build). - Link your bot account by running:
signal-cli link -n "OpenClaw"and then scan the QR code that appears using your Signal app.
- Configure Signal and start the gateway.
Here is an example configuration:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}If you need multi-account support, you can use channels.signal.accounts with per-account settings and an optional name. You can find the shared pattern in the gateway/configuration documentation.
Setup path B: register dedicated bot number (SMS, Linux)
Section titled “Setup path B: register dedicated bot number (SMS, Linux)”Use this path when you want a dedicated bot number instead of linking an existing app account.
- Get a number that can receive SMS (or voice verification if you are using a landline). Using a dedicated bot number is the best way to avoid account or session conflicts.
- Install
signal-clion your gateway host:
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz"sudo tar xf "signal-cli-${VERSION}-Linux-native.tar.gz" -C /optsudo ln -sf /opt/signal-cli /usr/local/bin/signal-cli --versionIf you choose the JVM build (signal-cli-${VERSION}.tar.gz), make sure you install JRE 25+ first. You should keep signal-cli updated because old releases can break when Signal server APIs change.
- Register and verify your number:
signal-cli -a +<BOT_PHONE_NUMBER> registerIf the system requires a captcha:
- Open
https://signalcaptchas.org/registration/generate.html. - Complete the captcha and copy the
signalcaptcha://...link target from the “Open Signal” button. - Try to run this from the same external IP as your browser session if possible.
- Run the registration again immediately, as captcha tokens expire fast:
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>- Configure OpenClaw, restart the gateway, and verify the channel:
# If you run the gateway as a user systemd service:systemctl --user restart openclaw-gateway
# Then verify:openclaw doctoropenclaw channels status --probe- Pair your DM sender:
- Send any message to the bot number.
- Approve the code on the server:
openclaw pairing approve signal <PAIRING_CODE>. - Save the bot number as a contact on your phone so you don’t see “Unknown contact” warnings.
Important: Registering a phone number account with signal-cli can de-authenticate your main Signal app session for that number. You should prefer a dedicated bot number, or use the QR link mode if you want to keep your existing phone setup active.
Upstream references:
signal-cliREADME:https://github.com/AsamK/signal-cli- Captcha flow:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - Linking flow:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
External daemon mode (httpUrl)
Section titled “External daemon mode (httpUrl)”If you want to manage signal-cli yourself—perhaps to avoid slow JVM cold starts, handle container initialization, or manage shared CPUs—you can run the daemon separately and point OpenClaw at it:
{ channels: { signal: { httpUrl: "http://127.0.0.1:8080", autoStart: false, }, },}This setup skips the auto-spawn process and the startup wait inside OpenClaw. If you experience slow starts while auto-spawning, you can adjust channels.signal.startupTimeoutMs.
Access control (DMs + groups)
Section titled “Access control (DMs + groups)”Managing who can talk to your bot is a big deal. For DMs, the default setting is channels.signal.dmPolicy = "pairing". If someone unknown sends a message, they get a pairing code that expires in an hour. You can handle these requests using these commands:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
This pairing process is the standard way to exchange tokens for Signal DMs. You can find more details in the Pairing documentation. If you have senders identified only by UUID (from sourceUuid), they are stored as uuid:<id> in your channels.signal.allowFrom list.
For groups, you have three options for channels.signal.groupPolicy: open, allowlist, or disabled. When you use the allowlist setting, channels.signal.groupAllowFrom determines who can trigger the bot. You can also get specific with channels.signal.groups["<group-id>" | "*"] to override things like requireMention, tools, and toolsBySender.
If you are running multiple accounts, use channels.signal.accounts.<id>.groups for specific overrides. Just a heads up: if channels.signal is completely missing from your config, the system defaults to groupPolicy="allowlist" for group checks, even if you set a different default in channels.defaults.groupPolicy.
How it works (behavior)
Section titled “How it works (behavior)”Under the hood, signal-cli runs as a daemon. The gateway picks up events using SSE. Every inbound message gets normalized into a shared channel envelope so the rest of the system understands it. When the bot replies, it always routes back to the original number or group.
Media + limits
Section titled “Media + limits”Signal has some limits you should know about. Outbound text gets split into chunks based on channels.signal.textChunkLimit, which defaults to 4000 characters. If you want cleaner breaks, set channels.signal.chunkMode="newline" to split on blank lines before the system checks the length.
Attachments work via base64 data fetched from signal-cli. There is a media cap of 8MB by default (channels.signal.mediaMaxMb), but you can change that. If you want to skip downloading media entirely, use channels.signal.ignoreAttachments.
For group history context, the bot looks at channels.signal.historyLimit or channels.signal.accounts.*.historyLimit. If those aren’t set, it falls back to messages.groupChat.historyLimit. The default is 50, but you can set it to 0 to disable it.
Typing + read receipts
Section titled “Typing + read receipts”To make the bot feel more natural, OpenClaw sends typing indicators using signal-cli sendTyping. It refreshes these signals while a reply is running.
You can also enable read receipts for allowed DMs by setting channels.signal.sendReadReceipts to true. Keep in mind that signal-cli does not support read receipts for groups yet.
Reactions (message tool)
Section titled “Reactions (message tool)”You can use the message action=react tool with channel=signal to interact with messages. When you want to target a specific message, you’ll need the sender’s E.164 phone number or their UUID. If you use a UUID, you can get it from your pairing output and format it as uuid:<id>, though the bare UUID works as well.
The messageId you need is the Signal timestamp for the specific message you are reacting to. If you are dealing with group reactions, you must include the targetAuthor or targetAuthorUuid.
Here are a few examples of how this looks in practice:
message action=react channel=signal target=uuid:123e4567-e89b-12d3-a456-426614174000 messageId=1737630212345 emoji=🔥message action=react channel=signal target=+15551234567 messageId=1737630212345 emoji=🔥 remove=truemessage action=react channel=signal target=signal:group:<groupId> targetAuthor=uuid:<sender-uuid> messageId=1737630212345 emoji=✅You can manage how these reactions behave through your configuration. The channels.signal.actions.reactions setting lets you enable or disable these actions, and it is set to true by default. The channels.signal.reactionLevel setting determines how the agent handles reactions. You can set this to off, ack, minimal, or extensive.
If you choose off or ack, the agent won’t be able to react, and the tool will return an error. Choosing minimal or extensive enables the reactions and sets the guidance level. If you need to customize this for specific accounts, you can use overrides like channels.signal.accounts.<id>.actions.reactions and channels.signal.accounts.<id>.reactionLevel.
Delivery targets (CLI/cron)
Section titled “Delivery targets (CLI/cron)”When you are working with the CLI or setting up cron jobs, you have several ways to specify where your messages should go.
For direct messages, you can use signal:+15551234567 or the plain E.164 number. If you prefer using UUIDs for DMs, use the uuid:<id> format or just the bare UUID. For group chats, use the signal:group:<groupId> format. If your Signal account supports it, you can also use username:<name> as a target.
Troubleshooting
Section titled “Troubleshooting”If things aren’t working as expected, run through this command ladder first to see where the break is:
openclaw statusopenclaw gateway statusopenclaw logs --followopenclaw doctoropenclaw channels status --probeYou can also confirm your DM pairing state if you suspect a connection issue:
openclaw pairing list signalHere are the common failures you might run into:
- The daemon is reachable but there are no replies: You should verify your account and daemon settings, specifically
httpUrlandaccount, along with your receive mode. - DMs are ignored: This usually happens when the sender is still pending pairing approval.
- Group messages are ignored: Check if group sender or mention gating is blocking delivery.
- Config validation errors after you’ve made edits: Just run
openclaw doctor --fixto clean things up. - Signal is missing from diagnostics: Double-check that
channels.signal.enabled: trueis set in your config.
If you need to check the system state further, use these extra commands:
openclaw pairing list signalpgrep -af signal-cligrep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20For a full triage flow, head over to /channels/troubleshooting.
Security notes
Section titled “Security notes”- Your
signal-cliaccount keys are stored locally, typically found at~/.local/share/signal-cli/data/. - Make sure you back up your Signal account state before you start a server migration or a rebuild.
- It is best to keep
channels.signal.dmPolicy: "pairing"active unless you have a specific reason for broader DM access. - You only need SMS verification for registration or recovery flows. Keep in mind that losing control of your number or account can make re-registration a lot harder.
Configuration reference (Signal)
Section titled “Configuration reference (Signal)”If you’re looking for the full configuration, you can find it here: Configuration.
When you’re setting up the Signal provider, you have several options to play with:
channels.signal.enabled: This turns the channel on or off when you start up.channels.signal.account: Use the E.164 format for your bot account here.channels.signal.cliPath: This is the path to yoursignal-cliinstallation.channels.signal.httpUrl: If you have a full daemon URL, put it here. It will override any host or port settings.channels.signal.httpHost,channels.signal.httpPort: These define where the daemon binds. The default is 127.0.0.1:8080.channels.signal.autoStart: This tells the system to automatically start the daemon. It defaults to true if you haven’t set anhttpUrl.channels.signal.startupTimeoutMs: This is how long the system waits for startup in milliseconds. It’s capped at 120000.channels.signal.receiveMode: You can set this toon-startormanual.channels.signal.ignoreAttachments: Use this if you want to skip downloading attachments.channels.signal.ignoreStories: This lets you ignore any stories coming from the daemon.channels.signal.sendReadReceipts: This handles forwarding read receipts.channels.signal.dmPolicy: You can choose betweenpairing,allowlist,open, ordisabled. The default ispairing.channels.signal.allowFrom: This is your DM allowlist. You can use E.164 numbers oruuid:<id>. If you set the policy toopen, you’ll need to use"*"here. Since Signal doesn’t use usernames, you’ll need phone or UUID IDs.channels.signal.groupPolicy: Set this toopen,allowlist, ordisabled. It defaults toallowlist.channels.signal.groupAllowFrom: This is the allowlist for people sending messages in groups.channels.signal.groups: You can set per-group overrides here, keyed by the Signal group ID (or use"*"). It supports fields likerequireMention,tools, andtoolsBySender.channels.signal.accounts.<id>.groups: This is just the per-account version of the groups setting if you’re running a multi-account setup.channels.signal.historyLimit: This sets the maximum number of group messages to include for context. Setting it to 0 turns it off.channels.signal.dmHistoryLimit: This limits DM history based on user turns. If you need to override this for a specific user, usechannels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: This defines the size of outbound message chunks in characters.channels.signal.chunkMode: You can uselength(the default) ornewline.newlinesplits messages at blank lines (paragraph boundaries) before it hits the length limit.channels.signal.mediaMaxMb: This sets the cap for both inbound and outbound media in MB.
There are also a few global options that affect Signal:
agents.list[].groupChat.mentionPatterns: Keep in mind that Signal doesn’t support native mentions.messages.groupChat.mentionPatterns: This acts as your global fallback.messages.responsePrefix.
Related
Section titled “Related”If you want to look into this further, check out these resources:
- Channels Overview — all supported channels
- Pairing — DM authentication and pairing flow
- Groups — group chat behavior and mention gating
- Channel Routing — session routing for messages
- Security — access model and hardening
OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.