Skip to main content

Overview

Liveblocks powers the real-time collaboration features including live cursors, presence indicators, and collaborative editing. It integrates seamlessly with Lexical editor and Clerk authentication.

Installation

The project uses multiple Liveblocks packages:
package.json
"@liveblocks/client": "^2.3.0",
"@liveblocks/node": "^2.3.0",
"@liveblocks/react": "^2.3.0",
"@liveblocks/react-lexical": "^2.3.0",
"@liveblocks/react-ui": "^2.3.0"
Install all packages:
npm install @liveblocks/client @liveblocks/node @liveblocks/react @liveblocks/react-lexical @liveblocks/react-ui

Environment Variables

Add your Liveblocks secret key to .env.local:
LIVEBLOCKS_SECRET_KEY=your_secret_key
Get your secret key from the Liveblocks Dashboard.

Configuration

Server Setup

Initialize the Liveblocks client in lib/liveblocks.ts:
lib/liveblocks.ts
import { Liveblocks } from "@liveblocks/node";

export const liveblocks = new Liveblocks({
  secret: process.env.LIVEBLOCKS_SECRET_KEY as string,
});

Type Definitions

Define your collaboration data types in liveblocks.config.ts:
liveblocks.config.ts
declare global {
  interface Liveblocks {
    // Custom user metadata
    UserMeta: {
      id: string;
      info: {
        id: string;
        name: string;
        email: string;
        avatar: string;
        color: string;
      };
    };

    // Room presence data
    Presence: {};

    // Conflict-free storage
    Storage: {};

    // Custom events
    RoomEvent: {};

    // Thread metadata for comments
    ThreadMetadata: {};

    // Room information
    RoomInfo: {};
  }
}

Authentication Endpoint

The authentication endpoint bridges Clerk and Liveblocks:
1

Get Clerk User

Retrieve the authenticated user from Clerk:
app/api/liveblocks-auth/route.ts
import { currentUser } from "@clerk/nextjs/server";
import { liveblocks } from "@/lib/liveblocks";
import { getUserColor } from "@/lib/utils";

export async function POST(request: Request) {
  const clerkUser = await currentUser();

  if (!clerkUser) {
    return new Response('Unauthorized', { status: 401 });
  }
}
2

Extract User Data

Map Clerk user data to Liveblocks format:
app/api/liveblocks-auth/route.ts
const { id, firstName, lastName, emailAddresses, imageUrl } = clerkUser;
const email = emailAddresses[0]?.emailAddress;

const user = {
  id,
  info: {
    id,
    name: `${firstName} ${lastName}`,
    email,
    avatar: imageUrl,
    color: getUserColor(id),
  }
}
3

Identify User

Authenticate the user with Liveblocks:
app/api/liveblocks-auth/route.ts
const { status, body } = await liveblocks.identifyUser(
  {
    userId: user.info.email,
    groupIds: [],
  },
  { userInfo: user.info },
);

return new Response(body, { status });

Integration with Lexical Editor

Liveblocks is integrated into the Lexical editor via plugins:
components/editor/Editor.tsx
import { 
  FloatingComposer, 
  FloatingThreads, 
  liveblocksConfig, 
  LiveblocksPlugin 
} from '@liveblocks/react-lexical'
import { useThreads } from '@liveblocks/react/suspense';

export function Editor({ roomId, currentUserType }: { roomId: string, currentUserType: UserType }) {
  const { threads } = useThreads();

  const initialConfig = liveblocksConfig({
    namespace: 'Editor',
    nodes: [HeadingNode],
    onError: (error: Error) => {
      console.error(error);
      throw error;
    },
    theme: Theme,
    editable: currentUserType === 'editor',
  });

  return (
    <LexicalComposer initialConfig={initialConfig}>
      <LiveblocksPlugin>
        <FloatingComposer className="w-[350px]" />
        <FloatingThreads threads={threads} />
        <Comments />
      </LiveblocksPlugin>
    </LexicalComposer>
  );
}

Key Features

The LiveblocksPlugin must be placed inside LexicalComposer to enable real-time collaboration.

Real-Time Components

  • FloatingComposer: Comment composer that appears when text is selected
  • FloatingThreads: Displays comment threads attached to document ranges
  • Comments: Custom component for managing comment interactions

Room Configuration

  • Room ID: Unique identifier for each collaborative document session
  • User Type: Controls editor permissions (editor vs. viewer)
  • Namespace: Isolates editor state ('Editor')

User Presence

Liveblocks automatically tracks:
  • Active users in the room
  • User cursor positions
  • User selection ranges
  • User metadata (name, avatar, color)

Build docs developers (and LLMs) love