Learn WebSocket - Real-Time Collaboration Features
Episode 20 of 34

Learn WebSocket - Real-Time Collaboration Features

This episode covers real-time collaboration features: Operational Transformation, CRDT, cursor position distribution, version history, and libraries such as Yjs, ShareDB, and Automerge.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Two people type in the same document at the same time. If the server just applies "latest document wins", one person loses all their writing. Applications like Google Docs solve this with smart conflict algorithms.

Episode 20 covers real-time collaboration: how two clients edit one document without deleting each other. You will learn the two big approaches — Operational Transformation and CRDT — plus the libraries that already solve this problem so you do not have to write it from scratch.

The Concurrency Problem

Conflicting Edits

Imagine a document containing "halo". Client A appends " dunia" at the end, client B appends " sayang" at the end — both based on the text "halo".

Two edits based on the old version
Versi bersama : "halo"
Edit A        : "halo dunia"
Edit B        : "halo sayang"

If the server applies A then B, and B was computed against positions in "halo", the result is a mess. This is called a conflict: two operations valid on their own, but incompatible if simply applied.

The Required Solution

The server needs a way to merge operations from many clients so the final result is consistent for everyone. That is where Operational Transformation and CRDT come in.

Operational Transformation

The OT Concept

Operational Transformation shifts the position of an operation so it fits with other operations that arrived earlier.

JSRepresenting an insert operation
const operasi = {
  tipe: "insert",
  posisi: 5,
  teks: " dunia",
  klien: "user-A",
  urutan: 7,
};

Every edit is represented as an operation: insert, delete, or retain at a specific position. When two operations overlap, a transform function adjusts the position of the later operation so both can be applied in any order.

A Simple Implementation

JSTransforming positions on two inserts
function transform(a, b) {
  if (b.tipe === "insert" && b.posisi <= a.posisi) {
    return { ...a, posisi: a.posisi + b.teks.length };
  }
  if (b.tipe === "delete" && b.posisi < a.posisi) {
    return { ...a, posisi: a.posisi - b.jumlah };
  }
  return a;
}

transform(a, b) adjusts operation a's position against b, which was already applied. OT is proven reliable for text editors, but its implementation is complex — that is why most teams use mature libraries.

CRDT

The CRDT Concept

Conflict-free Replicated Data Types take a different approach: every change carries a unique identity, and all replicas reach the same result without a server deciding who wins.

JSA CRDT element with a unique ID
const char = {
  id: { klien: "user-A", counter: 42 },
  teks: "x",
  kiri: null,
  kanan: null,
};

Every character has a unique ID and a position relative to its neighbors. Because positions are relative, two clients can add characters at the same place without overwriting each other — both exist.

CRDT Advantages

  • No authoritative server: clients can edit offline then sync.
  • Automatic convergence: all replicas end with the same result.
  • Great for offline-first: fits applications that often lose connectivity.

Collaborative Editing

Cursors and Selections

Besides the document content, you distribute the cursor position so other users see the cursor move in real time.

JSBroadcasting the cursor position
socket.on("cursor:move", (pos) => {
  socket.to("doc:" + pos.docId).emit("cursor:moved", {
    userId: socket.userId,
    posisi: pos.posisi,
    warna: socket.warna,
  });
});

cursor:move is broadcast only to collaborators of the same document, not to every connection. Cursor positions are ephemeral, so they do not need to be stored — just forwarded and continuously overwritten.

History and Conflict Resolution

Collaborative documents keep a version history. CRDT makes undo easy because every operation has an identity; to roll back, you just emit the operation that cancels it.

Implementation Libraries

Yjs, ShareDB, and Automerge

Writing OT or CRDT from scratch takes months. Mature libraries have already solved this.

Install Yjs and a provider
bun add yjs y-websocket

Yjs is the most popular CRDT with a ready-made WebSocket provider. ShareDB implements OT and fits if you need JSON documents database-style. Automerge focuses on offline-first mode with synchronization.

Yjs Integration

JSA Yjs document over WebSocket
const Y = require("yjs");
const { WebSocketProvider } = require("y-websocket");
 
const doc = new Y.Doc();
const provider = new WebSocketProvider("wss://sync.example.com", "room-1", doc);
 
provider.on("sync", () => {
  console.log("dokumen tersinkronisasi");
});

WebSocketProvider(url, room, doc) connects the Yjs document to a y-websocket server. All edits, cursors, and awareness (who is currently viewing) are managed by the provider automatically.

Closing

Episode 20 opened the world of collaboration: from two conflicting edits overwriting each other, to a system that binds everyone to the same result. OT transforms operations to be compatible, CRDT makes all replicas converge, and ready-made libraries save you from the complexity.

Key takeaways:

  • Two edits based on the old version need a conflict resolution mechanism.
  • OT transforms operation positions so they can be applied together.
  • CRDT gives every change an identity so results converge.
  • Cursor positions and selections are broadcast only to document collaborators.
  • Yjs, ShareDB, and Automerge provide mature implementations.
  • Yjs has a WebSocket provider, so integration is only a few lines.

In the next episode we build a real-time notifications system: notification architecture, user preferences, batching, and persistence of read and unread status.

Learn WebSocket - Real-Time Collaboration Features | Learn WebSocket