OpenClaw Manual OpenClaw

OpenClaw Signal Channel

Messaging
Hard

Connect OpenClaw to Signal using signal-cli — a third-party, open-source command-line interface for the Signal protocol. This integration provides privacy-first AI messaging with full end-to-end encryption. OpenClaw communicates with a signal-cli daemon over HTTP JSON-RPC and Server-Sent Events, allowing your AI assistant to send and receive messages on Signal. A dedicated phone number is required for the bot account.

Quick Info
Difficulty Hard
Category Messaging
Features Supported 4 / 6

Signal Supported Features

Text Messages

Supported

Media & Files

Supported

Reactions

Supported

Threads

Not Supported

Voice Messages

Not Supported

Group Chat

Supported

Signal Prerequisites

  • A dedicated phone number for the Signal bot account (separate from your personal number)
  • Java Runtime Environment (JRE 25+) installed on your server
  • signal-cli installed and accessible in your PATH
  • OpenClaw Gateway running and configured
  • An existing Signal account to link the bot from (or a new registration)

Signal Quick Setup

1

Install signal-cli

Download and install signal-cli from the official GitHub repository. It requires Java 25 or later. Verify the installation by running 'signal-cli --version' in your terminal.

2

Link or register a Signal account

Link signal-cli to an existing Signal account by running 'signal-cli link -n "OpenClaw"' and scanning the QR code from another device. Alternatively, register a new account with 'signal-cli -a +15551234567 register'. Use a dedicated number — running on your personal account will cause self-message loops.

3

Add Signal channel config

Add the Signal channel configuration to ~/.openclaw/openclaw.json. Set the 'account' field to your bot's E.164 phone number and configure the dmPolicy (pairing, allowlist, or open) to control who can message your assistant.

4

Start Gateway and send a test message

Launch the Gateway process. OpenClaw will automatically start the signal-cli daemon. Send a message to the bot's number from another Signal account. If using the default pairing policy, approve the sender via 'openclaw pairing approve signal <code>'.

Signal Configuration Example

config.json
{
  "channels": {
    "signal": {
      "enabled": true,
      "account": "+15551234567",
      "dmPolicy": "pairing"
    }
  }
}

Signal Deep Dive

Architecture Overview

OpenClaw connects to Signal through signal-cli — a Java-based command-line client that implements the Signal protocol. The architecture uses an HTTP JSON-RPC interface with Server-Sent Events (SSE) for real-time message delivery. By default, OpenClaw auto-spawns a signal-cli daemon process on Gateway startup. The daemon handles all Signal protocol operations (encryption, key exchange, message sending/receiving), while OpenClaw communicates with it over a local HTTP API. This keeps the Signal protocol layer completely separate from the AI logic. Alternatively, you can run signal-cli as an external daemon and point OpenClaw to it via the httpUrl config — useful for managing signal-cli independently or running it on a different host.
The auto-start daemon binds to 127.0.0.1:8080 by default. Change httpHost and httpPort if you need a different address.
Running signal-cli externally gives you more control over updates and lifecycle management. Set httpUrl to the full daemon URL to disable auto-start.

Signal Account Setup

Your bot needs a dedicated Signal account. Do not use your personal number — Signal ignores self-sent messages, and running both personal and bot accounts on the same number creates routing conflicts. Two options for account setup: • Link to existing device — Run 'signal-cli link -n "OpenClaw"' to generate a device link URI. Scan the QR code from the primary Signal app. This is the recommended approach as it's the simplest. • Fresh registration — Run 'signal-cli -a +15551234567 register' to register a new Signal account directly. You'll need to verify the number via SMS or voice call. Once linked or registered, signal-cli stores its credentials and keys locally. These persist across restarts.
openclaw.json
{
  "channels": {
    "signal": {
      "account": "+15551234567",
      "cliPath": "/usr/local/bin/signal-cli"
    }
  }
}
Avoid running the bot on your personal Signal number. Signal's self-message protection will ignore messages sent to yourself, and the bot will not function correctly.

External Daemon Mode

For advanced deployments, you can run signal-cli as a standalone daemon process outside of OpenClaw. This is useful when you want to manage signal-cli updates independently, run it on a separate machine, or share a single daemon across multiple services. Start the daemon manually with: signal-cli -a +15551234567 daemon --http=127.0.0.1:8080 Then point OpenClaw to it by setting httpUrl. When httpUrl is configured, OpenClaw skips auto-starting the daemon and connects to the existing process instead.
openclaw.json
{
  "channels": {
    "signal": {
      "account": "+15551234567",
      "httpUrl": "http://127.0.0.1:8080/api/v1/rpc"
    }
  }
}
When using an external daemon, ensure it's started before the Gateway. OpenClaw will wait up to startupTimeoutMs (max 120 seconds) for the daemon to become available.

