DEV Community

Alex Spinov
Alex Spinov

Posted on

Liveblocks Has a Free API That Adds Figma-Style Collaboration to Any App

Liveblocks gives you real-time collaboration primitives: live cursors, presence, conflict-free storage, and comments. Build multiplayer experiences like Figma, Notion, and Linear.

What Is Liveblocks?

Liveblocks provides the infrastructure for collaborative features. Instead of building WebSocket servers and conflict resolution from scratch, use Liveblocks APIs.

Quick Start

npm install @liveblocks/client @liveblocks/react
Enter fullscreen mode Exit fullscreen mode

Setup

// liveblocks.config.ts
import { createClient } from '@liveblocks/client'
import { createRoomContext } from '@liveblocks/react'

const client = createClient({ publicApiKey: process.env.NEXT_PUBLIC_LIVEBLOCKS_KEY! })

export const { RoomProvider, useMyPresence, useOthers, useStorage, useMutation } = createRoomContext(client)
Enter fullscreen mode Exit fullscreen mode

Live Cursors

function Cursors() {
  const others = useOthers()
  const [myPresence, updateMyPresence] = useMyPresence()

  return (
    <div onPointerMove={(e) => updateMyPresence({ cursor: { x: e.clientX, y: e.clientY } })}>
      {others.map(({ connectionId, presence }) => (
        presence.cursor && (
          <div key={connectionId} style={{ position: 'fixed', left: presence.cursor.x, top: presence.cursor.y }}>
            <svg width="24" height="24"><path d="M0 0l8 20 4-8 8-4z" fill="#e57373" /></svg>
          </div>
        )
      ))}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Conflict-Free Storage

function TodoList() {
  const todos = useStorage((root) => root.todos)

  const addTodo = useMutation(({ storage }, text: string) => {
    const todos = storage.get('todos')
    todos.push({ text, done: false, id: crypto.randomUUID() })
  }, [])

  const toggleTodo = useMutation(({ storage }, id: string) => {
    const todos = storage.get('todos')
    const todo = todos.find((t) => t.get('id') === id)
    todo?.set('done', !todo.get('done'))
  }, [])

  return (
    <div>
      <button onClick={() => addTodo('New task')}>Add</button>
      {todos?.map((todo) => (
        <div key={todo.id} onClick={() => toggleTodo(todo.id)}>
          {todo.done ? '' : ''} {todo.text}
        </div>
      ))}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Comments

import { Thread, Composer } from '@liveblocks/react-comments'
import '@liveblocks/react-comments/styles.css'

function CommentsPanel() {
  const { threads } = useThreads()
  return (
    <div>
      {threads.map((thread) => <Thread key={thread.id} thread={thread} />)}
      <Composer />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

REST API

export LB_KEY="your-secret-key"

# Get room storage
curl -s 'https://api.liveblocks.io/v2/rooms/my-room/storage' \
  -H "Authorization: Bearer $LB_KEY"

# Get active users
curl -s 'https://api.liveblocks.io/v2/rooms/my-room/active_users' \
  -H "Authorization: Bearer $LB_KEY" | jq 'length'

# Initialize storage
curl -s -X POST 'https://api.liveblocks.io/v2/rooms/my-room/storage' \
  -H "Authorization: Bearer $LB_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"liveblocksType": "LiveObject", "data": {"todos": {"liveblocksType": "LiveList", "data": []}}}'
Enter fullscreen mode Exit fullscreen mode

Free Tier

Feature Free Starter ($25/mo)
MAU 250 10,000
Connections 20 concurrent 200
Storage 50 rooms 500 rooms
Comments Yes Yes
Presence Yes Yes

Building collaborative data tools? Scrapfly provides shared web data. Email spinov001@gmail.com for collaborative scraping solutions.

Top comments (0)