
OpenClaw Integration with BlueBubbles (macOS REST)

By Sarah Jenkins


By Sarah Jenkins
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.
GET /api/v1/ping, POST /message/text, POST /chat/:id/*)./channels/pairing etc) with channels.bluebubbles.allowFrom + pairing codes.Security note:
channels.bluebubbles.password (for example ?password=<password> or x-password), regardless of loopback/proxy topology.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.
Save this as:
~/Scripts/poke-messages.scptExample script (non-interactive; does not steal focus):
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 trySave this as:
~/Library/LaunchAgents/com.user.poke-messages.plist<?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:
osascript → Messages). Approve them in the same user session that runs the LaunchAgent.Load it:
launchctl unload ~/Library/LaunchAgents/com.user.poke-messages.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plistBlueBubbles is available in interactive onboarding:
openclaw onboardThe wizard prompts for:
http://192.168.1.100:1234)/bluebubbles-webhookYou can also add BlueBubbles via CLI:
openclaw channels add bluebubbles --http-url http://192.168.1.100:1234 --password <password>DMs:
channels.bluebubbles.dmPolicy = "pairing".Groups:
channels.bluebubbles.groupPolicy = open | allowlist | disabled (default: allowlist).channels.bluebubbles.groupAllowFrom controls who can trigger in groups when allowlist is set.BlueBubbles group webhooks often only include raw participant addresses. If you want GroupMembers context to show local contact names instead, you can opt in to local Contacts enrichment on macOS:
channels.bluebubbles.enrichGroupParticipantsFromContacts = true enables the lookup. Default: false.{
channels: {
bluebubbles: {
enrichGroupParticipantsFromContacts: true,
},
},
}BlueBubbles supports mention gating for group chats, matching iMessage/WhatsApp behavior:
agents.list[].groupChat.mentionPatterns (or messages.groupChat.mentionPatterns) to detect mentions.requireMention is enabled for a group, the agent only responds when mentioned.Per-group configuration:
{
channels: {
bluebubbles: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
"*": { requireMention: true }, // default for all groups
"iMessage;-;chat123": { requireMention: false }, // override for specific group
},
},
},
}/config, /model) require authorization.allowFrom and groupAllowFrom to determine command authorization.BlueBubbles chats can be turned into durable ACP workspaces without changing the transport layer.
Fast operator flow:
/acp spawn codex --bind here inside the DM or allowed group chat./new and /reset reset the same bound ACP session in place./acp close closes the ACP session and removes the binding.Configured persistent bindings are also supported through top-level bindings[] entries with type: "acp" and match.channel: "bluebubbles".
match.peer.id can use any supported BlueBubbles target form:
+15555550123 or user@example.comchat_id:<id>chat_guid:<guid>chat_identifier:<identifier>For stable group bindings, prefer chat_id:* or chat_identifier:*.
Example:
{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: { agent: "codex", backend: "acpx", mode: "persistent" },
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "bluebubbles",
accountId: "default",
peer: { kind: "dm", id: "+15555550123" },
},
acp: { label: "codex-imessage" },
},
],
}channels.bluebubbles.sendReadReceipts (default: true).{
channels: {
bluebubbles: {
sendReadReceipts: false, // disable read receipts
},
},
}BlueBubbles supports advanced message actions when enabled in config:
{
channels: {
bluebubbles: {
actions: {
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
removeParticipant: true, // remove participants from groups
leaveGroup: true, // leave group chats
sendAttachment: true, // send attachments/media
},
},
},
}Available actions:
messageId, emoji, remove)messageId, text)messageId)messageId, text, to)text, to, effectId)chatGuid, displayName)chatGuid, media) — flaky on macOS 26 Tahoe (API may return success but the icon does not sync).chatGuid, address)chatGuid, address)chatGuid)to, buffer, filename, asVoice)sendAttachment still works, but upload-file is the canonical action name.OpenClaw may surface short message IDs (e.g., 1, 2) to save tokens.
MessageSid / ReplyToId can be short IDs.MessageSidFull / ReplyToIdFull contain the provider full IDs.messageId, but short IDs will error if no longer available.Use full IDs for durable automations and storage:
{{MessageSidFull}}, {{ReplyToIdFull}}MessageSidFull / ReplyToIdFull in inbound payloadsControl whether responses are sent as a single message or streamed in blocks:
{
channels: {
bluebubbles: {
blockStreaming: true, // enable block streaming (off by default)
},
},
}channels.bluebubbles.mediaMaxMb for inbound and outbound media (default: 8 MB).channels.bluebubbles.textChunkLimit (default: 4000 chars).Provider options:
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.enrichGroupParticipantsFromContacts: On macOS, optionally enrich unnamed group participants from local Contacts after gating passes. Default: false.channels.bluebubbles.groups: Per-group config (requireMention, etc.).channels.bluebubbles.sendReadReceipts: Send read receipts (default: true).channels.bluebubbles.blockStreaming: Enable block streaming (default: false; required for streaming replies).channels.bluebubbles.textChunkLimit: Outbound chunk size in chars (default: 4000).channels.bluebubbles.chunkMode: length (default) splits only when exceeding textChunkLimit; newline splits on blank lines (paragraph boundaries) before length chunking.channels.bluebubbles.mediaMaxMb: Inbound/outbound media cap in MB (default: 8).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.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:
agents.list[].groupChat.mentionPatterns (or messages.groupChat.mentionPatterns).messages.responsePrefix.Prefer chat_guid for stable routing:
chat_guid:iMessage;-;+15555550123 (preferred for groups)chat_id:123chat_identifier:...+15555550123, user@example.comguid/password query params or headers against channels.bluebubbles.password. Requests from localhost are also accepted.gateway.trustedProxies.channels.bluebubbles.webhookPath.openclaw pairing list bluebubbles and openclaw pairing approve bluebubbles <code>.POST /api/v1/message/react); ensure the server version exposes it.channels.bluebubbles.actions.edit=false.openclaw status --all or openclaw status --deep.For general channel workflow reference, see Channels and the Plugins guide.
About the author

Sarah Jenkins is a seasoned OpenClaw developer with a strong focus on optimizing high-performance computing solutions. Her work primarily involves crafting efficient parallel algorithms and enhancing GPU acceleration for complex scientific simulations. Jenkins is renowned for her meticulous attention to detail and her ability to translate intricate theoretical concepts into practical, robust OpenClaw implementations.