Beeper Matrix
Matrix adapter built and maintained by Beeper. Runs over Matrix sync (no webhooks) and works with Beeper conversations and bridged networks like WhatsApp, Telegram, Instagram, and Signal.
Install
Requires Node.js 22+.
pnpm add @beeper/chat-adapter-matrixQuick start
createMatrixAdapter() reads its configuration from environment variables when called without arguments.
import { Chat } from "chat";
import { createMemoryState } from "@chat-adapter/state-memory";
import { createMatrixAdapter } from "@beeper/chat-adapter-matrix";
const matrix = createMatrixAdapter();
const bot = new Chat({
userName: process.env.MATRIX_BOT_USERNAME ?? "beeper-bot",
state: createMemoryState(),
adapters: { matrix },
});
bot.onNewMention(async (thread, message) => {
await thread.subscribe();
await thread.post(`Hi ${message.author.userName}. Mention me or run /ping.`);
});
bot.onSlashCommand("/ping", async (event) => {
await event.channel.post("pong");
});
await bot.initialize();The standard Chat SDK building blocks — Threads, Direct Messages, subscriptions, and handlers — work the same here. The Matrix adapter just maps them onto Matrix rooms and threaded replies.
Authentication
Access token
Use a long-lived access token from your Matrix homeserver:
import { createMatrixAdapter } from "@beeper/chat-adapter-matrix";
createMatrixAdapter({
baseURL: process.env.MATRIX_BASE_URL,
auth: {
type: "accessToken",
accessToken: process.env.MATRIX_ACCESS_TOKEN,
userID: process.env.MATRIX_USER_ID,
},
});Username and password
createMatrixAdapter({
baseURL: process.env.MATRIX_BASE_URL,
auth: {
type: "password",
username: process.env.MATRIX_USERNAME,
password: process.env.MATRIX_PASSWORD,
userID: process.env.MATRIX_USER_ID,
},
});The adapter persists the resulting login session through your state adapter, so subsequent restarts reuse the existing session instead of logging in again.
Configuration
createMatrixAdapter({
baseURL: process.env.MATRIX_BASE_URL,
auth: {
type: "accessToken",
accessToken: process.env.MATRIX_ACCESS_TOKEN,
userID: process.env.MATRIX_USER_ID,
},
recoveryKey: process.env.MATRIX_RECOVERY_KEY,
commandPrefix: "/",
roomAllowlist: ["!room:beeper.com"],
inviteAutoJoin: {
inviterAllowlist: ["@alice:beeper.com", "@ops:beeper.com"],
},
matrixSDKLogLevel: "error",
});Defaults worth knowing:
- Persistence kicks in automatically whenever the
Chatinstance has astateadapter — Redis is recommended for restart durability. deviceIDis inferred from the auth payload when possible, then read back from state, and only generated as a last resort.recoveryKeyenables E2EE and key-backup bootstrap.inviteAutoJoin: {}enables invite auto-join. PassinviterAllowlistto scope it to specific accounts.
Advanced options
createMatrixAdapter({
baseURL: process.env.MATRIX_BASE_URL,
auth: {
type: "accessToken",
accessToken: process.env.MATRIX_ACCESS_TOKEN,
userID: process.env.MATRIX_USER_ID,
},
e2ee: {
useIndexedDB: false,
cryptoDatabasePrefix: "beeper-matrix-bot",
},
persistence: {
keyPrefix: "my-bot",
session: {
ttlMs: 86_400_000,
},
sync: {
persistIntervalMs: 10_000,
},
},
});Environment variables
When you call createMatrixAdapter() with no arguments, the adapter reads only these variables:
| Variable | Required | Description |
|---|---|---|
MATRIX_BASE_URL | Yes | Matrix homeserver base URL |
MATRIX_ACCESS_TOKEN | Yes* | Access token for access-token auth |
MATRIX_USERNAME | Yes* | Username for password auth |
MATRIX_PASSWORD | Yes* | Password for password auth |
MATRIX_USER_ID | No | User ID hint |
MATRIX_DEVICE_ID | No | Explicit device ID override |
MATRIX_RECOVERY_KEY | No | Enables E2EE and key-backup bootstrap |
MATRIX_BOT_USERNAME | No | Mention-detection username |
MATRIX_COMMAND_PREFIX | No | Slash command prefix (default: /) |
MATRIX_INVITE_AUTOJOIN | No | Enable invite auto-join |
MATRIX_INVITE_AUTOJOIN_ALLOWLIST | No | Comma-separated Matrix user IDs allowed to invite the bot |
MATRIX_SDK_LOG_LEVEL | No | Matrix SDK log level |
*Use either MATRIX_ACCESS_TOKEN, or MATRIX_USERNAME plus MATRIX_PASSWORD.
Persistence
For production, pair the adapter with a durable state adapter such as Redis:
import { Chat } from "chat";
import { createRedisState } from "@chat-adapter/state-redis";
import { createMatrixAdapter } from "@beeper/chat-adapter-matrix";
const matrix = createMatrixAdapter({
baseURL: process.env.MATRIX_BASE_URL,
auth: {
type: "accessToken",
accessToken: process.env.MATRIX_ACCESS_TOKEN,
userID: process.env.MATRIX_USER_ID,
},
recoveryKey: process.env.MATRIX_RECOVERY_KEY,
});
const bot = new Chat({
userName: process.env.MATRIX_BOT_USERNAME ?? "beeper-bot",
state: createRedisState({ url: process.env.REDIS_URL }),
adapters: { matrix },
});The state adapter persists:
- Generated or inferred device IDs
- Password-login sessions
- DM room mappings
- Matrix sync snapshots
- E2EE secrets bundles when E2EE is enabled
Thread model
- A Matrix room is a Chat SDK channel.
- Top-level room messages live on the channel timeline.
- Matrix threaded replies map to Chat SDK threads using
roomID + rootEventID. openDM(userId)reuses an existing direct room when one is already in state and creates a new one otherwise.
Message history APIs
The adapter implements the standard fetch surface:
fetchMessage(threadId, messageId)fetchMessages(threadId, options)fetchChannelMessages(channelId, options)fetchThread(threadId)fetchChannelInfo(channelId)listThreads(channelId, options)openDM(userId)
Limitations
handleWebhook()returns501by design — Matrix uses sync polling, not webhooks.- Cards, modals, and ephemeral messages are not implemented (Matrix has no native equivalent).
- Native streaming is not implemented at the adapter layer.
- Slash commands are parsed from plain text messages because Matrix does not emit native slash command events.
Feature support
Messaging
| Feature | Supported |
|---|---|
| Post message | |
| Edit message | |
| Delete message | |
| File uploads | |
| Streaming | |
| Scheduled messages |
Rich content
| Feature | Supported |
|---|---|
| Card format | |
| Buttons | |
| Link buttons | |
| Select menus | |
| Tables | |
| Fields | |
| Images in cards | |
| Modals |
Conversations
| Feature | Supported |
|---|---|
| Slash commands | Prefix-parsed |
| Mentions | |
| Add reactions | |
| Remove reactions | |
| Typing indicator | |
| DMs | |
| Ephemeral messages | |
| User lookup | |
| Parent subject | |
| Native client | |
| Custom API endpoint | baseURL |
Message history
| Feature | Supported |
|---|---|
| Fetch messages | |
| Fetch single message | |
| Fetch thread info | |
| Fetch channel messages | |
| List threads | |
| Fetch channel info | |
| Post channel message |