Tech 10 min read

Low-Latency Real-Time Synchronization on the Web: Technology Comparison and Implementation Guide

IkesanContents

I was building a real-time game in another project and needed to synchronize player movements in real time. In a previous article on design patterns for large-scale simultaneous viewing events, I covered “pseudo-synchronization” (server-time-based, primarily one-directional).

But this time was different. I needed to share the “right now” state directly between clients or through a server, with full bidirectional interaction.

This is about “small-scale but low-latency, bidirectional real-time synchronization.”

Pseudo-Sync vs True Sync

Large-scale event design and low-latency synchronization are fundamentally different.

AspectLarge-Scale Event (Pseudo-Sync)Bidirectional Real-Time (True Sync)
ScaleTens of thousandsA few to thousands
Sync directionOne-way (server → everyone)Bidirectional
Sync precisionSeconds are fineMilliseconds required
Server time rolePrimary (absolute reference)Supplementary
Network loadLow-frequency pollingConstant communication
Use casesBroadcasting, simultaneous viewingGames, collaboration, chat

Pseudo-sync is an optimization to minimize server load. True sync, on the other hand, exists to synchronize state between clients — the challenge is how much latency you can eliminate.

Technology Comparison Table

Here are seven representative communication technologies side by side.

TechnologyAvg LatencyImpl DifficultyScalabilityBrowser SupportBidirectionalP2P
WebSocket10-50ms★★☆Medium (scale-out is complex)★★★★★
WebRTC Data Channel5-30ms★★★★High (P2P capable)★★★★☆
SSE + HTTP/250-200ms★☆☆Medium★★★★★✗ (one-way)
HTTP/3 + QUIC5-50ms★★★Medium★★★☆☆
WebTransport5-30ms★★★★Medium★★☆☆☆ (experimental)
Agora (managed)5-100ms★☆☆Very high
LiveKit (OSS)5-100ms★★☆Very high (self-hosted)

Note: Latencies are typical values and depend heavily on network conditions. Implementation difficulty factors in library ecosystem maturity and learning curve.

WebSocket

A bidirectional communication protocol over TCP. The most standard option with the most implementation examples.

Characteristics

  • Persistent connection after handshake
  • Supports both text and binary
  • Near-100% browser support

Advantages

  • Simple implementation (rich library ecosystem)
  • Stable latency
  • Abundant debugging and monitoring tools

Disadvantages

  • State synchronization between servers is complex when scaling out
  • “Session affinity” is required for multi-server deployments
  • Load balancer configuration is cumbersome

Implementation Example

Server (Node.js + ws):

