### Create Advanced Collaborative Spreadsheet example Source: https://liveblocks.io/docs/tools/devtools Run this command to download and create a local project from the Advanced Collaborative Spreadsheet example. Follow the guided prompts to complete the setup. ```bash npx create-liveblocks-app@latest --example nextjs-spreadsheet-advanced ``` -------------------------------- ### Multiple editors setup example Source: https://liveblocks.io/docs/api-reference/liveblocks-react-blocknote Example of setting up multiple editors on one page, each with a separate field value. ```tsx import { useCreateBlockNoteWithLiveblocks } from "@liveblocks/react-blocknote"; import { BlockNoteView } from "@blocknote/mantine"; function TextEditors() { return (
// +++ // +++
); } function TextEditor({ field }: { field: string }) { const editor = useCreateBlockNoteWithLiveblocks( {}, { // +++ field, // +++ } ); return (
); } ``` -------------------------------- ### Create Liveblocks Starter Kit project Source: https://liveblocks.io/docs/tools/devtools Run this command to create a new Next.js project using the Liveblocks Starter Kit. Follow the guided prompts in the terminal to complete the setup. ```bash npx create-liveblocks-app@latest --next ``` -------------------------------- ### Full editor setup with LiveblocksPlugin and liveblocksConfig Source: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical Complete example of setting up a collaborative Lexical editor. It imports the necessary Lexical components and the Liveblocks plugin, creates an initialConfig with liveblocksConfig, and wraps the editor with LiveblocksPlugin containing FloatingThreads, FloatingComposer, and AnchoredThreads. ```tsx import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; // +++ import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical"; // +++ const initialConfig = liveblocksConfig({ namespace: "MyEditor", theme: {}, nodes: [], onError: (err) => console.error(err), }); function Editor() { return ( // +++ // +++ } placeholder={
Enter some text...
} ErrorBoundary={LexicalErrorBoundary} />
); } ``` -------------------------------- ### Start of app/page.tsx Source: https://liveblocks.io/docs/get-started/nextjs-ai-notifications Start of the app/page.tsx file. The full example is not shown in the source. ```tsx "use client"; ``` -------------------------------- ### Provider setting example Source: https://liveblocks.io/docs/products/ai-copilots/copilots Example value for the provider setting, showing 'OpenAI'. ```text OpenAI ``` -------------------------------- ### Initialize RoomProvider with initial storage Source: https://liveblocks.io/docs/api-reference/upgrading/0.18 Set up a RoomProvider with initial presence and storage containing a LiveObject with nested LiveList. This is the setup used in the following examples. ```tsx ``` -------------------------------- ### Install @liveblocks/chat-sdk-adapter and chat Source: https://liveblocks.io/docs/api-reference/liveblocks-chat-sdk-adapter Install the adapter and the Chat SDK package using npm. ```bash npm install @liveblocks/chat-sdk-adapter chat ``` -------------------------------- ### Implement multiple editors setup Source: https://liveblocks.io/docs/api-reference/liveblocks-react-tiptap Example showing how to render multiple TextEditor components, each with a unique field identifier. ```tsx import { useLiveblocksExtension } from "@liveblocks/react-tiptap"; import { useEditor, EditorContent } from "@tiptap/react"; function TextEditors() { return (
// +++ // +++
); } function TextEditor({ field }: { field: string }) { // +++ const liveblocks = useLiveblocksExtension({ field }); // +++ const editor = useEditor({ extensions: [ liveblocks, // ... ], }); return (
); } ``` -------------------------------- ### Install Supabase library Source: https://liveblocks.io/docs/guides/how-to-synchronize-your-liveblocks-yjs-document-data-to-a-supabase-postgres-database Install the Supabase JavaScript client using npm. ```bash npm i @supabase/supabase-js ``` -------------------------------- ### Example prompt: Add a realtime text editor with Liveblocks and Tiptap Source: https://liveblocks.io/docs/integrations/lovable Use this prompt in the Lovable chat to request adding a realtime text editor with Liveblocks and Tiptap. This is the first step in the setup process. ```text Add a realtime text editor with Liveblocks and Tiptap. ``` -------------------------------- ### Multiple subscriptions: old approach with manual setup Source: https://liveblocks.io/docs/api-reference/upgrading/0.18 Previously, deriving a computed value from multiple storage values required manual subscriptions and cleanup. This example shows the old, verbose method. ```tsx function Component() { const objA = useObject("a"); const objB = useObject("b"); const room = useRoom(); const [sum, setSum] = useState(); // ^^^ We’re trying to compute the result of a.x + b.x in here useEffect(() => { function onChange() { setSum(objA.get("x") + objB.get("x")); } const unsubA = room.subscribe(objA, onChange); const unsubB = room.subscribe(objB, onChange); return () => { unsubA(); unsubB(); }; }, [room, objA, objB]); } ``` -------------------------------- ### Install Liveblocks packages Source: https://liveblocks.io/docs/get-started/nextjs-canvas-custom Install the required Liveblocks client and React packages. ```bash npm install @liveblocks/client @liveblocks/react ``` -------------------------------- ### Simple system prompt example Source: https://liveblocks.io/docs/products/ai-copilots/copilots Example of a simple system prompt. ```text You're a helpful assistant that can answer questions and help with tasks. ``` -------------------------------- ### Install Bun Source: https://liveblocks.io/docs/tools/dev-server Install the Bun runtime required to run the Liveblocks development server. ```bash npm install -g bun ``` -------------------------------- ### Model setting example Source: https://liveblocks.io/docs/products/ai-copilots/copilots Example value for the model setting, showing 'GPT-4.1'. ```text GPT-4.1 ``` -------------------------------- ### Install Liveblocks and Handsontable dependencies Source: https://liveblocks.io/docs/get-started/nextjs-comments-handsontable Install the necessary Liveblocks and Handsontable packages for your project. ```bash npm install @liveblocks/client @liveblocks/react @liveblocks/react-ui @handsontable/react-wrapper handsontable ``` -------------------------------- ### Start development server Source: https://liveblocks.io/docs/tools/nextjs-starter-kit Run the development server to apply changes and view authentication in action. ```bash npm run dev ``` -------------------------------- ### Initialize React project Source: https://liveblocks.io/docs/guides/how-to-create-a-collaborative-online-whiteboard-with-react-redux-and-liveblocks Create a new React application using create-react-app. ```bash npx create-react-app redux-whiteboard ``` -------------------------------- ### Get Comment Success Response Example Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example of a successful response when retrieving a comment by its ID. ```json { "type": "comment", "threadId": "thread-id", "roomId": "room-id", "id": "comment-id", "userId": "alice", "createdAt": "2019-08-24T14:15:22Z", "editedAt": "2019-08-24T14:15:22Z", "deletedAt": "2019-08-24T14:15:22Z", "body": {}, "metadata": {}, "reactions": [], "attachments": [] } ``` -------------------------------- ### Get Thread Success Response Example Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example JSON response returned when successfully retrieving a thread by its ID. ```json { "type": "thread", "id": "thread-id", "roomId": "room-id", "comments": [ { "type": "comment", "threadId": "thread-id", "roomId": "room-id", "id": "comment-id", "userId": "string", "createdAt": "2019-08-24T14:15:22Z", "editedAt": "2019-08-24T14:15:22Z", "deletedAt": "2019-08-24T14:15:22Z", "body": {}, "metadata": {}, "reactions": [], "attachments": [] } ] } ``` -------------------------------- ### Run the dev server Source: https://liveblocks.io/docs/tools/dev-server Start the development server from your project directory. ```bash npx liveblocks dev ``` -------------------------------- ### Full AnchoredThreads implementation example Source: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical This example shows how to retrieve threads using useThreads and render them with AnchoredThreads within a Lexical editor setup. ```tsx import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; import { useThreads } from "@liveblocks/react/suspense"; import { liveblocksConfig, LiveblocksPlugin, FloatingComposer, // +++ AnchoredThreads, // +++ } from "@liveblocks/react-lexical"; const initialConfig = liveblocksConfig({ namespace: "MyEditor", theme: {}, nodes: [], onError: (err) => console.error(err), }); function Editor() { // +++ const { threads } = useThreads(); // +++ return ( // +++ // +++ } placeholder={
Enter some text...
} ErrorBoundary={LexicalErrorBoundary} />
); } ``` -------------------------------- ### Initialize room storage with enterRoom Source: https://liveblocks.io/docs/guides/how-to-use-liveblocks-storage-with-redux Example of initializing the room's storage when entering a room for the first time. ```javascript enterRoom("room-id", { firstName: "Lise", lastName: "Meitner", discoveries: ["Nuclear fission", "Protactinium"],}); ``` -------------------------------- ### Get Storage document response example Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example response showing the structure of a room's storage document in the default plain LSON format. ```json { "liveblocksType": "LiveObject", "data": { "aLiveObject": { "liveblocksType": "LiveObject", "data": { "a": 1 } }, "aLiveList": { "liveblocksType": "LiveList", "data": [ "a", "b" ] }, "aLiveMap": { "liveblocksType": "LiveMap", "data": { "a": 1, "b": 2 } }, "aLiveFile": { "liveblocksType": "LiveFile", "data": { "id": "fl_abc123456789012345678", "name": "photo.png", "size": 12345, "mimeType": "image/png" } } } } ``` -------------------------------- ### Install Liveblocks agent skills with npx Source: https://liveblocks.io/docs/integrations/claude-desktop Installs Liveblocks agent skills for Claude Desktop. Select Claude Desktop in the CLI and use global installation for easiest setup. Re-run this command if skills do not load. ```bash npx skills add liveblocks/skills ``` -------------------------------- ### Complete Chat SDK Adapter Integration Example Source: https://liveblocks.io/docs/api-reference/liveblocks-chat-sdk-adapter Full example of setting up a bot with the Chat SDK and Liveblocks adapter, including configuration, state, and event handlers for mentions and reactions. Uses a placeholder API key and webhook secret. ```TypeScript 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: "{{SECRET_KEY}}", 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}"` ); }); ``` -------------------------------- ### Active Users Response Example Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example JSON response for the GET /rooms/{roomId}/active-users endpoint, showing a list of active users with their connection IDs and IDs. ```json { "data": [ { "type": "user", "connectionId": 16, "id": "alice", "info": {} }, { "type": "user", "connectionId": 20, "id": "bob", "info": {} } ] } ``` -------------------------------- ### Initialize React project Source: https://liveblocks.io/docs/guides/how-to-create-a-collaborative-to-do-list-with-react-zustand-and-liveblocks Create a new React application with TypeScript support using create-react-app. ```bash npx create-react-app zustand-todo-app --template typescript ``` -------------------------------- ### Example query string for REST API Source: https://liveblocks.io/docs/guides/how-to-filter-rooms-using-query-language A query string example that filters rooms by ID prefix and metadata. This query is passed to the query parameter of the Get Rooms REST API. ```js roomId^'liveblocks:' AND metadata['roomType']:'whiteboard' ``` -------------------------------- ### Get Yjs subdocument as binary update Source: https://liveblocks.io/docs/api-reference/liveblocks-node Retrieves a specific subdocument as a binary update by providing its guid. ```ts const binaryYjsUpdate = await liveblocks.getYjsDocumentAsBinaryUpdate( "my-room-id", { // Optional, return a subdocument instead. guid is its unique identifier guid: "c4a755...", } ); ``` -------------------------------- ### Install dependencies Source: https://liveblocks.io/docs/get-started/nextjs-ai-react-flow Install the required Liveblocks, Vercel AI SDK, OpenAI, and Zod packages. ```bash npm install @liveblocks/node @liveblocks/react-flow ai @ai-sdk/openai zod ``` -------------------------------- ### Get Storage File Parameters Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example values for the roomId and fileId path parameters used when retrieving a Storage file. ```json { "schema": { "type": "string", "description": "ID of the room", "example": "my-room-id" }, "name": "roomId", "in": "path", "required": true }, { "schema": { "type": "string", "pattern": "^fl_[A-Za-z0-9_-]{21}$", "description": "ID of the Storage file", "example": "fl_abc123456789012345678" }, "name": "fileId", "in": "path", "required": true } ``` -------------------------------- ### Install Liveblocks and React Flow packages Source: https://liveblocks.io/docs/get-started/nextjs-react-flow Install all required Liveblocks and React Flow packages with npm, then initialize the Liveblocks configuration file using the CLI. Both commands are run in the terminal. ```bash npm install @liveblocks/client @liveblocks/react @liveblocks/react-ui @liveblocks/react-flow @xyflow/react ``` ```bash npx create-liveblocks-app@latest --init --framework react ``` -------------------------------- ### Notification event object structure Source: https://liveblocks.io/docs/products/notifications/email-notifications An example of the event object received when a user gets a new or updated inbox notification on the email channel. ```ts const event = { type: "notification", data: { channel: "email", kind: "$myCustomNotification", projectId: "my-project-id", roomId: "my-room-id", userId: "my-user-id", inboxNotificationId: "in_xt3p7ak...", createdAt: "2021-10-06T01:45:56.558Z", }, }; ``` -------------------------------- ### Initialize Storage Document Request Body Example Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints Example structure for the request body when initializing a room's storage. ```json { "liveblocksType": "LiveObject" ``` -------------------------------- ### Passing liveblocksConfig to LexicalComposer Source: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical Complete example of passing the config created by liveblocksConfig to LexicalComposer's initialConfig. Includes the full editor setup with LiveblocksPlugin and RichTextPlugin. ```tsx import { LexicalComposer } from "@lexical/react/LexicalComposer"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical"; const initialConfig = liveblocksConfig({ namespace: "MyEditor", theme: {}, nodes: [], onError: (err) => console.error(err), }); function Editor() { return ( } placeholder={
Enter some text...
} ErrorBoundary={LexicalErrorBoundary} />
); } ``` -------------------------------- ### Initialize Liveblocks client and storage Source: https://liveblocks.io/docs/guides/how-to-create-a-collaborative-to-do-list-with-javascript-and-liveblocks This snippet demonstrates how to initialize the Liveblocks client, enter a room, and set up an initial storage state using a LiveList to hold to-do items. ```javascript import { createClient, LiveList } from "@liveblocks/client"; const client = createClient({ publicApiKey: "pk_prod_xxxxxxxxxx…xxxxxxxxpk_prod_xxxxxxxxxxxxxxxxxxxxxxxx",}); async function run() { const { room, leave } = client.enterRoom("javascript-todo-app", { initialPresence: { isTyping: false }, initialStorage: { todos: new LiveList() }, }); const whoIsHere = document.getElementById("who_is_here"); const todoInput = document.getElementById("todo_input"); const someoneIsTyping = document.getElementById("someone_is_typing"); const { root } = await room.getStorage(); let todos = root.get("todos"); room.subscribe("others", (others) => { /* ... */ }); todoInput.addEventListener("keydown", (e) => { if (e.key === "Enter") { room.updatePresence({ isTyping: false }); todos.push({ text: todoInput.value }); todoInput.value = ""; } else { room.updatePresence({ isTyping: true }); } }); todoInput.addEventListener("blur", () => { room.updatePresence({ isTyping: false }); });} run(); ``` -------------------------------- ### Project structure overview Source: https://liveblocks.io/docs/tools/nextjs-starter-kit The directory layout of the Next.js Starter Kit project. ```text app components data icons layouts lib └─ actions └─ database └─ hooks └─ utils primitives styles types utils auth.ts auth.config.ts constants.ts liveblocks.config.ts liveblocks.server.config.ts package.json ``` -------------------------------- ### Upgrade Liveblocks packages to 1.5 Source: https://liveblocks.io/docs/api-reference/upgrading/1.5 Install the latest versions of the Liveblocks packages you use, for example in a React app. Update every Liveblocks package you're using. ```bash npm install @liveblocks/client@latest @liveblocks/node@latest @liveblocks/react@latest ``` -------------------------------- ### Set up RoomProvider with initialStorage Source: https://liveblocks.io/docs/get-started/nextjs Configures the Liveblocks provider and room with an initial storage object containing an input LiveObject. This is the first step in the quickstart, setting up the collaborative environment. ```tsx export function Room({ children }: { children: ReactNode }) { return ( Loading…}> {children} ); } ``` -------------------------------- ### Track cursors with useOthers and useUpdateMyPresence Source: https://liveblocks.io/docs/use-cases/canvas Use useOthers and useUpdateMyPresence from @liveblocks/react/suspense to get and set user cursor positions on the canvas. The example uses screen coordinates and renders a Cursor component for each other user. ```tsx import { useOthers, useUpdateMyPresence } from "@liveblocks/react/suspense"; import { Cursor } from "@liveblocks/react-ui"; function CanvasPresence() { // +++ const others = useOthers(); const updateMyPresence = useUpdateMyPresence(); // +++ return (
updateMyPresence({ cursor: { x: e.clientX, y: e.clientY } }) // +++ } onPointerLeave={ // +++ () => updateMyPresence({ cursor: null }) // +++ } > // +++ {others.map(({ connectionId, info, presence }) => ( // +++ ))}
); } ``` -------------------------------- ### Install @liveblocks/node, AI SDK, and Anthropic provider Source: https://liveblocks.io/docs/get-started/nextjs-comments-ai Run this command to install the packages needed for webhook verification, AI response generation, and Anthropic provider support. ```bash npm install @liveblocks/node ai @ai-sdk/anthropic ``` -------------------------------- ### Get ProseMirror document state with withProsemirrorDocument and api.getText Source: https://liveblocks.io/docs/guides/getting-prosemirror-state-on-the-server Use withProsemirrorDocument and api.getText to retrieve the text content of a ProseMirror document on the server. The example logs the text content, which is "My content". ```TypeScript import { Liveblocks } from "@liveblocks/node"; import { withProsemirrorDocument } from "@liveblocks/node-prosemirror"; const liveblocks = new Liveblocks({ secret: "{{SECRET_KEY}}", }); // +++ const textContent = await withProsemirrorDocument( { roomId: "your-room-id", client: liveblocks, field: "prosemirror" }, async (api) => { return api.getText(); } ); // +++ // "My content" console.log(textContent); ``` -------------------------------- ### Install Liveblocks and Tiptap packages Source: https://liveblocks.io/docs/get-started/nextjs-tiptap-storage Install all required Liveblocks and Tiptap packages. Every Liveblocks package should use the same version. ```bash npm install @liveblocks/client @liveblocks/react @liveblocks/react-ui @liveblocks/react-tiptap @tiptap/react @tiptap/starter-kit ``` -------------------------------- ### Set up Liveblocks client with LiveblocksProvider and RoomProvider Source: https://liveblocks.io/docs/get-started/react-tiptap-storage Set up a Liveblocks client with LiveblocksProvider and join a room with RoomProvider. In Storage mode, documents are created under root._tiptap_docs when the editor first connects, so initialStorage can be left empty. ```tsx "use client"; import { LiveblocksProvider, RoomProvider, } from "@liveblocks/react/suspense"; import { Editor } from "./Editor"; export default function App() { return ( {/* ... */} ); } ``` -------------------------------- ### Display unread count and mark all as read or delete all with hooks Source: https://liveblocks.io/docs/use-cases/inbox Use useUnreadInboxNotificationsCount to get the unread count, and useMarkAllInboxNotificationsAsRead and useDeleteAllInboxNotifications to perform bulk actions. The example shows a header with the count and buttons to trigger these actions. ```tsx import { useMarkAllInboxNotificationsAsRead, useUnreadInboxNotificationsCount, useDeleteAllInboxNotifications, } from "@liveblocks/react/suspense"; function InboxHeader() { // +++ const { count } = useUnreadInboxNotificationsCount(); const markAllAsRead = useMarkAllInboxNotificationsAsRead(); const deleteAll = useDeleteAllInboxNotifications(); // +++ return (
// +++ {count} unread // +++
); } ``` -------------------------------- ### Install Slate, Yjs, and Liveblocks packages Source: https://liveblocks.io/docs/guides/how-to-create-a-collaborative-text-editor-with-slate-yjs-nextjs-and-liveblocks Run this npm command to install all required packages for the collaborative editor: @liveblocks/client, @liveblocks/react, @liveblocks/yjs, @liveblocks/node, yjs, slate, slate-react, @slate-yjs/core, and @slate-yjs/react. ```bash npm install @liveblocks/client @liveblocks/react @liveblocks/yjs @liveblocks/node yjs slate slate-react @slate-yjs/core @slate-yjs/react ``` -------------------------------- ### GET /rooms/{roomId}/ydoc-binary Source: https://liveblocks.io/docs/api-reference/rest-api-endpoints This endpoint retrieves the room's Yjs document as a binary update. It can be used to obtain a copy of the document in your back end, and supports subdocuments via the `guid` query parameter. ```APIDOC ## [GET] /rooms/{roomId}/ydoc-binary ### Description This endpoint returns the room's Yjs document encoded as a single binary update. This can be used by `Y.applyUpdate(responseBody)` to get a copy of the document in your back end. To return a subdocument instead of the main document, pass its `guid`. Corresponds to [`liveblocks.getYjsDocumentAsBinaryUpdate`](https://liveblocks.io/docs/api-reference/liveblocks-node#get-rooms-roomId-ydoc-binary). ### Method GET ### Endpoint /rooms/{roomId}/ydoc-binary ### Parameters #### Path Parameters - **roomId** (string) - Required - ID of the room #### Query Parameters - **guid** (string) - Optional - ID of the subdocument ### Request Example (No request body) ### Response #### Success Response (200) - **binary update** (binary) - The room's Yjs document encoded as a binary Yjs update. #### Response Example (Response body is binary data) ``` -------------------------------- ### useUndo and useRedo hooks in React Source: https://liveblocks.io/docs/guides/how-to-use-liveblocks-multiplayer-undo-redo-with-react Use the useUndo and useRedo hooks from @liveblocks/react/suspense to get undo and redo functions. The example renders two buttons that call undo() and redo() to revert or reapply the last storage change. ```tsx import { useUndo, useRedo } from "@liveblocks/react/suspense"; function App() { const undo = useUndo(); const redo = useRedo(); return ( <> ); } ``` -------------------------------- ### Install Liveblocks and BlockNote packages Source: https://liveblocks.io/docs/get-started/nextjs-blocknote-storage Install all required Liveblocks and BlockNote packages. Every Liveblocks package should use the same version. ```bash npm install @liveblocks/client @liveblocks/react @liveblocks/react-ui @liveblocks/react-blocknote @blocknote/core @blocknote/react @blocknote/mantine ```