DM Policies

DM (Direct Message) policies control who can interact with your AI assistant in private chats. OpenClaw supports four policies: • pairing (default) — New contacts receive a random pairing code when they first message the bot. The code expires after 1 hour. Approve via 'openclaw pairing approve signal <code>' in your terminal. Once approved, they can chat freely. • allowlist — Only phone numbers or UUIDs listed in allowFrom can message the bot. Everyone else is silently ignored. Use E.164 format for phone numbers or 'uuid:<id>' for UUID-only contacts. • open — Anyone who messages the bot gets a response. Requires adding '*' to the allowFrom list as a safety confirmation. Use with caution. • disabled — DM functionality is completely turned off.
openclaw.json
{
  "channels": {
    "signal": {
      "dmPolicy": "allowlist",
      "allowFrom": ["+15551234567", "uuid:a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
    }
  }
}
Contacts who registered Signal without sharing their phone number will appear as 'uuid:<id>' in the allowFrom list. Check Gateway logs to find their UUID.
Per-contact history limits can be set via dms["<phone_or_uuid>"].historyLimit to override the global dmHistoryLimit.

Group Chat Management

OpenClaw supports Signal group chats with configurable access control: • open — Accept messages from all group members • allowlist — Only approved senders (via groupAllowFrom) can trigger the bot • disabled — Ignore all group messages Group conversations are fully isolated from DMs. Messages are tagged as 'agent:<agentId>:signal:group:<groupId>' to maintain separate context and history per group. You can configure historyLimit per group to control how many messages are included as AI context (default 50, set 0 to disable history).
openclaw.json
{
  "channels": {
    "signal": {
      "groupPolicy": "open",
      "historyLimit": 50
    }
  }
}

Privacy & End-to-End Encryption

Signal is the gold standard for private messaging. All messages between the bot and contacts are end-to-end encrypted using the Signal Protocol (Double Ratchet algorithm + X3DH key agreement). OpenClaw never sees plaintext messages in transit — decryption happens locally inside the signal-cli process on your server. Key privacy properties: • Messages are encrypted client-to-client — Signal's servers cannot read them • signal-cli stores encryption keys locally on your server • No data passes through Anthropic, OpenAI, or any third-party AI provider's infrastructure (messages are decrypted locally, processed by your self-hosted Gateway, and only the conversation context is sent to your configured AI provider) • Story events can be ignored entirely with ignoreStories: true
For maximum privacy, combine Signal with a locally-hosted LLM provider (e.g., Ollama) to keep all data entirely on your infrastructure.

Reactions

OpenClaw supports sending and receiving emoji reactions on Signal messages. Reactions are useful for acknowledgment (showing the user their message was received) and for interactive agent behaviors. Reaction syntax uses the message tool with targets in E.164 format, UUID format, or group format: • DM reaction: target=+15551234567 or target=uuid:<id> • Group reaction: target=signal:group:<groupId> with targetAuthor=uuid:<sender> Configure reaction behavior globally or per-account: • actions.reactions — Enable/disable reaction capability (default true) • reactionLevel — off/ack (disabled) or minimal/extensive (enabled with guidance)
openclaw.json
{
  "channels": {
    "signal": {
      "reactionLevel": "minimal"
    }
  }
}

Media & Attachments

OpenClaw handles media files on Signal including images, documents, audio, and video. Media is transferred through signal-cli as base64-encoded data. Inbound media is automatically downloaded and processed unless ignoreAttachments is set to true. Outbound media is base64-fetched from signal-cli before being sent. The default file size limit is 8 MB (mediaMaxMb). Signal itself supports larger files, but the base64 encoding overhead and processing time make 8 MB a practical default.
openclaw.json
{
  "channels": {
    "signal": {
      "mediaMaxMb": 8,
      "ignoreAttachments": false
    }
  }
}

Typing Indicators & Read Receipts

OpenClaw sends typing indicators while generating AI responses to maintain a natural conversation feel. The Gateway calls signal-cli's sendTyping endpoint and refreshes the indicator periodically during response generation. Read receipts can be forwarded for approved DM contacts when sendReadReceipts is enabled. This lets senders know their message has been processed. Note: Group read receipts are not supported by signal-cli.
openclaw.json
{
  "channels": {
    "signal": {
      "sendReadReceipts": true
    }
  }
}

Text Chunking & Delivery

For long AI responses, OpenClaw automatically splits text into multiple messages. The default chunk size is 4,000 characters per message. Two chunking modes are available: • length (default) — Hard split at the character limit • newline — Split at paragraph boundaries first, then apply the character limit Delivery targets use E.164 phone numbers, UUIDs, or group IDs: • DMs: signal:+15551234567 or bare E.164 number • UUID DMs: uuid:<id> or bare UUID • Groups: signal:group:<groupId>
openclaw.json
{
  "channels": {
    "signal": {
      "textChunkLimit": 4000,
      "chunkMode": "newline"
    }
  }
}

Signal Configuration Reference

enabled
Type: boolean Default: true

Enable or disable the Signal channel

account
Type: string Default: ""

Bot's phone number in E.164 format (e.g., +15551234567). Required

cliPath
Type: string Default: "signal-cli"

Path to the signal-cli executable

httpUrl
Type: string Default: ""

Full URL of an external signal-cli daemon. When set, disables auto-start

httpHost
Type: string Default: "127.0.0.1"

Host address for the auto-started signal-cli daemon to bind to

httpPort
Type: number Default: 8080

Port for the auto-started signal-cli daemon to bind to

autoStart
Type: boolean Default: true

Whether to automatically spawn the signal-cli daemon on Gateway startup

startupTimeoutMs
Type: number Default: 30000

Maximum time (ms) to wait for the signal-cli daemon to become available. Max 120000

dmPolicy
Type: string Default: "pairing"

Controls who can DM the bot. Options: pairing, allowlist, open, disabled

allowFrom
Type: string[] Default: []

Phone numbers (E.164) or uuid:<id> identifiers allowed to message the bot

dmHistoryLimit
Type: number Default: 50

Number of recent DM messages to include as AI context per conversation

groupPolicy
Type: string Default: "disabled"

Group chat policy. Options: disabled, allowlist, open

groupAllowFrom
Type: string[] Default: []

Phone numbers or UUIDs allowed to trigger the bot in groups (when groupPolicy is allowlist)

historyLimit
Type: number Default: 50

Maximum group messages included as AI context. Set 0 to disable

sendReadReceipts
Type: boolean Default: false

Whether to forward read receipt signals for approved DM contacts

textChunkLimit
Type: number Default: 4000

Maximum characters per outbound message before chunking

chunkMode
Type: string Default: "length"

Text chunking mode. Options: length (hard split), newline (paragraph-aware)

mediaMaxMb
Type: number Default: 8

Maximum media file size in megabytes for inbound/outbound attachments

ignoreAttachments
Type: boolean Default: false

Skip downloading inbound media attachments

ignoreStories
Type: boolean Default: false

Ignore Signal story events entirely

receiveMode
Type: string Default: ""

Message receive mode. Options: on-start (fetch on startup), manual

configWrites
Type: boolean Default: true

Allow /config commands to modify channel settings at runtime

reactionLevel
Type: string Default: "ack"

Bot reaction capability. Options: off, ack, minimal, extensive

Signal Frequently Asked Questions

Signal Troubleshooting

signal-cli fails to start with Java errors

Java is not installed, or the installed version is too old. signal-cli requires Java 25 or later.

Install OpenJDK 25+ on your server. Verify with 'java --version'. If multiple Java versions are installed, ensure the correct one is in your PATH or set JAVA_HOME. Also verify signal-cli is installed correctly by running 'signal-cli --version'.
Bot is not responding to any messages

The account field may be incorrect, the signal-cli daemon may not be running, or the sender hasn't been approved via pairing.

Check the account number matches the registered signal-cli account (E.164 format with country code). Run 'openclaw status' and 'openclaw gateway status' to verify the daemon is running. If using pairing policy, check pending pairings with 'openclaw pairing list signal' and approve the sender.
DMs are ignored even after approval

The sender may not be in the allowFrom list (when using allowlist policy), or the sender's identifier format may not match.

Check the Gateway logs for the sender's identifier. Some Signal users register without sharing their phone number — they'll appear as 'uuid:<id>' instead of a phone number. Add the correct identifier to allowFrom. Run 'openclaw channels status --probe' for detailed channel diagnostics.
Group messages are not being received

groupPolicy is set to 'disabled' (default), or the group is not in the allowlist.

Set groupPolicy to 'open' to accept all group messages, or use 'allowlist' and add the group ID to groupAllowFrom. Check Gateway logs for the group ID when a group message is received.
External daemon connection fails (httpUrl not reachable)

The signal-cli daemon is not running, the URL is incorrect, or a firewall is blocking the connection.

Verify the daemon is running and listening on the expected host:port. Test connectivity with 'curl http://127.0.0.1:8080/api/v1/rpc'. Check firewall rules if running across machines. Ensure the daemon was started with the correct --http flag matching your httpUrl config.