---
summary: "BlueBubbles setup for the supported iMessage path on macOS."
read_when:
  - Setting up BlueBubbles channel
  - Troubleshooting webhook pairing
  - Configuring iMessage on macOS
title: "BlueBubbles"
---

# BlueBubbles (macOS REST)

Use BlueBubbles when you want the supported iMessage bridge in Fased. The
gateway talks to the BlueBubbles macOS server over HTTP, receives inbound
webhook events, and uses the normal Fased DM and group access model.

Status: bundled channel bridge for iMessage on macOS. New iMessage deployments
should start here. Use the older `imsg` path only for established installs.

## Overview

- Runs on macOS via the BlueBubbles helper app ([bluebubbles.app](https://bluebubbles.app)).
- Recommended/tested: macOS Sequoia (15). macOS Tahoe (26) works, but edit is
  currently broken and group icon updates may report success without syncing.
- Fased talks to BlueBubbles through its REST API.
- Incoming messages arrive by webhook.
- Outgoing replies, typing indicators, read receipts, and tapbacks are REST
  calls.
- Attachments and stickers are ingested as inbound media when possible.
- Pairing and allowlists work like other Fased channels.
- Advanced features include edit, unsend, reply threading, message effects, and
  group management.

## Quick start

You need one macOS host running the BlueBubbles server and one Fased gateway
that can reach it over HTTP. In small setups they can be the same machine.

1. Install the BlueBubbles server on your Mac from
   [bluebubbles.app/install](https://bluebubbles.app/install).
2. In the BlueBubbles config, enable the web API and set a password.
3. Open **Agents**, select the Agent, then use **Agent > Channels >
   BlueBubbles**. Enter the server URL, password, and webhook path. Scripted
   setups can use config:

   ```json5
   {
     channels: {
       bluebubbles: {
         enabled: true,
         serverUrl: "http://192.168.1.100:1234",
         password: "example-password",
         webhookPath: "/bluebubbles-webhook",
       },
     },
   }
   ```

4. Point BlueBubbles webhooks to your gateway:

   ```text
   https://your-gateway-host:3000/bluebubbles-webhook?password=<password>
   ```

5. Start or restart the gateway if the UI asks for it; it will register the
   webhook handler and start pairing.

Security note:

- Always set a webhook password.
- Fased rejects BlueBubbles webhook requests unless they include a password or
  guid that matches `channels.bluebubbles.password`, such as
  `?password=<password>` or `x-password`.

## Keeping Messages.app alive (VM / headless setups)

Some macOS VM or always-on setups can leave Messages.app idle. Incoming events
may stop until the app is opened again. A simple workaround is to poke Messages
every 5 minutes with an AppleScript and 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 &quot;$HOME/Scripts/poke-messages.scpt&quot;</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
```

## Alternate setup paths

Normal browser setup is **Agent > Channels > BlueBubbles**. CLI onboarding can
also prompt for the same fields when you prefer terminal setup:

```
fased onboard
```

The wizard prompts for:

- **Server URL** (required): BlueBubbles server address, for example
  `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:

```
fased channels add --channel bluebubbles --http-url http://192.168.1.100:1234 --password <password>
```

## Access control (DMs + groups)

DMs:

- Default: `channels.bluebubbles.dmPolicy = "pairing"`.
- Unknown senders receive a pairing code. Messages wait for approval, and codes
  expire after 1 hour.
- Approve via:
  - `fased pairing list bluebubbles`
  - `fased pairing approve bluebubbles <CODE>`
- Pairing is the default token exchange. Details: [Pairing](/channels/pairing)

Groups:

- `channels.bluebubbles.groupPolicy = open | allowlist | disabled` (default: `allowlist`).
- `channels.bluebubbles.groupAllowFrom` controls who can trigger in groups when `allowlist` is set.

### Mention gating (groups)

BlueBubbles supports mention gating for group chats, matching iMessage/WhatsApp behavior:

- 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:

```json5
{
  channels: {
    bluebubbles: {
      groupPolicy: "allowlist",
      groupAllowFrom: ["+15555550123"],
      groups: {
        "*": { requireMention: true }, // default for all groups
        "iMessage;-;chat123": { requireMention: false }, // override for specific group
      },
    },
  },
}
```

### Command gating

- 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

- **Typing indicators**: Fased sends typing start events before and during
  response generation. BlueBubbles clears typing automatically on send or
  timeout.
- **Read receipts**: controlled by `channels.bluebubbles.sendReadReceipts`
  (default: `true`).

```json5
{
  channels: {
    bluebubbles: {
      sendReadReceipts: false, // disable read receipts
    },
  },
}
```

## Advanced actions

BlueBubbles supports advanced message actions when enabled in config:

```json5
{
  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:

- **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`)
- **setGroupIcon**: Set a group chat's icon/photo (`chatGuid`, `media`).
  This can be flaky on macOS 26 Tahoe.
- **addParticipant**: Add someone to a group (`chatGuid`, `address`)
- **removeParticipant**: Remove someone from a group (`chatGuid`, `address`)
- **leaveGroup**: Leave a group chat (`chatGuid`)
- **sendAttachment**: Send media/files (`to`, `buffer`, `filename`, `asVoice`)
  - Voice memos: set `asVoice: true` with **MP3** or **CAF** audio. BlueBubbles
    converts MP3 to CAF when sending voice memos.

### Message IDs (short vs full)

Fased 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.
- 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:

- Templates: `{{MessageSidFull}}`, `{{ReplyToIdFull}}`
- Context: `MessageSidFull` / `ReplyToIdFull` in inbound payloads

See [Configuration](/gateway/configuration) for template variables.

## Block streaming

Control whether responses are sent as a single message or streamed in blocks:

```json5
{
  channels: {
    bluebubbles: {
      blockStreaming: true, // enable block streaming (off by default)
    },
  },
}
```

## Media + limits

- 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).

## Configuration reference

Full configuration: [Configuration](/gateway/configuration)

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 using handles, emails,
  E.164 numbers, `chat_id:*`, or `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`).
