chat-adapter-imessage
iMessage community adapter for Chat SDK. Supports both local (on-device) and remote (Photon-based) iMessage integration.
Installation
Usage
The adapter supports two modes: local (running directly on a Mac with iMessage) and remote (connecting to a Photon iMessage server). The mode is auto-detected from the IMESSAGE_LOCAL environment variable.
Remote mode
Recommended for production. Connects to Photon's managed iMessage service over HTTP and Socket.IO, so your bot can run on any platform.
Local mode
For development or self-hosted deployments using imessage-kit. Reads from the local iMessage database and sends via AppleScript. Must run on macOS with Full Disk Access granted.
Agent Skill
An agent skill for this adapter is available in the photon-hq/skills repository. It provides a comprehensive, source-accurate reference that enables AI coding assistants (Cursor, Claude Code, Copilot, and others) to build with this adapter without needing to read the source.
The skill covers setup, both local and remote modes, all adapter methods, type definitions, webhook payload shapes, and common pitfalls.
Setup
Remote mode
Remote mode connects to a Photon iMessage server, which handles the macOS-side integration on your behalf. You'll need an active Photon subscription to get your server credentials.
- Request access from Photon to get your server credentials
- Copy your server URL and API key from the Photon dashboard
- Set
IMESSAGE_SERVER_URLandIMESSAGE_API_KEYenvironment variables - Set
IMESSAGE_LOCAL=false
Local mode
Local mode requires the adapter to run directly on a macOS machine with iMessage. It uses Apple's native APIs — reading from the local chat.db database and sending messages via AppleScript — with no external server required.
- Grant Full Disk Access to your terminal or application in System Settings > Privacy & Security > Full Disk Access
- Ensure iMessage is signed in and working on the Mac
- No additional environment variables are required — local mode is the default
Receiving messages
Call startGatewayListener() to listen for new messages in real-time. In remote mode, this uses Socket.IO push events. In local mode, it polls the iMessage database.
In serverless environments, use a cron job to maintain the connection.
Gateway setup for serverless
1. Create Gateway route
2. Configure Vercel Cron
This runs every 9 minutes, ensuring overlap with the 10-minute listener duration.
3. Environment variables
CRON_SECRET is automatically added by Vercel when you configure cron jobs.
Configuration
Environment variables
Features
Modals (Limited)
Remote mode supports limited modal functionality by mapping the Chat SDK's openModal() to iMessage native polls via the Photon SDK. Only Select children are supported — the first Select in the modal is used to create a poll.
Modal.titlebecomes the poll questionSelect.optionsbecome the poll choices- Votes trigger
onModalSubmitwith the selected option'svalue
Not supported:
Select.placeholderandSelect.label— iMessage polls don't have these fieldsTextInput,RadioSelect, and other modal children — silently ignoredModal.submitLabelandModal.closeLabel— not applicable to polls- Only the first
Selectchild is used; other children are ignored - Local mode —
openModal()throwsNotImplementedError
Tapback reactions
iMessage uses tapbacks instead of emoji reactions. The adapter maps standard emoji names to iMessage tapbacks:
Limitations
- Local mode: Only supports sending/receiving messages, message history, and file uploads. Reactions, typing indicators, message editing, modals, and thread fetching require remote mode.
- Formatting: iMessage is plain-text only. Markdown formatting (bold, italic, etc.) is stripped when sending messages, preserving only the text content.
- Platform: Local mode requires macOS. Remote mode can run on any platform — Photon manages the iMessage infrastructure for you.
- Cards: iMessage has no support for structured card layouts.
- Modals: Limited to
Select-based modals mapped to iMessage native polls. Only the firstSelectchild is used;placeholder,label,TextInput,RadioSelect, and other fields are not supported. Remote mode only.
Troubleshooting
"serverUrl is required" error
- Set
IMESSAGE_SERVER_URLor passserverUrlin config when using remote mode - This error occurs when
IMESSAGE_LOCAL=falsebut no server URL is provided
"apiKey is required" error
- Set
IMESSAGE_API_KEYor passapiKeyin config when using remote mode
Local mode not receiving messages
- Verify Full Disk Access is granted to your terminal or application
- Check that iMessage is signed in and working
- Messages are polled from the local database — there may be a short delay
Remote mode connection issues
- Verify the server URL is correct and accessible
- Check that the API key matches your Photon iMessage service credentials
- Confirm your Photon subscription is active
License
MIT