How live sports scores update in real time
How sports apps deliver sub-second score updates to millions of concurrent users using WebSocket fan-out, server-sent events, and intelligent client polling with delta compression.
The Problem Statement
Interviewer: "You are watching a live football match on a sports app. The moment a goal is scored in the stadium, the score on your phone updates almost instantly, along with millions of other users' phones. Walk me through how that works. How does the data get from the stadium to your screen in under a second?"
This question tests your understanding of real-time data pipelines at massive scale. The interviewer is looking for three things: how structured event data flows from a physical venue through ingestion systems to application servers, how you fan out a single event to millions of concurrent connections without melting your infrastructure, and whether you can reason about the bandwidth and connection management challenges of persistent connections at scale.
This question combines two hard problems. The first is data ingestion: turning a referee's whistle into a structured JSON event within a defined latency budget. The second is fan-out: delivering that event to millions of concurrent viewers quickly. Each problem alone is manageable. Combined, they create architectural constraints that force tradeoffs between latency, cost, and reliability.
The same patterns appear in stock tickers, live election results, multiplayer game state sync, and any system where millions of users need the same data at the same time. Once you understand the sports score architecture, you have a template for all broadcast-style real-time systems.
Clarifying the Scenario
You: "Before I design this, I want to scope the problem properly."
You: "When you say 'real time,' what latency budget are we targeting? Sub-second from the event happening in the stadium to the user's screen?"
Interviewer: "Under 2 seconds end-to-end for score changes. Clock updates can be slightly slower."
You: "How many concurrent users at peak? Are we talking regular season games or Super Bowl scale?"
Interviewer: "Design for Super Bowl scale. 100 million concurrent viewers, all wanting live updates."
You: "Should I cover just score updates, or the full event stream: substitutions, cards, play-by-play?"
Interviewer: "Full event stream. Score changes are the highest priority, but users see everything."
You: "Got it. I will structure my answer in three parts: how data gets from the stadium to our servers, how we fan out events to millions of concurrent connections, and how we optimize bandwidth using delta compression so we are not sending the full scoreboard on every update."
Interviewer: "Good structure. Start from the stadium."
Setting the latency budget early is critical. "Real time" means different things to different people. A 2-second budget for score changes gives us room for network jitter, but not for batch processing or polling delays. This constraint eliminates any design based on periodic API polling.
My Approach
I break this into four areas:
- Data ingestion pipeline: How a goal in the stadium becomes a structured event on our servers within 500ms
- Fan-out to millions: How a single event reaches 100M concurrent WebSocket connections without running 100M individual pushes from one server
- Delta compression: How we minimize bandwidth by sending only what changed, not the entire scoreboard every time
- Connection management: How we handle millions of persistent connections, graceful degradation for clients that cannot maintain WebSockets, and mobile-specific challenges
The core insight is that this is a broadcast problem, not a request-response problem. Every connected user receives the same data at the same time. That means we can use hierarchical fan-out (like a tree) instead of point-to-point delivery. One server tells 100 edge servers, each edge server tells 1 million clients. The event is copied at each tier, not sent individually from a central server.
Think of it like a stadium announcer using a PA system versus individually whispering the score to each fan. The announcer speaks once. The speakers (edge servers) amplify the message. Every fan hears it simultaneously.
Numbers at a glance
| Metric | Approximate value |
|---|---|
| Concurrent users (Super Bowl peak) | 100-150 million |
| Events per game (football) | 200-500 structured events |
| Score change events per game | 4-12 (goals, touchdowns, etc.) |
| Event payload size (delta) | 200-500 bytes |
| Full scoreboard payload | 2-5 KB |
| Target end-to-end latency | Under 2 seconds |
| WebSocket connections per edge server | 500K-1M |
| Edge servers needed at peak | 100-300 |
| Data provider webhook latency | 100-300ms from live event |
Scale context: why this is a broadcast problem
During the 2024 Super Bowl, over 120 million viewers watched simultaneously. If each viewer's app polls your API every 5 seconds, that is 24 million requests per second. A typical API server handles 10,000 requests per second. You would need 2,400 API servers just for polling, and 80% of responses would be "nothing changed." WebSocket push eliminates this entirely: you send data only when something actually happens.
The Architecture
Here is the full pipeline from stadium event to user's screen.
Let me walk through the critical path. When a goal is scored, the official scorer in the stadium enters it into the data provider's system (Sportradar, Opta, or Stats Perform). The data provider's system generates a structured JSON event and sends it to our webhook endpoint within 100-300ms of the live event. Our ingestion layer validates, deduplicates, normalizes the event, and publishes it to a Kafka topic partitioned by game ID. The fan-out layer consumes from Kafka and pushes the event to all edge servers that have subscribers for that game. Each edge server pushes the event to its connected clients via WebSocket.
Total latency budget: 200ms (provider) + 50ms (ingestion) + 50ms (Kafka to router) + 50ms (router to edge) + 50ms (edge to client) = roughly 400-600ms in the happy path. Well within our 2-second budget, with room for network jitter.
The key architectural decision is the hierarchical fan-out. The Kafka consumer (router) does not push to 100 million clients directly. It pushes to 200 edge servers. Each edge server is responsible for its own pool of 500K connections. This is the tree-shaped broadcast that makes the math work.
Common mistake: single-tier fan-out
Candidates often draw a single WebSocket server that pushes to all clients. At 100M connections, even if each push takes 1 microsecond, broadcasting to all clients from one server takes 100 seconds. Hierarchical fan-out (router to edge servers to clients) is essential. Think of it as a CDN for real-time events.
Deep Dive 1: The Data Ingestion Pipeline: From Stadium to Server
The journey from a real-world event to a structured data event is more complex than most engineers realize. There is a human in the loop, and the data passes through a third-party provider before reaching your infrastructure.
The data provider is a critical dependency. A provider may combine operators, venue feeds, and automated sensors. Its system validates the event against the current game state (you cannot score a goal during halftime), assigns a unique event ID and UTC timestamp, and pushes it to your webhook within a provider-specific latency budget.
Source tiers and validation
The source tier depends on the sport and venue:
- Automated tracking can provide fast position or clock signals, but may not cover every event or venue.
- Human operators can classify goals, penalties, substitutions, and other semantic events when automated signals are unavailable or need confirmation.
- Broadcast or manual fallback can keep the feed alive during a provider outage, with a clearly degraded latency guarantee.
For high-impact events, ingesting more than one source can improve resilience. Compare events using a semantic key such as game_id + event_type + game_clock + team, deduplicate retries, and route disagreements for correction or review instead of silently emitting two score changes.
Event types and priorities
Not all events are equal. Score changes are the highest priority and should be delivered with the lowest latency. Clock updates are lower priority and can tolerate slightly higher latency. A useful priority model is:
| Priority | Event types | Latency target | Delivery guarantee |
|---|---|---|---|
| P0 (critical) | Score change, game start, game end | Under 1 second | At-least-once, ordered |
| P1 (high) | Cards, substitutions, penalties | Under 2 seconds | At-least-once |
| P2 (medium) | Play-by-play, possession changes | Under 5 seconds | Best-effort |
| P3 (low) | Clock tick, statistics updates | Under 10 seconds | Best-effort, batched |
P0 events bypass any batching or aggregation. They flow through the pipeline immediately. P3 events (like clock ticks every second) are batched into 5-second windows to reduce fan-out volume. This priority system is how you prevent a flood of possession-change events from delaying score update delivery.
Deduplication
Data providers sometimes send duplicate events (network retry, provider-side retry). The webhook receiver tracks seen event IDs in a Redis set with a 1-hour TTL. If an event ID has been seen before, the receiver drops it. This is cheap and effective because event IDs are small strings and the deduplication window only needs to cover the retry period.
Key insight: the data provider is the bottleneck you cannot control
Your entire pipeline can be under 200ms, but if the data provider takes 5 seconds to enter and transmit the event, users see it 5 seconds late. Provider latency is therefore an important SLA to measure and negotiate. Some platforms use multiple providers simultaneously and race the events, taking whichever arrives first while reconciling disagreements later.
Deep Dive 2: Fan-Out to Millions of Concurrent Users
The hardest engineering problem in this system is not receiving events. It is delivering a single event to 100 million connected clients in under a second. This is the fan-out challenge.
The fan-out happens in two tiers. Tier 1: the Kafka consumer publishes the event to a Redis Pub/Sub channel named after the game ID. Every edge server that has clients subscribed to that game listens on that channel. Redis Pub/Sub delivers the message to all subscribers in microseconds. Tier 2: each edge server iterates through its local subscriber list for that game and pushes the event to each WebSocket connection.
Connection management at scale
A single Linux server can handle 500K-1M concurrent WebSocket connections with proper tuning (ulimit -n, net.core.somaxconn, tcp_tw_reuse). The bottleneck is not memory (each connection uses roughly 2-4 KB of kernel buffer), but CPU for serializing and writing messages to each socket.
At 100M concurrent connections, you need 100-200 edge servers. These are distributed geographically: US-East, US-West, EU-West, AP-South, etc. Users connect to the nearest edge server via DNS-based routing or an anycast IP. This reduces latency and distributes the connection load.
Channel-based subscription
When a user opens the "Game A Live" page, their client establishes a WebSocket connection to the nearest edge server and sends a subscription message: {"subscribe": "game:12345"}. The edge server adds that connection to its local subscriber set for game 12345. When an event arrives for game 12345 via Redis Pub/Sub, the edge server iterates through the subscriber set and writes the event to each connection.
This is efficient because:
- Only clients watching Game A receive Game A events (no wasted bandwidth for irrelevant games)
- The subscription state is local to each edge server (no distributed subscription registry needed)
- Adding/removing subscriptions is O(1) on a hash set
Delivery protocol hierarchy
Not every client can maintain a WebSocket connection. Corporate firewalls, proxy servers, and some mobile networks block WebSocket upgrades. A protocol hierarchy with automatic fallback is useful:
| Protocol | Best for | Latency | Server cost | Limitation |
|---|---|---|---|---|
| WebSocket | Modern browsers, mobile apps | 50-100ms | Medium (persistent connections) | Blocked by some proxies |
| Server-Sent Events (SSE) | Restricted networks, simpler clients | 100-200ms | Low (HTTP-based, one-directional) | No binary data, browser limit of 6 connections |
| Long-polling | Legacy clients, extreme fallback | 1-5 seconds | High (repeated HTTP requests) | Higher latency, more server load |
The client tries WebSocket first. If the connection upgrade fails (HTTP 403 or timeout), it falls back to SSE. If SSE also fails, it falls back to long-polling with a 5-second interval. This graceful degradation ensures every client gets updates, with the best possible latency for their network environment.
CDN-cached recovery path
Polling should not be the primary delivery mechanism, but it is a valuable recovery path. Keep the latest full game snapshot in a cache or CDN with a short TTLβoften around 1-2 seconds for a live matchβand let reconnecting or restricted clients fetch that snapshot. Clients using persistent connections can also poll occasionally as a consistency baseline. The cache reduces repeated reads from the origin, while the snapshot's sequence number tells the client whether it is current.
Deep Dive 3: Delta Compression and Bandwidth Optimization
When 100 million users are connected simultaneously, every byte matters. Sending the full scoreboard (2-5 KB) on every event wastes bandwidth. Most events change only one or two fields. Delta compression sends only what changed.
The protocol works in three modes:
- Snapshot: Sent when a client first connects or falls too far behind. Contains the complete game state. Roughly 2-5 KB.
- Delta: Sent for each event. Contains only the fields that changed, plus a sequence number. Roughly 200-500 bytes.
- Delta batch: Sent when a client reconnects and missed a few events. Contains an ordered list of deltas from the client's last known sequence number.
Sequence numbers for ordering
Every event gets a monotonically increasing sequence number within a game. The client tracks the last sequence number it received. If it receives seq 48 after seq 46 (missed 47), it requests a re-sync from seq 47. The edge server maintains a sliding window of recent deltas (last 100 events per game) in memory. If the client's last sequence is within the window, send the missing deltas. If it is too far behind (e.g., reconnecting after 30 minutes), send a full snapshot.
This is the same pattern used in collaborative editors, video game netcode, and database replication. Sequence numbers with re-sync are a general answer to "what if I missed something?"
Bandwidth math
Let me do the math to show why delta compression matters:
- Without compression: 100M users x 200 events per game x 3 KB per event = 60 TB per game. That is roughly $5,000 in bandwidth cost per game.
- With delta compression: 100M users x 200 events x 300 bytes per delta = 6 TB per game. Ten times cheaper.
- With batched clock ticks: Clock ticks (every second for 90 minutes = 5,400 events) are batched into 5-second windows, reducing clock events from 5,400 to 1,080. Further savings.
For mobile users on cellular, bandwidth is even more precious. Applying gzip or another negotiated compression method to WebSocket frames can reduce repetitive JSON payloads, though CPU cost and compression side channels must be considered.
A representative real-time architecture
A large sports service can combine WebSocket push for its app, SSE for restricted browsers, and edge-cached polling endpoints for third-party embeds. Capacity and latency targets should be established from measured event rates and connection counts rather than assumed from a single provider or product.
The Tricky Parts
-
Mobile connection instability: Mobile users switch between WiFi and cellular, go through tunnels, and have intermittent connectivity. The WebSocket connection drops and must be re-established. The client needs automatic reconnection with exponential backoff, and the re-sync protocol (sequence numbers) ensures no events are lost during the gap. Caching the last known game state locally keeps the UI from flashing to a loading state on every reconnection.
-
Thundering herd on game start: When a major game starts, millions of users open the app simultaneously. All of them need to establish WebSocket connections and request initial snapshots at the same time. Without connection rate limiting, edge servers will be overwhelmed. A jittered connection window lets each client add a random delay of 0-5 seconds before connecting, spreading the thundering herd over a few seconds.
-
Multi-game scoreboards: A user watching a "scoreboard" page sees live updates for 15 games simultaneously. Subscribing to 15 channels per connection multiplies the fan-out work on the edge server. Aggregate events for "scoreboard" subscribers: instead of pushing every event for every game individually, batch all events from the last second into a single "scoreboard update" message. This reduces per-client pushes from potentially dozens per second to one per second.
-
Event ordering across providers: If you use multiple data providers for redundancy and race their events, you may receive them out of order. Provider A sends "goal at minute 73" before Provider B sends "corner kick at minute 72." Your normalizer must re-order events by game clock, not by arrival time. A short buffer (500ms) at the normalizer allows events to arrive and be sorted before publishing.
-
Corrections and review events: A VAR review or later provider correction must be published as a new sequenced event, not by mutating an event already delivered. The client can reconcile the score and show the correction state; the event log remains auditable and reconnecting clients receive the same ordered history.
-
Data provider failure: If a primary provider's feed goes down mid-game, there are no new events from that source. A secondary provider can be activated automatically, and manual entry can be the last resort with degraded latency. A visible "last updated" timestamp manages expectations during outages.
-
Push notification for key events: Not every user has the app open. Users who "follow" a team but are not actively watching should receive a mobile push notification for goals and game-ending events. This is a separate pipeline: the event router publishes P0 events to a push notification service (Firebase Cloud Messaging, APNs) that handles delivery to offline devices. The push notification includes just enough data to update the lock screen widget.
Do not conflate push notifications with WebSocket push
WebSocket push is for live, in-app updates to active users. Mobile push notifications (FCM/APNs) are for reaching users whose app is closed. They use completely different infrastructure, have different latency characteristics (push notifications can take 1-10 seconds), and different rate limits (APNs throttles per device). Design them as separate systems that share the same event source.
What Most People Get Wrong
| Mistake | What they say | Why it is wrong | What to say instead |
|---|---|---|---|
| Polling-first design | "Clients poll the API every second" | 100M users x 1 req/sec = 100M QPS, mostly wasted | "WebSocket push with SSE and polling as fallbacks" |
| Single-tier fan-out | "The server pushes to all clients" | One server cannot iterate 100M connections in under a second | "Hierarchical fan-out: router to edge servers to clients" |
| Ignoring the data source | "Events come from our system" | You do not generate sports data; third-party providers do | "Sportradar/Opta webhook with HMAC verification and dedup" |
| Full state on every push | "Send the complete scoreboard" | 3KB x 100M users x 200 events = 60 TB per game | "Delta compression with sequence numbers for gap detection" |
| No fallback for WebSocket | "Everyone uses WebSocket" | Corporate proxies and mobile networks block WS upgrades | "WebSocket first, SSE fallback, long-poll last resort" |
How I Would Communicate This in an Interview
Here is how I would actually say this:
"The pipeline has three stages: ingestion, fan-out, and delivery.
For ingestion, sports data comes from third-party providers like Sportradar. They have operators at every venue who enter events in real time. The provider sends us the event via a signed webhook within 200ms of it happening. Our ingestion layer validates the signature, deduplicates by event ID, normalizes the event into a unified format across sports, and publishes it to a Kafka topic partitioned by game ID.
For fan-out, I would not have clients poll. At Super Bowl scale (100M concurrent users), polling generates 50M+ requests per second with 95% returning 'no change.' Instead, clients maintain WebSocket connections to dedicated edge servers. When an event arrives, the Kafka consumer publishes it to Redis Pub/Sub on a channel named after the game. Every edge server subscribed to that game receives the event and pushes it to its local WebSocket connections. This is a two-tier fan-out: one event becomes 200 edge server pushes, each of which becomes 500K client pushes.
For bandwidth, I use delta compression. On first connect, the client gets a full snapshot. After that, each event is a delta containing only changed fields plus a sequence number. If the client detects a gap in sequence numbers (missed event due to disconnection), it requests a re-sync. The edge server maintains a sliding window of recent deltas for efficient re-sync.
The fallback hierarchy is WebSocket first, Server-Sent Events if WebSocket fails, and long-polling as a last resort. For users not in the app, key events trigger mobile push notifications through FCM/APNs as a separate pipeline."
Interview Cheat Sheet
- "Where does the data come from?" Say: third-party data providers (Sportradar, Opta) have operators at venues who enter events in real time; they push to our webhook within 200ms.
- "Why not poll for updates?" Say: at 100M users, polling generates 50M+ QPS with 95% returning no change; WebSocket push sends data only when something happens, eliminating wasted requests.
- "How do you handle 100M concurrent connections?" Say: hierarchical fan-out with dedicated edge servers; each edge server holds 500K-1M connections; Redis Pub/Sub distributes events from Kafka to all edge servers in microseconds.
- "What if WebSocket is blocked?" Say: protocol fallback hierarchy: WebSocket first, SSE second, long-polling third; client detects and falls back automatically.
- "How do you save bandwidth?" Say: delta compression; send only changed fields plus sequence numbers; full snapshots only on initial connect or if client falls too far behind.
- "What if the client misses an event?" Say: sequence numbers on every delta; client detects gaps and requests re-sync; edge server maintains a sliding window of recent deltas for efficient catch-up.
- "What if the data provider goes down?" Say: multi-provider redundancy; race events from two providers, take whichever arrives first; if both fail, manual fallback with degraded latency.
- "How do you handle game start thundering herd?" Say: jittered connection window; clients add random 0-5 second delay before connecting; pre-warm edge servers for major events.
- "What about users not in the app?" Say: separate push notification pipeline via FCM/APNs for key events (goals, game end); different infrastructure, different latency guarantees.
- "What is the latency budget?" Say: 200ms provider to webhook, 50ms ingestion, 100ms Kafka to edge, 50ms edge to client; total 400-600ms typical, well under the 2-second target.
Test Your Understanding
Q1. During the Super Bowl halftime show, 80 million users close the sports app. When the second half starts, they all reopen it within 30 seconds. Each client needs to re-establish a WebSocket connection and receive a full game state snapshot. How do you prevent this from crashing your edge servers?
Q2. A user's app shows the score as 21-14, but the actual score is 21-21. The user missed a score update because their WebSocket connection dropped briefly during a tunnel. How does the system detect and fix this without the user manually refreshing?
Q3. You are using Redis Pub/Sub to fan out events from the router to edge servers. Redis Pub/Sub has no message persistence: if an edge server is temporarily disconnected from Redis (network blip), it misses any events published during the gap. How do you handle this?
Q4. Your system processes events from two data providers simultaneously for redundancy. Provider A sends a "touchdown" event 300ms before Provider B sends the same event. How do you prevent sending duplicate score updates to users?
Q5. A major soccer match has 50 million viewers. During normal play, you send about 1 event per second (possession changes, fouls). But when a goal is scored, you send a burst of 5 events in 500ms (goal event, updated score, scorer details, assist details, celebration replay timestamp). Some edge servers report packet loss under this burst. How do you smooth this out?
Q6. Your edge servers are in four regions (US-East, US-West, EU-West, Asia). A user in the US is watching a Premier League match happening in England. The data provider sends the webhook to your US-East ingestion endpoint. The event must reach the user connected to a US-West edge server. What is the latency for each hop, and where is the biggest bottleneck?
Q7. Your system sends push notifications for goals to users who follow a team but do not have the app open. During a Champions League night with 8 simultaneous matches, 6 goals are scored within a 2-minute window. A user following all 8 teams gets 6 push notifications in rapid succession. The user complains about notification spam. How do you fix this?
Q8. Your company decides to add live betting odds to the sports score feed. A betting company provides odds that update every 100ms. This is 10x the event volume of score updates. How does this affect your architecture, and what would you change?
Quick Recap
- Live sports data comes from third-party providers (Sportradar, Opta) who have operators at venues entering events in real time, delivering via webhook within 200-500ms.
- The ingestion layer validates HMAC signatures, deduplicates by event ID, normalizes across sports, and publishes to Kafka partitioned by game ID.
- Fan-out uses a hierarchical two-tier model: Kafka to Redis Pub/Sub to edge servers to clients, turning one event into millions of client pushes without any single server handling all connections.
- Dedicated edge servers handle 500K-1M WebSocket connections each, separate from application servers, and are geographically distributed.
- Delta compression sends only changed fields with sequence numbers, reducing bandwidth by 10x compared to full-state pushes, with snapshot fallback for reconnecting clients.
- The protocol fallback hierarchy (WebSocket, SSE, long-polling) ensures every client gets updates regardless of network restrictions.
- Mobile push notifications for key events use a separate pipeline (FCM/APNs) for users who do not have the app open.
- The human operator at the stadium is the largest source of latency in the entire pipeline, dwarfing all network and processing delays combined.
Related Concepts
- WebSocket architecture: The persistent connection protocol that enables server-push without polling, used here for the last-mile delivery to clients.
- Pub/Sub and message fan-out: Redis Pub/Sub and Kafka's topic model are the distribution backbone, the same patterns used in chat systems, notification pipelines, and collaborative editing.
- CDN edge computing: Edge servers for WebSocket connections are conceptually similar to CDN edge nodes: stateless, geographically distributed, and handling the last-mile delivery.
- Event sourcing: The sequence-numbered delta model is a lightweight form of event sourcing, where the current state is reconstructed from an ordered log of events.
- Operational Transform and CRDTs: The "detect gaps, re-sync" protocol used here for score updates is a simplified version of the conflict resolution protocols used in Google Docs and collaborative editors.