- `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` or `newline`. `newline` splits on
  blank lines before length chunking.
- `channels.bluebubbles.mediaMaxMb`: Inbound media cap in MB (default: 8).
- `channels.bluebubbles.mediaLocalRoots`: Absolute local directories allowed for
  outbound local media paths. Local path sends require this allowlist.
  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`.

## Addressing / delivery targets

Prefer `chat_guid` for stable routing:

- `chat_guid:iMessage;-;+15555550123` (preferred for groups)
- `chat_id:123`
- `chat_identifier:...`
- Direct handles: `+15555550123`, `user@example.com`
  - If a direct handle has no existing DM chat, Fased creates one through
    `POST /api/v1/chat/new`. This requires the BlueBubbles Private API.

## Security

- Webhook requests are authenticated by comparing `guid` or `password` query
  params or headers against `channels.bluebubbles.password`.
- Keep the API password and webhook endpoint secret (treat them like credentials).
- If you proxy the gateway on the same host, require auth at the proxy and
  configure `gateway.trustedProxies`. See
  [Gateway security](/gateway/security#reverse-proxy-configuration).
- Enable HTTPS + firewall rules on the BlueBubbles server if exposing it outside your LAN.

## Troubleshooting

- If typing/read events stop working, check BlueBubbles webhook logs and verify
  the gateway path matches `channels.bluebubbles.webhookPath`.
- Pairing codes expire after one hour; use `fased pairing list bluebubbles`
  and `fased pairing approve bluebubbles <code>`.
- Reactions require the BlueBubbles private API (`POST /api/v1/message/react`); ensure the server version exposes it.
- 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.
- Fased 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: `fased status --all` or `fased status --deep`.

For general channel workflow reference, see [Channels](/channels) and the [Plugins](/tools/plugin) guide.
