System Design: Design WhatsApp Status/Stories — Ephemeral Content, Media Processing, View Tracking, Privacy, TTL

WhatsApp Status (stories) lets 2+ billion users share photos, videos, and text that disappear after 24 hours. Designing an ephemeral content system tests your understanding of TTL-based storage, media processing at massive scale, privacy-respecting view tracking, and efficient content distribution. This guide covers the architecture specific to stories/status features.

Data Model and TTL Storage

Status update: status_id, user_id, media_type (image/video/text), media_url, caption, created_at, expires_at (created_at + 24 hours), view_count, privacy_setting (all_contacts/selected_contacts/exclude_contacts). Storage strategy: (1) Active statuses (less than 24 hours old) are stored in a “hot” database with fast reads. Cassandra with TTL: INSERT … USING TTL 86400 automatically deletes the row after 24 hours. No garbage collection job needed. (2) Media files (images/videos) are stored in S3 with a lifecycle policy that deletes objects after 25 hours (1 hour buffer for clock skew and in-flight views). (3) A cleanup job runs hourly to catch any missed deletions and reconcile counts. Scale: if 500 million users post 1 status per day = 500 million statuses/day. Each with a 200 KB average media file = 100 TB of media per day, but only 100 TB is stored at any time (24-hour rolling window). With 3x replication in S3: 300 TB. The metadata is much smaller: 500 million rows in Cassandra at ~500 bytes each = 250 GB.

Status Tray: Who Has Updates?

The status tray (the row of circles at the top of the chat list) shows which contacts have active statuses. This is one of the most queried data structures — every time a user opens WhatsApp, the tray must be computed. Algorithm: (1) Get the user contact list (phone numbers). (2) For each contact, check if they have any active statuses (created_at within the last 24 hours AND the user is allowed to see them based on privacy settings). (3) Sort: unseen statuses first (contacts whose most recent status the user has not viewed), then by recency. Optimization: computing this for each of 500 million users with 100+ contacts each is expensive. Pre-compute: maintain a per-user status tray in Redis. When a contact posts a new status: push an update to all their contacts trays (fanout). When a status expires (TTL): the tray automatically becomes stale and refreshes on next view. Fanout consideration: a user with 1000 contacts posting a status triggers 1000 Redis updates. With 500M statuses/day from users averaging 200 contacts: 100 billion Redis updates per day. This is heavy but manageable with a Redis cluster. Alternative: lazy computation — compute the tray only when the user opens the app. Cache for 60 seconds. Most users do not refresh more frequently than that.

Media Processing

When a user uploads a status image or video: (1) The client compresses the media before upload (client-side compression reduces bandwidth). Images: resize to maximum 1024px, compress to JPEG quality 70. Videos: compress to 720p, cap at 30 seconds. (2) Upload to S3 via presigned URL (the server never handles the raw bytes). (3) Server-side processing: images — generate a thumbnail (150px) for the status tray preview, strip EXIF data (GPS location, camera info) for privacy, apply end-to-end encryption (encrypt the media with a symmetric key, distribute the key to authorized viewers via the Signal Protocol). Videos — generate a thumbnail from the first frame, validate duration (30-second limit), and transcode to a standard format if needed. (4) The processed media URL and encryption key are stored in the status metadata. (5) Push notification to contacts: “User X posted a status.” Content moderation: unlike regular WhatsApp messages (end-to-end encrypted, WhatsApp cannot read them), status media sent to “all contacts” is NOT end-to-end encrypted in all implementations. Some platforms scan for policy violations before distribution. WhatsApp uses on-device AI for content classification before upload.

View Tracking and Privacy

View tracking: when a user views a status, record: (viewer_id, status_id, viewed_at). The status creator sees the view count and the list of viewers. Storage: Cassandra with partition key = status_id. Each view is a row in the partition. For a popular user with 1000 contacts all viewing: 1000 rows per status. This is small per status but large in aggregate (500M statuses * average 50 views = 25 billion view records per day, but TTL-deleted after 24 hours). View receipt: when the viewer app downloads the status media, it sends a “viewed” signal to the server. The server records the view and pushes a real-time update to the creator (via WebSocket) incrementing the view count and adding the viewer to the list. Privacy settings: (1) My contacts — visible to all phone contacts who have your number. (2) My contacts except — visible to all contacts except a blocklist. (3) Only share with — visible only to a whitelist. The privacy check happens when: computing the status tray (do not show statuses the user cannot see) and when the user attempts to view (server verifies permission before serving the media). Muted contacts: users can mute specific contacts statuses. Muted statuses appear at the end of the tray, grayed out. Mute state is stored per-user in a local preference, not sent to the server (privacy — the poster does not know they are muted).

Distribution and Caching

Status media is viewed many times (once per contact). Caching is critical. CDN: media files are served via CDN. A popular user status (viewed by 500+ contacts) is cached at edge servers after the first few views. Long-tail users (viewed by 10-20 contacts) may not benefit from CDN caching — the origin serves directly. Pre-fetch: when the status tray loads, the app pre-fetches the thumbnails for all visible statuses. When the user taps a contact status ring, the full media for the first status is likely already cached (pre-fetched in the background). Sequential viewing: users view statuses in sequence (tap through a contact statuses one by one). Pre-fetch the next 2-3 statuses while the current one is being viewed for instant transitions. Bandwidth optimization: on cellular networks, auto-download only thumbnails. Full media downloads when the user explicitly taps. On WiFi: auto-download all. This setting is user-configurable (WhatsApp has detailed media auto-download settings per network type). Encryption key distribution: the symmetric encryption key for the status media is sent to each authorized contact via the existing WhatsApp messaging protocol (Signal Protocol). The key is ephemeral and deleted when the status expires.

Scroll to Top