Sign in

API Reference - @liveblocks/chat-sdk-adapter

@liveblocks/chat-sdk-adapter is a Chat SDK platform adapter backed by Liveblocks Comments. It maps Liveblocks rooms, threads, and comments to the Chat SDK's Channel / Thread / Message model, allowing you to build conversational bots that read and post in Liveblocks comment threads.

Installation

Terminal
npm install @liveblocks/chat-sdk-adapter chat

Prerequisites

Before using this adapter, ensure you have:

  1. A Liveblocks project with rooms using Comments.
  2. A secret key (sk_...) from the Liveblocks dashboard for REST API calls.
  3. A webhook signing secret (whsec_...) from the dashboard to verify webhook payloads.
  4. Webhooks configured to subscribe to commentCreated, commentReactionAdded, and commentReactionRemoved events.
  5. A stable botUserId that matches how you identify users in your app.

createLiveblocksAdapter

Factory function that creates a new LiveblocksAdapter instance.

import { createLiveblocksAdapter } from "@liveblocks/chat-sdk-adapter";
const adapter = createLiveblocksAdapter({ apiKey: "", webhookSecret: "whsec_...", botUserId: "my-bot-user", botUserName: "MyBot",});

Configuration options

  • apiKeystringRequired

    Liveblocks secret key (sk_...) for REST API calls.

  • webhookSecretstringRequired

    Webhook signing secret (whsec_...) from the dashboard.

  • botUserIdstringRequired

    User ID used when the bot creates, edits, or reacts to comments. Should match your app's user identifiers.

  • botUserNamestringDefault is "liveblocks-bot"

    Display name for the bot.

  • resolveUsersfunction

    Resolves user IDs to user info for mentions. Returns an array of user info in the same order as the input IDs, or undefined to skip resolution.

  • resolveGroupsInfofunction

    Resolves group IDs to group info for mentions. Returns an array of group info in the same order as the input IDs, or undefined to skip resolution.

  • loggerLoggerDefault is ConsoleLogger('info')

    Chat SDK-compatible logger instance.

Resolving mentions

When comments contain @mentions, the adapter needs to resolve user and group IDs to display names. Use resolveUsers and resolveGroupsInfo to provide this mapping:

const adapter = createLiveblocksAdapter({  apiKey: "",  webhookSecret: "whsec_...",  botUserId: "my-bot-user",
resolveUsers: async ({ userIds }) => { const users = await getUsersFromDatabase(userIds); return users.map((user) => ({ name: user.fullName, avatar: user.avatarUrl, })); },
resolveGroupsInfo: async ({ groupIds }) => { const groups = await getGroupsFromDatabase(groupIds); return groups.map((group) => ({ name: group.displayName })); },});

Webhook events

The adapter processes incoming Liveblocks webhook requests via the Chat SDK's webhook handler. Supported events:

  • commentCreated — Triggers message processing in the Chat SDK
  • commentReactionAdded — Triggers reaction handlers
  • commentReactionRemoved — Triggers reaction handlers
export async function POST(request: Request) {  return bot.webhooks.liveblocks(request, {    waitUntil: (p) => void p,  });}
Webhook verification

The adapter automatically verifies webhook signatures using the webhookSecret provided during configuration. Invalid requests receive a 401 response.

ID encoding

The adapter uses a prefixed encoding scheme for thread and channel IDs:

  • Thread ID: liveblocks:{roomId}:{threadId}
  • Channel ID: liveblocks:{roomId}

encodeThreadId

Encodes a Liveblocks room ID and thread ID into a single thread ID string.

adapter.encodeThreadId(data: { roomId: string; threadId: string }): string
const encoded = adapter.encodeThreadId({  roomId: "my-room",  threadId: "th_abc123",});// "liveblocks:my-room:th_abc123"

decodeThreadId

Decodes an encoded thread ID string back into its room ID and thread ID components. Throws an Error if the format is invalid.

adapter.decodeThreadId(threadId: string): { roomId: string; threadId: string }
const { roomId, threadId } = adapter.decodeThreadId(  "liveblocks:my-room:th_abc123");// roomId: "my-room"// threadId: "th_abc123"

Room IDs may contain colons (:), which are preserved during encoding/decoding. However, Liveblocks thread IDs must not contain colons as the last colon is used as the delimiter when decoding.

Liveblocks-specific behavior

Reactions

Liveblocks Comments only supports Unicode emoji. Custom emoji identifiers that cannot be resolved to Unicode will fail validation.

await adapter.addReaction(threadId, messageId, "👍"); // Worksawait adapter.addReaction(threadId, messageId, "thumbs_up"); // Converted to 👍

Typing indicators

The startTyping method is a no-op as typing indicators are not supported by Liveblocks Comments.

Message format limitations

Limited formatting support

Liveblocks Comments has a simpler content model than full Markdown. Content from the Chat SDK is automatically converted, but some formatting is flattened.

Liveblocks Comments supports:

  • Paragraphs with inline formatting (bold, italic, code, strikethrough)
  • Links
  • @mentions (users and groups)

The following are not supported and will be flattened to plain text:

  • Headings — Converted to paragraphs
  • Bullet and numbered lists — Converted to paragraphs
  • Code blocks — Converted to paragraphs
  • Tables — Converted to ASCII representation in a paragraph
  • HTML — Rendered as plain text

Card payloads from the Chat SDK are converted to markdown/plain text (or use fallbackText if provided), then converted to a comment body. Interactivity is not preserved.

Example

Here's a complete example integrating the adapter with the Chat SDK:

import { Chat } from "chat";import {  createLiveblocksAdapter,  LiveblocksAdapter,} from "@liveblocks/chat-sdk-adapter";import { createMemoryState } from "@chat-adapter/state-memory";
const bot = new Chat<{ liveblocks: LiveblocksAdapter }>({ userName: "MyBot", adapters: { liveblocks: createLiveblocksAdapter({ apiKey: "", webhookSecret: "whsec_...", botUserId: "my-bot-user", botUserName: "MyBot", resolveUsers: async ({ userIds }) => { const users = await getUsersFromDatabase(userIds); return users.map((user) => ({ name: user.fullName })); }, }), }, state: createMemoryState(),});
bot.onNewMention(async (thread, message) => { await thread.adapter.addReaction(thread.id, message.id, "👀"); await thread.post(`Hello, ${message.author.userName}!`);});
bot.onReaction(async (event) => { if (!event.added) return; await event.adapter.postMessage( event.threadId, `${event.user.userName} reacted with "${event.emoji.name}"` );});

Webhook handler (Next.js)

import { bot } from "./bot";
export async function POST(request: Request) { return bot.webhooks.liveblocks(request, { waitUntil: (p) => void p, });}

The waitUntil option is recommended for serverless environments (e.g., Vercel) to allow background processing of messages after the response is sent.