Sign in

How to use Liveblocks Presence with Zustand

In this guide, we’ll be learning how to use Liveblocks Presence with Zustand using the APIs from the @liveblocks/zustand package.

Install Liveblocks

This guide assumes you already have Liveblocks set up into your Zustand store. If you don’t make sure to follow these quick steps to get started first.

Get other users in the room

Need help troubleshooting presence?

Try the Liveblocks DevTools extension to inspect and debug your collaborative experiences as you build them, in realtime.

If you want to list all the people connected to the room, you can use liveblocks.others to get an array of the other users in the room.

import useStore from "./store";
function YourComponent() { useStore((state) => state.liveblocks.others);}

Update user presence

To create immersive multiplayer experiences, it’s helpful for each person in the room to share their real‑time state with other connected users. That real‑time state often corresponds to a cursor position or even the item a user has currently selected. We call this concept “Presence”.

For instance, to share the cursor’s position in real‑time with others, we’re going to add a new presenceMapping option to our liveblocks middleware configuration to specify which part of the state maps to the current user’s presence. In this case, we’re updating the cursor position in our store in the onPointerMove event listener in our React component.

src/store.ts
import create from "zustand";import { createClient } from "@liveblocks/client";import { liveblocks } from "@liveblocks/zustand";import type { WithLiveblocks } from "@liveblocks/zustand";
type Cursor = { x: number; y: number };
type State = { cursor: Cursor; setCursor: (cursor: Cursor) => void;};
const client = createClient({ publicApiKey: "",});
const useStore = create<WithLiveblocks<State>>()( liveblocks( (set) => ({ cursor: { x: 0, y: 0 }, setCursor: (cursor) => set({ cursor }), }), { client, presenceMapping: { cursor: true, }, } ));
export default useStore;
src/App.tsx
import React, { useEffect } from "react";import useStore from "./store";
import "./App.css";
const App = () => { const { liveblocks: { enterRoom, leaveRoom }, } = useStore();
useEffect(() => { enterRoom("room-id"); return () => { leaveRoom("room-id"); }; }, [enterRoom, leaveRoom]);
const setCursor = useStore((state) => state.setCursor); return ( <div style={{ width: "100vw", height: "100vh" }} onPointerMove={(e) => setCursor({ x: e.clientX, y: e.clientY })} /> );};
export default App;

Get other users’ presence

Get people’s cursor positions with liveblocks.others.map(user => user.presence.cursor).

src/App.tsx
function App() {  /* ... */
const others = useStore((state) => state.liveblocks.others); const othersCursors = others.map((user) => user.presence.cursor);
// Render cursors with custom SVGs based on x and y}