2026-01-18 03:17:30 +00:00
---
2026-01-19 18:50:22 -08:00
summary: "iMessage via BlueBubbles macOS server (REST send/receive, typing, reactions, pairing, advanced actions)."
2026-01-18 03:17:30 +00:00
read_when:
- Setting up BlueBubbles channel
- Troubleshooting webhook pairing
2026-01-19 18:50:22 -08:00
- Configuring iMessage on macOS
2026-01-31 16:04:03 -05:00
title: "BlueBubbles"
2026-01-18 03:17:30 +00:00
---
2026-01-31 21:13:13 +09:00
2026-01-18 03:17:30 +00:00
# BlueBubbles (macOS REST)
2026-01-19 18:50:22 -08:00
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **Recommended for iMessage integration** due to its richer API and easier setup compared to the legacy imsg channel.
2026-01-18 03:17:30 +00:00
## Overview
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- Runs on macOS via the BlueBubbles helper app ([bluebubbles.app ](https://bluebubbles.app )).
2026-01-20 00:43:56 -08:00
- Recommended/tested: macOS Sequoia (15). macOS Tahoe (26) works; edit is currently broken on Tahoe, and group icon updates may report success but not sync.
2026-01-30 03:15:10 +01:00
- OpenClaw talks to it through its REST API (`GET /api/v1/ping` , `POST /message/text` , `POST /chat/:id/*` ).
2026-01-18 03:17:30 +00:00
- Incoming messages arrive via webhooks; outgoing replies, typing indicators, read receipts, and tapbacks are REST calls.
- Attachments and stickers are ingested as inbound media (and surfaced to the agent when possible).
2026-02-07 15:40:35 -05:00
- Pairing/allowlist works the same way as other channels (`/channels/pairing` etc) with `channels.bluebubbles.allowFrom` + pairing codes.
2026-01-19 18:50:22 -08:00
- Reactions are surfaced as system events just like Slack/Telegram so agents can "mention" them before replying.
- Advanced features: edit, unsend, reply threading, message effects, group management.
2026-01-18 03:17:30 +00:00
## Quick start
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
1. Install the BlueBubbles server on your Mac (follow the instructions at [bluebubbles.app/install ](https://bluebubbles.app/install )).
2. In the BlueBubbles config, enable the web API and set a password.
2026-01-30 03:15:10 +01:00
3. Run `openclaw onboard` and select BlueBubbles, or configure manually:
2026-02-06 10:08:59 -05:00
2026-01-18 03:17:30 +00:00
```json5
{
channels: {
bluebubbles: {
enabled: true,
2026-01-19 18:50:22 -08:00
serverUrl: "http://192.168.1.100:1234",
2026-01-18 03:17:30 +00:00
password: "example-password",
2026-01-31 21:13:13 +09:00
webhookPath: "/bluebubbles-webhook",
},
},
2026-01-18 03:17:30 +00:00
}
```
2026-02-06 10:08:59 -05:00
2026-01-19 18:50:22 -08:00
4. Point BlueBubbles webhooks to your gateway (example: `https://your-gateway-host:3000/bluebubbles-webhook?password=<password>` ).
2026-01-18 03:17:30 +00:00
5. Start the gateway; it will register the webhook handler and start pairing.
2026-02-14 19:47:46 +01:00
Security note:
2026-02-21 11:41:35 +01:00
- Always set a webhook password.
- Webhook authentication is always required. OpenClaw rejects BlueBubbles webhook requests unless they include a password/guid that matches `channels.bluebubbles.password` (for example `?password=<password>` or `x-password` ), regardless of loopback/proxy topology.
2026-03-02 17:20:46 +00:00
- Password authentication is checked before reading/parsing full webhook bodies.
2026-02-14 19:47:46 +01:00
2026-02-03 18:06:54 -08:00
## Keeping Messages.app alive (VM / headless setups)
Some macOS VM / always-on setups can end up with Messages.app going “idle” (incoming events stop until the app is opened/foregrounded). A simple workaround is to **poke Messages every 5 minutes** using an AppleScript + LaunchAgent.
### 1) Save the AppleScript
Save this as:
- `~/Scripts/poke-messages.scpt`
Example script (non-interactive; does not steal focus):
```applescript
try
tell application "Messages"
if not running then
launch
end if
-- Touch the scripting interface to keep the process responsive.
set _chatCount to (count of chats)
end tell
on error
-- Ignore transient failures (first-run prompts, locked session, etc).
end try
```
### 2) Install a LaunchAgent
Save this as:
- `~/Library/LaunchAgents/com.user.poke-messages.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
< plist version = "1.0" >
< dict >
< key > Label< / key >
< string > com.user.poke-messages< / string >
< key > ProgramArguments< / key >
< array >
< string > /bin/bash< / string >
< string > -lc< / string >
< string > /usr/bin/osascript " $HOME/Scripts/poke-messages.scpt" < / string >
< / array >
< key > RunAtLoad< / key >
< true / >
< key > StartInterval< / key >
< integer > 300< / integer >
< key > StandardOutPath< / key >
< string > /tmp/poke-messages.log< / string >
< key > StandardErrorPath< / key >
< string > /tmp/poke-messages.err< / string >
< / dict >
< / plist >
```
Notes:
- This runs **every 300 seconds** and **on login** .
- The first run may trigger macOS **Automation** prompts (`osascript` → Messages). Approve them in the same user session that runs the LaunchAgent.
Load it:
```bash
launchctl unload ~/Library/LaunchAgents/com.user.poke-messages.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist
```
2026-01-19 18:50:22 -08:00
## Onboarding
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
BlueBubbles is available in the interactive setup wizard:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
```
2026-01-30 03:15:10 +01:00
openclaw onboard
2026-01-19 18:50:22 -08:00
```
The wizard prompts for:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- **Server URL** (required): BlueBubbles server address (e.g., `http://192.168.1.100:1234` )
- **Password** (required): API password from BlueBubbles Server settings
- **Webhook path** (optional): Defaults to `/bluebubbles-webhook`
- **DM policy**: pairing, allowlist, open, or disabled
- **Allow list**: Phone numbers, emails, or chat targets
You can also add BlueBubbles via CLI:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
```
2026-01-30 03:15:10 +01:00
openclaw channels add bluebubbles --http-url http://192.168.1.100:1234 --password < password >
2026-01-19 18:50:22 -08:00
```
## Access control (DMs + groups)
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
DMs:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- Default: `channels.bluebubbles.dmPolicy = "pairing"` .
- Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour).
- Approve via:
2026-01-30 03:15:10 +01:00
- `openclaw pairing list bluebubbles`
- `openclaw pairing approve bluebubbles <CODE>`
2026-02-07 15:40:35 -05:00
- Pairing is the default token exchange. Details: [Pairing ](/channels/pairing )
2026-01-19 18:50:22 -08:00
Groups:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- `channels.bluebubbles.groupPolicy = open | allowlist | disabled` (default: `allowlist` ).
- `channels.bluebubbles.groupAllowFrom` controls who can trigger in groups when `allowlist` is set.
### Mention gating (groups)
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
BlueBubbles supports mention gating for group chats, matching iMessage/WhatsApp behavior:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- Uses `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns` ) to detect mentions.
- When `requireMention` is enabled for a group, the agent only responds when mentioned.
- Control commands from authorized senders bypass mention gating.
Per-group configuration:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
```json5
{
channels: {
bluebubbles: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
2026-01-31 21:13:13 +09:00
"*": { requireMention: true }, // default for all groups
"iMessage;-;chat123": { requireMention: false }, // override for specific group
},
},
},
2026-01-19 18:50:22 -08:00
}
```
### Command gating
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- Control commands (e.g., `/config` , `/model` ) require authorization.
- Uses `allowFrom` and `groupAllowFrom` to determine command authorization.
- Authorized senders can run control commands even without mentioning in groups.
## Typing + read receipts
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- **Typing indicators**: Sent automatically before and during response generation.
- **Read receipts**: Controlled by `channels.bluebubbles.sendReadReceipts` (default: `true` ).
2026-01-30 03:15:10 +01:00
- **Typing indicators**: OpenClaw sends typing start events; BlueBubbles clears typing automatically on send or timeout (manual stop via DELETE is unreliable).
2026-01-19 18:50:22 -08:00
```json5
{
channels: {
bluebubbles: {
2026-01-31 21:13:13 +09:00
sendReadReceipts: false, // disable read receipts
},
},
2026-01-19 18:50:22 -08:00
}
```
## Advanced actions
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
BlueBubbles supports advanced message actions when enabled in config:
```json5
{
channels: {
bluebubbles: {
actions: {
2026-01-31 21:13:13 +09:00
reactions: true, // tapbacks (default: true)
edit: true, // edit sent messages (macOS 13+, broken on macOS 26 Tahoe)
unsend: true, // unsend messages (macOS 13+)
reply: true, // reply threading by message GUID
sendWithEffect: true, // message effects (slam, loud, etc.)
renameGroup: true, // rename group chats
setGroupIcon: true, // set group chat icon/photo (flaky on macOS 26 Tahoe)
addParticipant: true, // add participants to groups
2026-01-19 18:50:22 -08:00
removeParticipant: true, // remove participants from groups
2026-01-31 21:13:13 +09:00
leaveGroup: true, // leave group chats
sendAttachment: true, // send attachments/media
},
},
},
2026-01-19 18:50:22 -08:00
}
```
Available actions:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- **react**: Add/remove tapback reactions (`messageId` , `emoji` , `remove` )
- **edit**: Edit a sent message (`messageId` , `text` )
- **unsend**: Unsend a message (`messageId` )
- **reply**: Reply to a specific message (`messageId` , `text` , `to` )
- **sendWithEffect**: Send with iMessage effect (`text` , `to` , `effectId` )
- **renameGroup**: Rename a group chat (`chatGuid` , `displayName` )
2026-01-20 00:43:56 -08:00
- **setGroupIcon**: Set a group chat's icon/photo (`chatGuid` , `media` ) — flaky on macOS 26 Tahoe (API may return success but the icon does not sync).
2026-01-19 18:50:22 -08:00
- **addParticipant**: Add someone to a group (`chatGuid` , `address` )
- **removeParticipant**: Remove someone from a group (`chatGuid` , `address` )
- **leaveGroup**: Leave a group chat (`chatGuid` )
2026-01-23 04:33:36 +00:00
- **sendAttachment**: Send media/files (`to` , `buffer` , `filename` , `asVoice` )
- Voice memos: set `asVoice: true` with **MP3** or **CAF** audio to send as an iMessage voice message. BlueBubbles converts MP3 → CAF when sending voice memos.
2026-01-19 18:50:22 -08:00
2026-01-21 17:19:38 +00:00
### Message IDs (short vs full)
2026-01-31 21:13:13 +09:00
OpenClaw may surface _short_ message IDs (e.g., `1` , `2` ) to save tokens.
2026-01-21 17:19:38 +00:00
- `MessageSid` / `ReplyToId` can be short IDs.
- `MessageSidFull` / `ReplyToIdFull` contain the provider full IDs.
- Short IDs are in-memory; they can expire on restart or cache eviction.
- Actions accept short or full `messageId` , but short IDs will error if no longer available.
Use full IDs for durable automations and storage:
2026-01-31 21:13:13 +09:00
2026-01-21 17:19:38 +00:00
- Templates: `{{MessageSidFull}}` , `{{ReplyToIdFull}}`
- Context: `MessageSidFull` / `ReplyToIdFull` in inbound payloads
See [Configuration ](/gateway/configuration ) for template variables.
2026-01-19 18:50:22 -08:00
## Block streaming
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
Control whether responses are sent as a single message or streamed in blocks:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
```json5
{
channels: {
bluebubbles: {
2026-02-02 01:22:41 -08:00
blockStreaming: true, // enable block streaming (off by default)
2026-01-31 21:13:13 +09:00
},
},
2026-01-19 18:50:22 -08:00
}
```
## Media + limits
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- Inbound attachments are downloaded and stored in the media cache.
- Media cap via `channels.bluebubbles.mediaMaxMb` (default: 8 MB).
- Outbound text is chunked to `channels.bluebubbles.textChunkLimit` (default: 4000 chars).
2026-02-21 11:18:29 -05:00
## Configuration reference
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
Full configuration: [Configuration ](/gateway/configuration )
Provider options:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- `channels.bluebubbles.enabled` : Enable/disable the channel.
- `channels.bluebubbles.serverUrl` : BlueBubbles REST API base URL.
- `channels.bluebubbles.password` : API password.
- `channels.bluebubbles.webhookPath` : Webhook endpoint path (default: `/bluebubbles-webhook` ).
- `channels.bluebubbles.dmPolicy` : `pairing | allowlist | open | disabled` (default: `pairing` ).
- `channels.bluebubbles.allowFrom` : DM allowlist (handles, emails, E.164 numbers, `chat_id:*` , `chat_guid:*` ).
- `channels.bluebubbles.groupPolicy` : `open | allowlist | disabled` (default: `allowlist` ).
- `channels.bluebubbles.groupAllowFrom` : Group sender allowlist.
- `channels.bluebubbles.groups` : Per-group config (`requireMention` , etc.).
- `channels.bluebubbles.sendReadReceipts` : Send read receipts (default: `true` ).
2026-02-02 01:22:41 -08:00
- `channels.bluebubbles.blockStreaming` : Enable block streaming (default: `false` ; required for streaming replies).
2026-01-19 18:50:22 -08:00
- `channels.bluebubbles.textChunkLimit` : Outbound chunk size in chars (default: 4000).
2026-01-25 13:24:00 +00:00
- `channels.bluebubbles.chunkMode` : `length` (default) splits only when exceeding `textChunkLimit` ; `newline` splits on blank lines (paragraph boundaries) before length chunking.
2026-01-19 18:50:22 -08:00
- `channels.bluebubbles.mediaMaxMb` : Inbound media cap in MB (default: 8).
2026-02-14 17:43:44 +00:00
- `channels.bluebubbles.mediaLocalRoots` : Explicit allowlist of absolute local directories permitted for outbound local media paths. Local path sends are denied by default unless this is configured. Per-account override: `channels.bluebubbles.accounts.<accountId>.mediaLocalRoots` .
2026-01-19 18:50:22 -08:00
- `channels.bluebubbles.historyLimit` : Max group messages for context (0 disables).
- `channels.bluebubbles.dmHistoryLimit` : DM history limit.
- `channels.bluebubbles.actions` : Enable/disable specific actions.
- `channels.bluebubbles.accounts` : Multi-account configuration.
Related global options:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns` ).
- `messages.responsePrefix` .
## Addressing / delivery targets
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
Prefer `chat_guid` for stable routing:
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- `chat_guid:iMessage;-;+15555550123` (preferred for groups)
- `chat_id:123`
- `chat_identifier:...`
- Direct handles: `+15555550123` , `user@example.com`
2026-01-30 03:15:10 +01:00
- If a direct handle does not have an existing DM chat, OpenClaw will create one via `POST /api/v1/chat/new` . This requires the BlueBubbles Private API to be enabled.
2026-01-18 03:17:30 +00:00
## Security
2026-01-31 21:13:13 +09:00
2026-01-18 03:17:30 +00:00
- Webhook requests are authenticated by comparing `guid` /`password` query params or headers against `channels.bluebubbles.password` . Requests from `localhost` are also accepted.
- Keep the API password and webhook endpoint secret (treat them like credentials).
2026-01-27 05:47:45 +00:00
- Localhost trust means a same-host reverse proxy can unintentionally bypass the password. If you proxy the gateway, require auth at the proxy and configure `gateway.trustedProxies` . See [Gateway security ](/gateway/security#reverse-proxy-configuration ).
2026-01-18 03:17:30 +00:00
- Enable HTTPS + firewall rules on the BlueBubbles server if exposing it outside your LAN.
## Troubleshooting
2026-01-31 21:13:13 +09:00
2026-01-19 18:50:22 -08:00
- If typing/read events stop working, check the BlueBubbles webhook logs and verify the gateway path matches `channels.bluebubbles.webhookPath` .
2026-01-30 03:15:10 +01:00
- Pairing codes expire after one hour; use `openclaw pairing list bluebubbles` and `openclaw pairing approve bluebubbles <code>` .
2026-01-18 03:17:30 +00:00
- Reactions require the BlueBubbles private API (`POST /api/v1/message/react` ); ensure the server version exposes it.
2026-01-20 00:43:56 -08:00
- Edit/unsend require macOS 13+ and a compatible BlueBubbles server version. On macOS 26 (Tahoe), edit is currently broken due to private API changes.
- Group icon updates can be flaky on macOS 26 (Tahoe): the API may return success but the new icon does not sync.
2026-01-30 03:15:10 +01:00
- OpenClaw auto-hides known-broken actions based on the BlueBubbles server's macOS version. If edit still appears on macOS 26 (Tahoe), disable it manually with `channels.bluebubbles.actions.edit=false` .
- For status/health info: `openclaw status --all` or `openclaw status --deep` .
2026-01-18 03:17:30 +00:00
2026-02-07 15:40:35 -05:00
For general channel workflow reference, see [Channels ](/channels ) and the [Plugins ](/tools/plugin ) guide.