Back to Blog
TutorialFebruary 2, 202613 min

iMessage AI Bot with BlueBubbles Setup Guide

Build an AI assistant for iMessage using BlueBubbles on macOS. Full feature support including reactions and effects.

imessagebluebubblesmacosappleai chatbot

Molted Team

Molted.cloud

iMessage is the messaging platform Apple users actually use. Unlike WhatsApp or Telegram, there is no official bot API. But with BlueBubbles running on a Mac, you can build an AI assistant that responds to your iMessages. This guide shows how.

Why iMessage AI is different

Apple does not provide a public iMessage API. The only way to automate iMessage is:

  • BlueBubbles - macOS app that exposes iMessage via REST API
  • imsg - Native macOS integration (legacy approach)
  • Jailbreak tweaks - iOS-based, not recommended

BlueBubbles is the most reliable option. It runs on a Mac (can be a Mac Mini) and provides a full API for sending/receiving messages.

Requirements

  • A Mac that stays on - Mac Mini is perfect for this
  • macOS with iMessage signed in
  • BlueBubbles server app
  • Full Disk Access permission for BlueBubbles

Install BlueBubbles server

  1. Download BlueBubbles from bluebubbles.app
  2. Install and open the app
  3. Grant Full Disk Access (System Settings → Privacy → Full Disk Access)
  4. Sign in to your iCloud account in Messages app
  5. Configure BlueBubbles server settings

Enable the API

In BlueBubbles settings:

  • Enable "Private API" features for full functionality
  • Set a server password
  • Note your server URL (local or with Ngrok/Cloudflare tunnel)

Project setup

mkdir imessage-ai
cd imessage-ai
npm init -y
npm install axios @anthropic-ai/sdk dotenv express

Create .env:

BLUEBUBBLES_URL=http://localhost:1234
BLUEBUBBLES_PASSWORD=your-server-password
ANTHROPIC_API_KEY=your-anthropic-key

BlueBubbles API client

require('dotenv').config();
const axios = require('axios');
const Anthropic = require('@anthropic-ai/sdk');
const express = require('express');

const BB_URL = process.env.BLUEBUBBLES_URL;
const BB_PASSWORD = process.env.BLUEBUBBLES_PASSWORD;

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const conversations = new Map();

// BlueBubbles API helper
const bb = axios.create({
  baseURL: BB_URL,
  params: { password: BB_PASSWORD },
});

// Send message via BlueBubbles
async function sendMessage(chatGuid, text) {
  await bb.post('/api/v1/message/text', {
    chatGuid,
    message: text,
    method: 'private-api', // Uses private API for delivery receipts
  });
}

// Get recent messages from a chat
async function getChatMessages(chatGuid, limit = 10) {
  const response = await bb.get(`/api/v1/chat/${chatGuid}/message`, {
    params: { limit, sort: 'DESC' },
  });
  return response.data.data;
}

// Process incoming message with AI
async function handleMessage(chatGuid, text, senderName) {
  // Get or create conversation
  if (!conversations.has(chatGuid)) {
    conversations.set(chatGuid, []);
  }
  const history = conversations.get(chatGuid);

  // Add user message
  history.push({ role: 'user', content: text });

  // Trim history
  if (history.length > 20) {
    history.splice(0, history.length - 20);
  }

  try {
    const response = await anthropic.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      system: `You are a helpful iMessage assistant. Keep responses concise for mobile.
The user's name is ${senderName}.`,
      messages: history,
    });

    const reply = response.content[0].text;
    history.push({ role: 'assistant', content: reply });

    await sendMessage(chatGuid, reply);
  } catch (error) {
    console.error('Error:', error);
    await sendMessage(chatGuid, 'Sorry, I encountered an error.');
  }
}

// Webhook server for BlueBubbles events
const app = express();
app.use(express.json());

app.post('/webhook', async (req, res) => {
  const { type, data } = req.body;

  if (type === 'new-message') {
    const message = data;

    // Ignore our own messages
    if (message.isFromMe) {
      return res.sendStatus(200);
    }

    const chatGuid = message.chats?.[0]?.guid;
    const text = message.text;
    const senderName = message.handle?.firstName || 'User';

    if (chatGuid && text) {
      await handleMessage(chatGuid, text, senderName);
    }
  }

  res.sendStatus(200);
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
  console.log('Configure BlueBubbles to send webhooks to http://localhost:3000/webhook');
});

