โก Different Ways to Implement Real-Time Communication Between Client and Server

Table of contents

The web is no longer just about static pages. Today, users expect instant updates โ whether itโs a chat app, stock price ticker, multiplayer game, or live notifications.
But how do we make this happen? How can the client (browser or mobile app) and server communicate in real time?
In this blog, weโll explore different approaches to real-time communication โ from traditional methods to modern solutions โ with examples and use cases for each.
๐ข 1. The Traditional Approach: HTTP Polling
Polling is the simplest way to get real-time-like behavior. The client repeatedly asks the server for new data at regular intervals.
๐น How It Works:
- The client sends an HTTP request every few seconds.
- The server responds with the latest data.
- The client updates the UI if thereโs new information.
๐น Example (JavaScript):
setInterval(async () => {
const response = await fetch('/messages');
const messages = await response.json();
console.log("Latest messages:", messages);
}, 3000); // every 3 seconds
โ Pros:
- Very easy to implement.
- Works with all browsers and servers.
- No special protocols needed.
โ Cons:
- Wastes resources (server gets requests even if nothing has changed).
- Not truly "real-time" (depends on polling interval).
- High latency for critical applications.
๐น Best Use Case:
- When real-time isnโt critical (e.g., checking for new blog comments).
๐ข 2. Long Polling
Long polling is an improvement over normal polling. Instead of responding immediately, the server holds the request open until new data is available.
๐น How It Works:
- The client sends a request to the server.
- The server waits until it has new data, then responds.
- Once the client receives a response, it sends another request immediately.
๐น Example (Node.js + Express):
// Server-side (Node.js + Express)
app.get('/updates', (req, res) => {
setTimeout(() => {
res.json({ message: "New data available!" });
}, 5000); // simulate delay
});
// Client-side
async function getUpdates() {
const response = await fetch('/updates');
const data = await response.json();
console.log(data);
getUpdates(); // call again to keep listening
}
getUpdates();
โ Pros:
- More efficient than regular polling.
- Works without special protocols.
โ Cons:
- Still uses HTTP for every message.
- Not as efficient as WebSockets or Server-Sent Events.
๐น Best Use Case:
- Notifications and updates where WebSockets are not available.
๐ข 3. Server-Sent Events (SSE)
Most beginners jump straight to WebSockets when thinking about real-time communication, but sometimes you donโt need two-way communication. If your application only requires the server to push updates to the client (one-way), then Server-Sent Events (SSE) is often the simplest and most efficient choice.
๐น How It Works
SSE uses a long-lived HTTP connection (usually GET
) where:
Client opens a connection using the built-in
EventSource
API in JavaScript.- This is just like opening a normal HTTP request, but it stays open.
Server keeps the connection alive and streams messages whenever thereโs new data.
- Instead of closing after one response, the server keeps writing data to the client.
Client receives events in real-time.
- Each event is sent in a special text-based format that starts with
data:
.
- Each event is sent in a special text-based format that starts with
Automatic reconnection.
- If the connection drops (e.g., due to network issues), the browser automatically reconnects after a few seconds.
- You donโt have to write extra reconnection logic (which you need in WebSockets).
๐น Example
Letโs build a real-time clock using SSE.
Client-Side (Browser)
// Open a connection to the server
const eventSource = new EventSource('/time');
// Default message handler
eventSource.onmessage = (event) => {
console.log("Current time:", event.data);
document.body.innerHTML = `<h1>${event.data}</h1>`;
};
// Optional: Listen to custom events
eventSource.addEventListener("news", (event) => {
console.log("Breaking news:", event.data);
});
// Handle errors (auto-reconnect will still happen)
eventSource.onerror = () => {
console.log("Connection lost, trying to reconnect...");
};
Server-Side (Node.js + Express)
const express = require('express');
const app = express();
app.get('/time', (req, res) => {
// Tell the browser this is an event stream
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// Send a message every second
setInterval(() => {
const now = new Date().toLocaleTimeString();
res.write(`data: ${now}\n\n`);
}, 1000);
// Optional: Send a custom event
setTimeout(() => {
res.write("event: news\n");
res.write("data: Server-Sent Events are awesome!\n\n");
}, 5000);
});
app.listen(3000, () => console.log("SSE server running on http://localhost:3000"));
๐ Whatโs Happening?
res.setHeader('Content-Type', 'text/event-stream')
โ tells the browser this is a continuous stream.res.write("data: ...\n\n")
โ sends a message to the client (note the double\n\n
which is required by the SSE spec).- On the client,
eventSource.onmessage
receives these messages automatically. - If the connection drops, the browser reconnects.
๐น Format of SSE Messages
Each message from the server follows this simple text format:
data: Hello, this is a message!
For custom events:
event: news
data: Breaking: Server-Sent Events are lightweight!
For multiple lines:
data: This is line 1
data: This is line 2
The browser automatically combines them into a single message.
โ Pros of SSE
- Easy to implement: Just use
EventSource
in the browser โ no extra libraries. - Built-in automatic reconnection: Browser reconnects if the connection drops.
- Lightweight protocol: Text-based, simple to debug, runs over plain HTTP.
- Supports custom events: You can send different event types (
news
,update
, etc.). - Better than Polling/Long Polling: No need to open and close connections repeatedly.
- Firewall-friendly: Since it uses regular HTTP, it works well across firewalls and proxies.
โ Cons of SSE
One-way only: Server โ Client.
- If the client needs to send data, it must use a normal HTTP request or another channel.
- No binary support: SSE sends only UTF-8 text, unlike WebSockets that can send binary data.
- Limited browser support in the past: Modern browsers support SSE, but old versions of Internet Explorer donโt.
- Connection limits: Some browsers limit how many open SSE connections a single domain can have (e.g., 6).
๐น Best Use Cases for SSE
SSE is perfect when:
- The server only needs to push updates (no need for full two-way communication).
- You want simplicity over complex setups like WebSockets.
Applications like:
- ๐ Live dashboards (e.g., monitoring CPU usage, logs).
- ๐ฐ Live news or stock tickers.
- โฝ Sports score updates.
- ๐ Notifications/alerts.
- โฐ Real-time clocks, timers, or status updates.
๐ข 4. WebSockets
When you need true real-time, two-way communication between the client and the server, WebSockets are the go-to solution.
Unlike Server-Sent Events (SSE), which only allow the server to push data to the client, WebSockets provide a bi-directional channel where both client and server can send and receive data anytime.
Thatโs why WebSockets are used in chat apps, multiplayer games, live trading dashboards, and collaborative tools.
๐น How It Works
Handshake (Upgrade Request)
- Communication starts as a normal HTTP request.
- The client asks the server to "upgrade" the connection to the WebSocket protocol.
Example request headers:
GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
Upgrade Response
- The server responds confirming the upgrade.
- At this point, the connection switches from HTTP โ WebSocket protocol.
Full-Duplex Communication
- Once established, both client and server can send messages anytime, without re-establishing the connection.
- Messages are sent in small, efficient frames (text or binary).
Persistent Connection
- The connection remains open until either client or server closes it.
- Unlike polling or SSE, no repeated HTTP requests are needed.
๐น Example
Letโs build a simple chat app using WebSockets.
Server-Side (Node.js + ws library)
const WebSocket = require('ws');
// Create a WebSocket server on port 8080
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', ws => {
console.log("Client connected!");
// Listen for messages from the client
ws.on('message', message => {
console.log(`Received: ${message}`);
// Echo message back to client
ws.send(`You said: ${message}`);
});
// Send a welcome message
ws.send("Welcome to the WebSocket server!");
});
Client-Side (Browser JavaScript)
// Create WebSocket connection
const socket = new WebSocket('ws://localhost:8080');
// Connection opened
socket.onopen = () => {
console.log("Connected to server");
socket.send("Hello Server!");
};
// Listen for messages
socket.onmessage = (event) => {
console.log("Message from server:", event.data);
};
// Handle errors
socket.onerror = (error) => {
console.error("WebSocket Error:", error);
};
// Handle connection close
socket.onclose = () => {
console.log("Connection closed");
};
โ Now, whenever the client sends a message, the server instantly receives it and can respond back โ no polling required.
๐น WebSocket Message Format
WebSocket messages are sent in frames. Two main types:
- Text frames โ UTF-8 text messages.
- Binary frames โ Binary data (e.g., images, audio, video chunks).
This makes WebSockets ideal for applications that deal with more than just text.
โ Pros of WebSockets
- Bi-directional: Both client and server can send/receive messages anytime.
- Truly real-time: Near-zero latency after connection is established.
- Efficient: Only one connection, no repeated HTTP requests.
- Supports binary data: Unlike SSE, WebSockets can send images, audio, or binary blobs.
- Widely supported: Works on all modern browsers and mobile apps.
- Scalable: Can handle thousands of simultaneous connections with proper infrastructure.
โ Cons of WebSockets
- More complex: Harder to implement than SSE or polling.
- Needs stateful servers: Unlike stateless HTTP, servers must track connections.
- Scaling challenges: Load balancing WebSockets requires special considerations.
- No built-in reconnection: If a connection drops, you must write custom reconnection logic.
- Not ideal for one-way feeds: SSE is simpler and more efficient if you only need server โ client communication.
๐น Best Use Cases for WebSockets
WebSockets are the default choice when you need instant, two-way communication. Perfect for:
- ๐ฌ Chat applications (WhatsApp Web, Slack, Discord).
- ๐ฎ Multiplayer online games (real-time player updates).
- ๐ Live dashboards (stock prices, trading apps, monitoring tools).
- โ๏ธ Collaborative apps (Google Docs, whiteboards, shared coding).
- ๐ก IoT device communication (devices streaming data to servers).
๐ข 5. WebRTC
When we talk about real-time communication, WebSockets and SSE usually come to mind. But thereโs another powerful technology designed for direct peer-to-peer communication: WebRTC (Web Real-Time Communication).
Unlike WebSockets (which always go through a central server), WebRTC allows browsers, mobile apps, or devices to talk directly to each other for audio, video, and data sharing.
Thatโs why WebRTC powers apps like Google Meet, Zoom (web client), Discord voice chat, and file-sharing tools.
๐น How It Works
WebRTC is more complex than SSE or WebSockets because it involves peer-to-peer connections. The process usually involves three main steps:
Signaling
Before two peers can connect, they need to exchange information like:
- Network details (IP, ports).
- Media capabilities (video/audio formats).
- This is done using a signaling server (often via WebSockets or HTTP).
Connection Establishment
- Once peers have exchanged info, WebRTC tries to connect directly using ICE (Interactive Connectivity Establishment).
- It may use STUN servers (to discover public IP addresses behind NAT) or TURN servers (relay when direct connection isnโt possible).
Peer-to-Peer Communication
- After setup, peers exchange video, audio, or data directly without sending everything through the main server.
- This reduces latency and server costs.
๐น Example: Simple WebRTC Setup
Letโs build a very basic example where two browsers exchange video streams.
Client-Side (Browser JavaScript)
// Create a peer connection
const peer = new RTCPeerConnection();
// Get access to webcam + microphone
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then(stream => {
// Show local video
document.getElementById("localVideo").srcObject = stream;
// Add tracks to peer connection
stream.getTracks().forEach(track => peer.addTrack(track, stream));
});
// Handle remote stream
peer.ontrack = (event) => {
document.getElementById("remoteVideo").srcObject = event.streams[0];
};
// Create an offer (for signaling)
peer.createOffer().then(offer => {
peer.setLocalDescription(offer);
// Send this offer to the other peer via a signaling server
});
๐ Whatโs happening here:
- We request camera + microphone access.
- We attach our media tracks to the peer connection.
- We create an offer that contains connection details.
- This offer must be sent to the other peer using a signaling channel (e.g., WebSocket server).
On the other peerโs side, they would:
- Receive the offer.
- Set it as their remote description.
- Generate an answer and send it back.
After this handshake, the peers are connected and can exchange video/audio directly.
๐น WebRTC Data Channels
Besides video and audio, WebRTC also supports data channels for sending text, JSON, or files peer-to-peer.
const peer = new RTCPeerConnection();
// Create a data channel
const channel = peer.createDataChannel("chat");
// When the connection is open, send a message
channel.onopen = () => {
channel.send("Hello from Peer 1!");
};
// Listen for messages
channel.onmessage = (event) => {
console.log("Received:", event.data);
};
โ This can be used for real-time gaming, file sharing, or even building a peer-to-peer chat app without a central server.
โ Pros of WebRTC
- Peer-to-peer โ Low latency, no central server for streaming.
- Supports video, audio, and data โ Perfect for conferencing and file sharing.
- Bandwidth efficient โ No need to relay everything through a central server.
- Secure by default โ Uses DTLS (Datagram Transport Layer Security) and SRTP (Secure Real-time Transport Protocol).
- Cross-platform โ Works in browsers, mobile apps, IoT devices.
โ Cons of WebRTC
- Complex setup โ Requires signaling, STUN/TURN servers, and handling NAT/firewall issues.
- Not just client-server โ Works best for peer-to-peer, but scaling to many users (like a Zoom call) often requires additional media servers (SFU/MCU).
- Browser compatibility quirks โ While widely supported, there can be differences in implementation.
- Extra servers still needed โ Even though media is P2P, you need signaling + TURN fallback servers.
๐น Best Use Cases for WebRTC
WebRTC is designed for real-time peer-to-peer interactions:
- ๐ฅ Video conferencing apps (Google Meet, Jitsi, Zoom web client).
- ๐๏ธ Voice chat apps (Discord, WhatsApp Web calls).
- ๐ Peer-to-peer file sharing (send files directly without uploading to a server).
- ๐ฎ Multiplayer games (fast, low-latency data channels).
- ๐ IoT communication (devices streaming live sensor/video data).
๐ข 6. Using Third-Party Services
Sometimes, setting up your own WebSockets, SSE, or WebRTC infrastructure can feel overwhelming โ especially if youโre just starting out or want to move fast.
Thatโs where third-party services and libraries come in. They handle the complex real-time logic, so you can focus on building your app.
Here, weโll look at two of the most popular options:
๐น Firebase Realtime Database / Firestore
Firebase (by Google) is a Backend-as-a-Service (BaaS) platform. Its Realtime Database and Cloud Firestore allow apps to sync data instantly across clients without you having to manage WebSockets or servers.
How It Works:
- Data is stored in a NoSQL database (JSON for Realtime Database, document/collection model for Firestore).
- When data changes, all connected clients automatically get updates in real time.
- Firebase handles the underlying WebSockets/SSE for you.
Example (Firestore โ Client Side)
import { initializeApp } from "firebase/app";
import { getFirestore, collection, onSnapshot } from "firebase/firestore";
const firebaseConfig = {
apiKey: "your-api-key",
authDomain: "your-app.firebaseapp.com",
projectId: "your-project-id"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// Listen to real-time updates
const messagesRef = collection(db, "messages");
onSnapshot(messagesRef, (snapshot) => {
snapshot.docs.forEach(doc => {
console.log("New message:", doc.data());
});
});
โ In this example, whenever a new message is added to the messages collection, all connected clients immediately receive it.
Pros:
- Super easy to set up (just client-side code).
- No backend setup needed.
- Scales automatically.
- Great for beginners.
Cons:
- Vendor lock-in (tied to Google Cloud).
- Pricing can grow as usage scales.
- Less flexible for advanced use cases compared to building your own backend.
Best Use Cases:
- Simple chat apps.
- Live feeds (news, comments, dashboards).
- Collaborative tools with low-to-medium scale.
๐น Socket.IO (on top of WebSockets)
Socket.IO is a popular JavaScript library that makes working with WebSockets much easier. While WebSockets themselves are powerful, they can be tricky to implement (handling reconnections, fallbacks, etc.). Socket.IO abstracts all of that.
How It Works:
- Socket.IO runs on top of WebSockets (and falls back to long-polling if needed).
- Provides a simple event-based API (
socket.emit
,socket.on
). - Handles automatic reconnection, fallback, and broadcasting out of the box.
Example
Server (Node.js + Express)
const express = require("express");
const http = require("http");
const { Server } = require("socket.io");
const app = express();
const server = http.createServer(app);
const io = new Server(server);
io.on("connection", (socket) => {
console.log("A user connected");
// Listen for messages from client
socket.on("chat message", (msg) => {
console.log("Message:", msg);
// Broadcast to all clients
io.emit("chat message", msg);
});
socket.on("disconnect", () => {
console.log("User disconnected");
});
});
server.listen(3000, () => {
console.log("Socket.IO server running on http://localhost:3000");
});
Client (Browser)
const socket = io("http://localhost:3000");
// Send a message
socket.emit("chat message", "Hello everyone!");
// Listen for messages
socket.on("chat message", (msg) => {
console.log("Received:", msg);
});
โ With just a few lines, you get a real-time chat system with broadcasting and reconnection handling.
Pros:
- Event-driven API (easy to reason about).
- Handles reconnections and fallbacks automatically.
- Supports rooms and namespaces (for scaling).
- Works well for chat apps, multiplayer games, live dashboards.
Cons:
- Requires setting up a backend server (unlike Firebase).
- Adds an abstraction layer over WebSockets, which may limit very advanced use cases.
Best Use Cases:
- Chat/messaging apps.
- Multiplayer games.
- Collaboration tools (whiteboards, shared docs).
- Apps where you want full control of the backend.
๐ Which One Should You Choose?
Method | Direction | Efficiency | Best For |
Polling | Client โ Server | โ Poor | Simple checks |
Long Polling | Client โ Server | โก Better | Notifications |
SSE | Server โ Client | โก Efficient | Feeds, tickers |
WebSockets | Client โ Server | ๐ Excellent | Chat, games, dashboards |
WebRTC | Peer โ Peer | ๐ Excellent | Video/voice apps |
Third-Party | Varies | โ Easy setup | Quick prototypes, scaling |
๐ฏ Conclusion
Real-time communication is essential in modern apps.
- Use Polling/Long Polling if simplicity matters.
- Use SSE if updates are one-way.
- Use WebSockets for full bi-directional communication.
- Use WebRTC for peer-to-peer video/audio.
- Use third-party services for faster development.
๐ The right choice depends on your use case, scale, and complexity.
โจ Thatโs it! Now you know the different ways to implement real-time communication. Which one have you used in your projects? Let me know in the comments! ๐
๐ Whatโs Next?
You might want to explore:
- ๐งฐ Boost Your App Performance with Caching
- ๐ Supercharge Your Node.js App with node-cache
- ๐ง Understanding Memory Leaks in JavaScript
- ๐ณ Docker Simplified
โ๏ธ Authorโs Note
This blog is a comprehensive guide to real-time communication methods, but the best way to learn is by doing! Try implementing these techniques in your own projects. If you have any questions or suggestions, feel free to reach out.
๐ฌ Have Questions or Suggestions?
Drop a comment below or connect with me on LinkedIn or GitHub. Letโs make apps faster together! ๐
Subscribe to my newsletter
Read articles from KUNTAL MAITY directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

KUNTAL MAITY
KUNTAL MAITY
Iโm a passionate Full-Stack Developer who loves building performance-driven web and mobile applications. I work primarily with JavaScript, React, Next.js, Node.js, and MongoDB, and I enjoy simplifying complex concepts into developer-friendly tutorials. On this blog, you'll find hands-on guides, real-world projects, and developer insightsโall aimed at helping you level up your coding skills and build production-ready apps. Whether you're into backend performance, frontend polish, or full-stack architecture, there's something here for you! Letโs learn, build, and grow together. ๐ปโจ