HomeBlog › Design WhatsApp

Design WhatsApp

A chat messaging system design interview walkthrough: persistent WebSocket connections, the message queue and fan-out, message storage, delivery and read receipts, presence, and end-to-end encryption at scale.

"Design WhatsApp" is one of the most common chat messaging system design questions, and a close cousin of designing a generic chat app and designing a notification system. The crux is two-fold: holding millions of persistent connections so messages arrive instantly, and guaranteeing reliable, ordered delivery — even when the recipient's phone is off.

Here's the full WhatsApp system design walkthrough with a diagram, covering the WebSocket layer, the messaging protocol, message storage, delivery guarantees, presence, group messaging, encryption, and the trade-offs interviewers probe.

          +-----------+   WebSocket   +------------------+
  Send    |  Client A | ============> |  Gateway (conn)  |
  & Recv  +-----------+               +------------------+
                                        |        |
                          +-------------+        +-------------+
                          v                                    v
                  +-----------------+                  +-----------------+
                  | Message Service |  --- queue -->   | Message Store   |
                  | route + fan-out |                  | inbox, sharded  |
                  +--------+--------+                   +-----------------+
                           |
                           v
          +-----------+   WebSocket   +------------------+
          |  Client B | <============ |  Gateway (conn)  |
          +-----------+               +------------------+
                                        ^
                                   +---------+
                                   | Presence|
                                   |  (Redis)|
                                   +---------+
WhatsApp architecture: clients hold persistent WebSocket connections to stateless gateways; the message service routes and fans out through a queue; messages persist in a sharded per-user store, with presence tracked in Redis.

1. Clarify the requirements

Functional requirements

Non-functional requirements

Back-of-the-envelope scale: Assume 2B users and ~100B messages sent per day. That averages ~1.2M messages/sec, with peaks several times higher. Hundreds of millions of devices stay connected at once, so the connection layer — not raw compute — is the dominant cost. Messages themselves are tiny (a few hundred bytes), but media is offloaded separately, much like in designing Instagram.

2. API and protocol

Unlike a request/response app, chat is driven over a long-lived WebSocket. After a normal HTTPS handshake and auth, the client upgrades to a socket and exchanges small framed events in both directions.

# Establish the realtime channel
GET  /v1/connect        (HTTP upgrade -> WebSocket)

# Events over the open socket (bidirectional)
-> SEND     { toUserId, convId, clientMsgId, ciphertext }
<- ACK      { clientMsgId, serverMsgId, status: "stored" }
<- DELIVER  { serverMsgId, fromUserId, convId, ciphertext }
-> RECEIPT  { serverMsgId, status: "delivered" | "read" }
<- PRESENCE { userId, state: "online" | "offline", lastSeen }

3. High-level architecture

Every client opens a persistent WebSocket to a gateway server whose only job is connection management. Gateways are stateless about message content — they hold sockets and forward frames — so they scale horizontally, and a session registry (in Redis) maps each userId to the gateway currently holding its connection.

When Client A sends a message, its gateway hands it to the message service. That service assigns a server-side ID and ordering token, writes the message to the message store, and looks up where the recipient is connected. If Client B is online, the message is pushed to B's gateway and down its socket; if not, it stays queued in B's inbox until reconnect.

A message queue (Kafka-style) decouples ingestion from fan-out, so a burst of sends is absorbed and delivered asynchronously without dropping anything. Presence updates flow through a separate lightweight path so they never compete with message delivery.

4. Data model & storage

Message store: a wide-column store (Cassandra-style) is the natural fit — write-heavy, append-only, and easy to shard. Each message row holds:

Sharding: partition by conv_id so a conversation's messages live together and ordering is cheap within a shard. A monotonic per-conversation sequence number gives each message a total order, which is what makes ordered delivery possible without a global clock.

Presence / session registry (Redis): a fast key-value map of userId → gatewayId plus an online flag and last-seen timestamp, updated as connections open and close.

5. Delivery guarantees and ordering

This is the part interviewers push on hardest. A message must never be lost and must not appear out of order.

When the recipient is offline, the message sits in their inbox marked undelivered. On reconnect, the gateway replays the queued messages in sequence order, then flips them to delivered — the mechanism behind a receipt that shows up minutes later.

6. Presence, receipts, and groups

Presence and last-seen: when a socket opens, the user is marked online in Redis; when it closes, offline with a last-seen timestamp. To avoid a storm of updates, presence is only pushed to users who share an open conversation, and status changes are debounced.

Read receipts: sent, delivered, and read are just small ack events routed back through the same pipeline as a normal message — one tick when stored, two when the device receives it, blue when the chat is opened.

Group messaging: a group send fans out to each member — the service reads the member list, pushes to every online member's gateway, and queues for the offline ones. Because groups are capped at a few hundred members, fan-out stays bounded, unlike a social feed's celebrity problem in designing a news feed.

7. End-to-end encryption

With end-to-end encryption, messages are encrypted on the sender's device and decrypted only on the recipient's, so servers route ciphertext they cannot read. Key exchange happens directly between devices, and the backend stores a bundle of public prekeys so a sender can start a session even when the recipient is offline. Crucially, the connection, queuing, and fan-out layers are unchanged — they move opaque bytes and never see plaintext.

Key trade-offs the interviewer probes

Framework reminder: every system design answer follows the same arc — requirements → estimates → API → high-level design → data model → scale → trade-offs. Keep the system design cheat sheet in mind and narrate which stage you're in.

Practice chat messaging design with live AI support

CoPilot Interview surfaces a structured design skeleton — requirements, API, data model, and scaling — in about 4 seconds during real Zoom and Teams calls. Free for Windows and macOS, invisible on screen-share.

Try it free

FAQ

Why does WhatsApp use WebSockets instead of HTTP polling?

Chat needs instant, bidirectional delivery, so each client holds a persistent WebSocket connection to a gateway server. The server can push an incoming message down that open socket the moment it arrives, instead of the client repeatedly polling over HTTP. This cuts latency to milliseconds and avoids the wasted requests of long polling at scale.

How are messages delivered when the recipient is offline?

If the recipient has no active connection, the message is persisted in a per-user inbox or message store and marked undelivered. When the user reconnects, the server replays all queued messages in order, then marks them delivered. This is what lets the double-check mark appear later once the phone comes back online.

How do delivery and read receipts work?

Receipts are small acknowledgement messages that flow back to the sender. One check means the server stored the message, two checks mean the recipient's device received it, and blue checks mean the recipient opened the chat. Each transition is an ack event routed back through the same messaging pipeline as a normal message.

How does group messaging scale?

A message to a group is fanned out to each member: the server looks up the member list, then delivers a copy to every online member's connection and queues it for offline ones. Because groups are capped (a few hundred members), fan-out stays bounded, unlike a social feed where one post can reach millions of followers.

How does end-to-end encryption fit into the design?

With end-to-end encryption, messages are encrypted on the sender's device and only decrypted on the recipient's device, so the servers route ciphertext they cannot read. The backend still handles connection management, queuing, and fan-out exactly the same way — it just never sees plaintext, and key exchange happens directly between devices.