iMessage AI made easy

OpenClaw includes BlueBubbles integration. Configure once, works forever.

Start free trial

Configure BlueBubbles webhook

In BlueBubbles settings → Webhooks:

  1. Add new webhook URL: http://localhost:3000/webhook
  2. Enable "New Message" events
  3. Save

Now every incoming iMessage triggers your AI handler.

Handle images

app.post('/webhook', async (req, res) => {
  const { type, data } = req.body;

  if (type === 'new-message') {
    const message = data;
    if (message.isFromMe) return res.sendStatus(200);

    const chatGuid = message.chats?.[0]?.guid;

    // Check for attachments
    if (message.attachments?.length > 0) {
      const attachment = message.attachments[0];

      if (attachment.mimeType?.startsWith('image/')) {
        // Download attachment
        const imageResponse = await bb.get(
          `/api/v1/attachment/${attachment.guid}/download`,
          { responseType: 'arraybuffer' }
        );

        const base64 = Buffer.from(imageResponse.data).toString('base64');

        const aiResponse = await anthropic.messages.create({
          model: 'claude-sonnet-4-20250514',
          max_tokens: 1024,
          messages: [{
            role: 'user',
            content: [
              {
                type: 'image',
                source: {
                  type: 'base64',
                  media_type: attachment.mimeType,
                  data: base64,
                },
              },
              {
                type: 'text',
                text: message.text || 'What is in this image?',
              },
            ],
          }],
        });

        await sendMessage(chatGuid, aiResponse.content[0].text);
        return res.sendStatus(200);
      }
    }

    // Handle text messages
    if (message.text) {
      await handleMessage(chatGuid, message.text, message.handle?.firstName);
    }
  }

  res.sendStatus(200);
});

Group chat support

app.post('/webhook', async (req, res) => {
  const { type, data } = req.body;

  if (type === 'new-message') {
    const message = data;
    const chat = message.chats?.[0];
    const isGroupChat = chat?.participants?.length > 1;

    // In group chats, only respond if mentioned
    if (isGroupChat) {
      const botName = 'AI'; // Your trigger word
      if (!message.text?.toLowerCase().includes(botName.toLowerCase())) {
        return res.sendStatus(200);
      }
    }

    // ... rest of handler
  }
});

Reactions and effects

BlueBubbles Private API supports iMessage features:

// Send a reaction
await bb.post('/api/v1/message/react', {
  chatGuid,
  messageGuid: originalMessageGuid,
  reaction: 'love', // love, like, dislike, laugh, emphasize, question
});

// Send with effect
await bb.post('/api/v1/message/text', {
  chatGuid,
  message: 'Congrats!',
  method: 'private-api',
  effectId: 'com.apple.messages.effect.CKConfettiEffect',
});

Full iMessage AI experience

OpenClaw on Molted supports reactions, effects, and group chats. No code needed.

Try free for 24 hours

Keep it running

For 24/7 operation:

# Install PM2
npm install -g pm2

# Start with PM2
pm2 start index.js --name imessage-ai

# Auto-start on boot
pm2 startup
pm2 save

Also configure your Mac:

  • Disable sleep (System Settings → Energy Saver)
  • Enable "Prevent automatic sleeping when display is off"
  • Set BlueBubbles to launch at login

Limitations

  • Requires a Mac - No way around this for iMessage
  • Private API risks - Apple could break it with updates
  • Single account - One iMessage account per Mac
  • No business API - This is for personal use

OpenClaw alternative

OpenClaw supports BlueBubbles as a channel. If you have BlueBubbles running, you can:

  1. Deploy OpenClaw (Molted or self-hosted)
  2. Configure BlueBubbles URL and password
  3. Enable the iMessage channel

OpenClaw handles webhooks, conversation state, and multi-model support automatically.

Related guides

Free 24-hour trial

iMessage AI assistant

OpenClaw with BlueBubbles. Full iMessage support on your Mac Mini.

Start free trial

24-hour free trial · No credit card required · Cancel anytime

Ready to try OpenClaw?

Deploy your AI personal assistant in 60 seconds. No coding required.

Start free trial

24-hour free trial · No credit card required