import WebSocket from 'ws';

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    console.log('Received:', message);

    // Broadcast to all clients
    wss.clients.forEach(client => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

Client (JavaScript):

const ws = new WebSocket('ws://localhost:8080');

ws.onopen = () => {
  console.log('Connected');
  ws.send(JSON.stringify({ type: 'position', x: 100, y: 200 }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
  // Update other players' positions on screen, etc.
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

Use Cases

Chat, collaborative boards, early-stage games, real-time notifications.


WebRTC Data Channel

Enables P2P communication. The key feature is direct data exchange with peers.

Characteristics

  • Data communication over UDP/SCTP
  • P2P connection (separate signaling server required)
  • Multi-client support (mesh or star topology)

Advantages

  • Minimal latency in P2P mode since traffic bypasses the server
  • NAT traversal built in (STUN/TURN)
  • Server load does not increase as clients scale

Disadvantages

  • High learning curve for implementation
  • Signaling server design is complex
  • Mesh management for multi-party communication is cumbersome

Implementation Example

Signaling server (Node.js + Socket.IO):

import express from 'express';
import { Server } from 'socket.io';

const app = express();
const io = new Server(8080);

io.on('connection', (socket) => {
  socket.on('offer', (data) => {
    // Relay offer from A to B
    socket.broadcast.emit('offer', {
      from: socket.id,
      offer: data.offer
    });
  });

  socket.on('answer', (data) => {
    // Send answer from B to A
    io.to(data.to).emit('answer', {
      from: socket.id,
      answer: data.answer
    });
  });

  socket.on('ice-candidate', (data) => {
    // Relay ICE candidate to the peer
    io.to(data.to).emit('ice-candidate', {
      from: socket.id,
      candidate: data.candidate
    });
  });
});

Client (simplified):

const socket = io('http://localhost:8080');
let peerConnection;

socket.on('offer', async (data) => {
  peerConnection = new RTCPeerConnection();

  // Receive the data channel
  peerConnection.ondatachannel = (event) => {
    const dc = event.channel;
    dc.onmessage = (e) => {
      console.log('Received:', e.data);
    };
  };

  await peerConnection.setRemoteDescription(
    new RTCSessionDescription(data.offer)
  );
  const answer = await peerConnection.createAnswer();
  await peerConnection.setLocalDescription(answer);

  socket.emit('answer', { to: data.from, answer });
});

// Initiate a connection
async function initiateConnection() {
  peerConnection = new RTCPeerConnection();
  const dc = peerConnection.createDataChannel('game-sync');

  dc.onopen = () => {
    dc.send(JSON.stringify({ type: 'init', playerId: 'me' }));
  };

  const offer = await peerConnection.createOffer();
  await peerConnection.setLocalDescription(offer);
  socket.emit('offer', { offer });
}

Use Cases

1v1 match games, P2P file sharing, low-latency data exchange among multiple participants.


SSE + HTTP/2

A one-way stream from server to client. The simplest option when bidirectional communication is not needed.

Characteristics

  • Server → client, one-way only
  • HTTP/2 bypasses connection count limits
  • Text stream format

Advantages

  • Extremely simple implementation (just use EventSource)
  • Excellent firewall/proxy compatibility
  • Strong browser support

Disadvantages

  • One-way only (client → server requires regular HTTP requests)
  • Complexity increases if polling in both directions

Implementation Example

Server (Node.js + Express):

import express from 'express';

const app = express();
const clients = new Set();

app.get('/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  clients.add(res);

  res.on('close', () => {
    clients.delete(res);
  });
});

// Broadcast function
function broadcast(data) {
  clients.forEach(res => {
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  });
}

app.post('/action', (req, res) => {
  const action = req.body;
  broadcast(action);
  res.sendStatus(200);
});

app.listen(8080);

Client (JavaScript):

const eventSource = new EventSource('/stream');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Broadcast:', data);
  // Update the UI, etc.
};

eventSource.onerror = () => {
  console.error('Connection lost');
};

// Send an action from the client (regular HTTP)
async function sendAction(action) {
  await fetch('/action', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(action)
  });
}

Use Cases

Stock/crypto tickers, live scoreboards, notification systems, leaderboards.


HTTP/3 + QUIC

The QUIC protocol over UDP. Gaining attention as the next-generation HTTP.

Characteristics

  • UDP-based (not TCP)
  • Avoids Head-of-Line (HoL) blocking
  • Multiple parallel streams
  • 0-RTT connection resumption

Browser Support

Chrome/Edge: ✓ Safari: ✓ (recently added) Firefox: Experimental Overall adoption: ~26% (as of 2024)

Advantages

  • Lower latency than TCP
  • Resilient to network switches (WiFi → LTE)

Disadvantages

  • Server implementation standardization is still in progress
  • May be blocked by firewalls/proxies
  • Debugging is complex

Notes

Using an HTTP/3-capable CDN or edge server gives you the benefits automatically. Cloudflare already offers it as standard. That said, if WebSocket is sufficient for your use case, there is no need to force a switch to HTTP/3.


WebTransport (Emerging Technology)

Not recommended for production use at this time. Still experimental.

A next-generation standard built on QUIC and HTTP/3 that lets you flexibly choose between streams (reliability-focused) and datagrams (speed-focused).

Characteristics

  • Streams: Reliable (potential successor to WebSocket)
  • Datagrams: Unreliable, ultra-low latency (ideal for games)
  • Browser-native API

Browser Support

Chrome 86+ only. Safari has plans to implement. Firefox TBD.

Advantages

  • State-of-the-art latency performance
  • Use-case-specific options

Disadvantages

  • Limited browser support
  • Few implementation examples and reference materials
  • Specification is still in flux

Reference Implementation

// Chrome experimental
async function connectWebTransport() {
  try {
    const transport = await WebTransport.connect(
      'https://example.com:4433/game'
    );

    // Stream-based (reliability-focused)
    const writer = transport.datagrams.writable.getWriter();
    writer.write(new Uint8Array([1, 2, 3]));

    // Datagram-based (speed-focused)
    transport.incomingUnidirectionalStreams.getReader().read()
      .then(({ value }) => {
        const reader = value.getReader();
        reader.read().then(({ value, done }) => {
          console.log('Received:', new TextDecoder().decode(value));
        });
      });
  } catch (e) {
    console.error('WebTransport error:', e);
  }
}

Managed Platforms (Agora Example)

Fully delegate infrastructure management to an external provider. No scaling worries.

Characteristics

  • SaaS model, no infrastructure management
  • Global edge server network
  • Standardized APIs

Advantages

  • Zero operational and scaling overhead
  • Minimized latency for global delivery
  • Comprehensive support

Disadvantages

  • Vendor lock-in
  • Customization limitations
  • Monthly costs

Code Example

import AgoraRTC from "agora-rtc-sdk-ng";

const agoraEngine = AgoraRTC.createClient({
  mode: "rtc",
  codec: "vp8"
});

agoraEngine.on("user-published", async (user, mediaType) => {
  await agoraEngine.subscribe(user, mediaType);
});

agoraEngine.on("user-unpublished", async (user) => {
  await agoraEngine.unsubscribe(user);
});

// Join
await agoraEngine.join(appId, channelName, token, uid);

Open-Source Platforms (LiveKit Example)

Full control with self-hosting. Maximum customization freedom.

Characteristics

  • Published on GitHub
  • Kubernetes-ready
  • Deployable on your own infrastructure

Advantages

  • High customization freedom
  • No lock-in
  • Cost savings possible at scale

Disadvantages

  • Infrastructure setup and operation costs
  • Troubleshooting is on you

Getting Started

import {
  connect,
  Room,
  RoomOptions
} from 'livekit-client';

const url = 'ws://your-livekit-server:7880';
const token = await generateToken(userName, roomName);

const room = new Room();
await room.connect(url, token);

room.on('participantConnected', (participant) => {
  console.log('Joined:', participant.name);
});

Use Case Guide

Real-Time Games

Requirements: Latency under 50ms, multiple players (2–100), bidirectional

Recommended:

  1. WebSocket (standard choice)
  2. WebRTC Data Channel (for P2P)

Implementation tips:

  • Player position data relayed through the server (to broadcast to everyone)
  • Send inputs immediately (use client-side prediction as well)
  • Separate frame-rate sync (60fps) from server tick sync

Multiplayer Whiteboard

Requirements: Latency under 100ms, multiple users (2–20), moderate sync precision

Recommended:

  1. WebSocket
  2. SSE (for one-way parts like background changes)

Implementation tips:

  • Batch drawing strokes before sending (per-frame sending is heavy)
  • CRDT (Conflict-free Replicated Data Type) for conflict resolution (adds complexity, so evaluate carefully)

Live Collaboration (Figma-style)

Requirements: Latency under 50ms, many simultaneous connections (10–100), Operational Transformation required

Recommended:

  1. WebSocket (OT-capable server)
  2. Managed (Yjs or PartyKit integration)

Implementation tips:

  • Normalize each user’s operations on the server (Operational Transformation)
  • Use optimistic updates on the client to mask latency

Chat / Messaging

Requirements: ~500ms latency acceptable, many users, no need to retain history after delivery

Recommended:

  1. WebSocket (real-time)
  2. HTTP polling (fallback)

Implementation tips:

  • Store message history in a database; fetch only on connection
  • On disconnect, retrieve new messages upon reconnection

Stock / Crypto Tickers

Requirements: 100–500ms latency, broadcast (one-way), many client connections

Recommended:

  1. SSE + HTTP/2 (simple, scales well)
  2. WebSocket (when customization is needed)

Implementation tips:

  • Push via SSE whenever there is an update
  • Cache the latest values in local storage on the client

Real-Time Audio / Video

Requirements: 10–100ms latency (codec-dependent), multiple simultaneous connections, high throughput

Recommended:

  1. WebRTC (standard, P2P capable)
  2. Managed (Agora, Twilio)

Implementation tips:

  • Choose audio codec (Opus) and video codec (VP8/H.264)
  • Adjust quality based on network load (reduce resolution/frame rate)

YouTube Live-Style Comment System

Requirements: A few seconds of latency is fine, streamer and viewers need time synchronization

Recommended:

  1. WebSocket + time sync (leveraging the pseudo-sync approach)
  2. SSE (for one-way delivery)

Implementation tips:

  • Combine the timesheet approach from the pseudo-sync article to synchronize comment delivery with video playback
  • Correct clock drift between clients using server time

Technology Selection Flow

START

[Q1] Do you need latency under 50ms?
  ├─ YES → Go to Q2
  └─ NO → Go to Q3

[Q2] Is direct client-to-client communication (P2P) required?
  ├─ YES → Consider WebRTC Data Channel
  └─ NO → Consider WebSocket or HTTP/3

[Q3] Do you want to minimize server management overhead?
  ├─ YES → Consider managed platforms like Agora
  └─ NO (self-hosting is fine) → Go to Q4

[Q4] Is broadcast (one-way) sufficient?
  ├─ YES → Consider SSE + HTTP/2
  └─ NO (bidirectional required) → WebSocket

Adoption Examples and Reference Resources

WebSocket: Discord, Slack (core implementation), Socket.IO (npm weekly downloads 1.5M+)

WebRTC: Google Meet, Zoom (video/audio), various competitive games

SSE: Twitter X (real-time feed portion)

Agora: Webinar platforms, live commerce

LiveKit: Video chat platforms, enterprise applications


Pseudo-sync (large-scale, one-way) and true sync (small-scale, bidirectional) are fundamentally different in design philosophy.

Selection criteria:

  1. Latency under 50ms → WebSocket or WebRTC Data Channel
  2. P2P required → WebRTC Data Channel
  3. Broadcast only → SSE + HTTP/2
  4. Minimize operational cost → Managed platforms like Agora
  5. Customization priority → WebSocket or LiveKit

Mixed-use patterns are common too. For example, a YouTube Live-style system might combine “SSE for video delivery,” “WebSocket for comments,” and “server time sync for timed effects” — using multiple technologies together is the realistic approach.

The previous pseudo-sync article covered scaling methods for large-scale events. This one covers implementation patterns for “small-scale but low-latency” scenarios. Pick the right approach based on your requirements.