Liveblocks Integration for Real-time Collaboration in Mobile Applications
Liveblocks — managed infrastructure for collaborative editing: WebSocket server, CRDT storage, presence, comments, notifications — all behind cloud API. In browser integration takes day. In React Native — more interesting because official React hooks (@liveblocks/react) work, but several nuances surface only in production.
What Liveblocks Provides Out of Box
Three key primitives:
Storage — CRDT storage based on proprietary implementation (not Y.js). LiveObject, LiveList, LiveMap — typed structures with automatic merge. Changes replicated between all clients in room (<100 ms within one region).
Presence — ephemeral user state: cursor position, selection, status. Doesn't persist, stored only while user online. Perfect for displaying avatars and real-time activity.
Yjs-integration — from v1.x Liveblocks supports Y.js via @liveblocks/yjs, allowing Tiptap/Slate on web and same document in mobile app.
Connecting in React Native
import { createClient } from '@liveblocks/client';
import { createRoomContext } from '@liveblocks/react';
const client = createClient({
authEndpoint: '/api/liveblocks-auth', // JWT via your backend
// or publicApiKey for prototypes
});
type Presence = {
cursor: { x: number; y: number } | null;
selectedItemId: string | null;
};
type Storage = {
items: LiveList<{ id: string; text: string; done: boolean }>;
};
export const { RoomProvider, useMyPresence, useStorage, useMutation } =
createRoomContext<Presence, Storage>(client);
RoomProvider wraps editor screen. Inside it useStorage gives immutable CRDT storage snapshot, useMutation — transactional mutations.
Problem in RN: @liveblocks/client under hood uses fetch and WebSocket — both exist in React Native. But EventSource (SSE, needed for Liveblocks Notifications) absent in RN without polyfill. Package react-native-event-source or eventsource + global polyfill solve this:
// index.js, before everything
import EventSource from 'react-native-event-source';
global.EventSource = EventSource;
Presence in Mobile Context
In browser presence usually — mouse coordinates. In mobile app meaningless. Typical cases:
-
Collaborative todo list: presence =
{ focusedItemId: string | null }— highlight item other user editing. -
Collaborative board: presence =
{ x, y, tool: 'pen' | 'eraser' }— show other participant's stylus. -
Document editor: presence =
{ selection: { anchor, focus } | null }— text selection.
useOthersConnectionIds + useOther give reactive present data. For optimization: useOthersMapped select only needed presence field and not rerender on unrelated changes.
Offline Mode: What Liveblocks Lacks Out of Box
Liveblocks doesn't provide offline persistence on client. Without network, changes lost. For mobile application critical.
Workaround — buffer mutations in AsyncStorage:
const [pendingMutations, setPendingMutations] = useAtom(pendingMutationsAtom);
// On network loss
NetInfo.addEventListener(state => {
if (!state.isConnected) {
// save current state locally
const snapshot = storage.toObject();
AsyncStorage.setItem('offline_snapshot', JSON.stringify(snapshot));
} else {
// on restore — replay pending
pendingMutations.forEach(mutation => mutation());
setPendingMutations([]);
}
});
Not true CRDT offline — merge not guaranteed on simultaneous offline changes on multiple devices. For full offline on Liveblocks need combining with Y.js via @liveblocks/yjs and custom local provider. Solution more complex but correct.
AppState and Reconnect
iOS kills WebSocket on background transition. Liveblocks SDK handles reconnect automatically, but room.getStatus() after restore goes through reconnecting → connected cycle. If UI doesn't react to room status — user sees stale state.
const status = useStatus(); // 'initial' | 'connecting' | 'connected' | 'reconnecting'
if (status === 'reconnecting') {
return <ReconnectingBanner />;
}
Handle reconnecting explicitly — especially if app shows shared list that changed while offline.
Pricing and Limits
Liveblocks — paid service with free tier (50 MAU, 1000 rooms). For production: Starter from $99/mo, Pro from $299/mo. This is managed infrastructure — you don't run WebSocket servers but depend on their SLA (99.9% on Pro).
If requirements include self-hosted or data residency in specific jurisdiction — Liveblocks not suitable. Then consider Y.js + Hocuspocus or PartyKit on own infrastructure.
Assessment
Integrating Liveblocks in React Native (Storage + Presence, without offline): 2–4 weeks. With offline buffer and Y.js integration: 5–8 weeks. Flutter — via @liveblocks/client in webview or custom Dart client with WebSocket: 4–7 weeks.







