Design problems
Media & streamingHardSDE-3 40 min

Design live cricket streaming for 25M+ viewers (JioHotstar)

Asked at
AmazonDream11GoogleJioHotstarNetflix

The interviewer asks

“Design the streaming platform for an India vs Pakistan World Cup match on an app like JioHotstar. Expect 25M+ concurrent viewers, sudden surges when a wicket falls or a star walks out to bat, commentary in several Indian languages, ads in every over break, and a live scorecard.”

What a strong answer looks like

This is not a general live-streaming design; it is a capacity and survival problem around one known event. A strong answer starts with the numbers: 25-50M concurrent viewers mostly on mobile at ~1-1.5 Mbps is 30-60 Tbps, close to the total CDN capacity available in India, and traffic can jump by millions of users within minutes. The video path is one high-quality broadcast feed encoded redundantly in two regions, packaged once into HLS/DASH with many language audio tracks, and distributed through several CDNs with client-side steering. The real deep dives are elsewhere: you cannot autoscale fast enough, so you pre-scale from a forecast and load-test beyond it; you protect the API tier with CDN-cached, non-personalised responses and pre-planned degradation levels (a 'panic mode' that switches off non-essential features and caps bitrate); you serve 25M simultaneous ad breaks with cohort-based server-side ad insertion; and you push the scorecard as cacheable JSON rather than millions of sockets.

Concepts to mention

Bandwidth maths: concurrency × bitrate vs CDN capacityPre-scaling from a forecast instead of autoscalingLoad testing realistic surge shapesDegradation levels delivered via cached configMulti-CDN with QoE-based steering and client failoverRedundant encoders in two regions with aligned segmentsBitrate capping as a capacity leverSeparate audio renditions for commentary languagesCohort-based server-side ad insertionScorecard as CDN-cached JSONSigned playback tokens validated at the edgeJittered retries to avoid reconnect storms

1 Requirements

Functional

  • Watch the live match with adaptive bitrate on mobile, web and TV
  • Choose commentary language (English, Hindi, Tamil, Telugu, Kannada, Bengali, Marathi) and switch without restarting
  • Subscription and free-tier entitlement, login with OTP
  • Server-side ads in over breaks and between innings, targeted by cohort
  • Live scorecard and ball-by-ball updates in the app
  • Live concurrency figure shown to users and to internal teams
  • Pause and rewind within the live window; highlights after key moments

Non-functional

  • 25M concurrent viewers as the base case; design and test for 50M+
  • Survive surges of 1-3M new viewers per minute (toss, wicket, last overs, a famous batter coming in)
  • Video start < 3 s p90; rebuffering < 1% of viewing time on 4G
  • Latency behind live: ~15-30 s is acceptable (stability matters more than being first); keep spoilers within a few seconds of TV
  • Playback availability 99.99% for the duration of the match; no single CDN, region or encoder can take the stream down
  • Ad breaks start for all viewers within the 30-60 s over break

Out of scope (say it out loud)

  • Broadcast production (cameras, graphics) before the feed reaches us
  • Payments for subscriptions
  • Fantasy games and live chat inside the app
  • Recommendations outside the match page

2 Estimates

Peak egress~30 Tbps at 25M, ~60-75 Tbps at 50MMostly mobile at 720p or lower: ~1.2-1.5 Mbps average × 25M ≈ 30-37 Tbps
Viewer surge rate~20-50k new sessions/s1-3M users joining within a minute after a wicket or at the start of the second innings ÷ 60 s
Segment requests at edges~5-6M req/s25M viewers ÷ ~4-6 s segments; plus playlist refreshes, for each language track
API requests during surges~200-500k req/sEach joining user makes ~5-10 calls (config, auth refresh, entitlement, playback, ads, scorecard) within seconds: 40k joins/s × ~8
Concurrency heartbeats~400k-1M/s25-50M viewers × one heartbeat per ~50-60 s
Ad decisions per break25M within ~5-10 sEvery viewer hits the ad break at the same moment; per-user ad calls would be 2.5-5M req/s
Encoding~10-20 renditions × 2 regionsOne feed, ladder from ~180p at 200 kbps to 1080p at 5-6 Mbps (4K for TVs), plus ~7 audio tracks; tiny compute compared to delivery

3 API

EndpointWhat it does
GET/v1/config?app_version=…CDN-cached app configuration and feature flags, including the current degradation level
GET/v1/match/{id}/pageMatch page layout, mostly static and CDN-cached for 10-30 s
POST/v1/playback/{content_id}Entitlement check and signed, CDN-specific playback URLs with a token
GEThttps://cdnX…/live/{match}/master.m3u8?token=…Master playlist with video renditions and language audio groups
GEThttps://cdn…/score/{match}.jsonScorecard snapshot, regenerated every ball, cached at CDN for 2-5 s
POST/v1/heartbeatSession alive signal every ~60 s for concurrency counting and stream limits
POST/v1/auth/otpOTP login; rate-limited and queued during surges

4 Data model

users and subscriptionsSharded Postgres / Aurora + Redis cache
user_idphoneplanplan_expirydevicesregion

Entitlement is cached in a signed token on the device so the playback call rarely needs the database.

live segmentsPackager origin + CDN shield
match/rendition/segment_nmatch/audio_{lang}/segment_nplaylists

Produced in two regions; CDNs pull from the active origin with a fallback.

playback tokensStateless signed tokens (HMAC/JWT)
user_idcontent_idcdnexpirymax bitrate

CDN edges validate tokens without calling back to the origin.

concurrency countersKafka → Flink → Redis
match_idwindowcount by platform/region/language

Aggregated stream counts; the public number is approximate and smoothed.

ad pods by cohortRedis / CDN-cached manifests
break_idcohort_id (city tier, language, device, subscriber)ad pod segment list

Prepared before each break; tens to hundreds of cohorts instead of 25M individual decisions.

scorecardRedis + JSON files on CDN
match statebatting/bowling cardslast 12 ballscommentary text

Updated by the data operator feed every ball; published as a static file.

QoE eventsKafka → ClickHouse
sessionCDNISPcitybitraterebuffererrorsstart time

Real-time dashboards per CDN and ISP drive steering decisions during the match.

5 Architecture

CLIENTSEDGESERVICESASYNCDATAEXTERNALSRT / fibre, 2 pathsHLS/DASH + audiocollapsed pullsvideo, score JSONconfig, play, beatcached 30 scache miss onlycohort podsstitched playlistsscore.json per ballheartbeatsQoE by CDN/ISPconcurrencysteer, degradeViewer apps (mostlymobile)API edge (WAF, cache)Multi-CDN edgesEntitlement +playbackSSAI ad stitcherConfig + panicswitchesScorecard publisherKafka (heartbeats,QoE)Encoders + packagersx2Flink concurrency +QoEUsers + subscriptionsDBRedis (tokens, pods)Origin + shieldClickHouse dashboardsBroadcast feed(stadium)
ClientEdge / gatewayService / workerQueue / streamCacheDatabase / storageAI / modelThird partyrequestasync (event / queue)

Hover a box to highlight its connections.

6 Request flows

A wicket falls and 2M people open the app

  1. 1Push notifications and social media send millions of users to the app within a minute.
  2. 2The app fetches /config from the CDN (cached, no origin hit); it carries feature flags such as 'recommendations off' and 'max bitrate 720p' if a degradation level is active.
  3. 3The match page comes from the CDN too; personalised widgets are disabled at high load so the response is identical for everyone and fully cacheable.
  4. 4The app calls /playback; the API edge forwards to the entitlement service, which validates the user's signed session token and subscription from the token or Redis, without touching the database for most users.
  5. 5The service returns a signed URL on one of three CDNs, chosen by weight for the user's ISP and region from live QoE data.
  6. 6The player loads the master playlist, starts at a low rendition to begin quickly, and climbs to its allowed maximum bitrate.
  7. 7Clients add random jitter (0-30 s) to non-urgent calls such as profile refresh and heartbeats, so the surge does not hit every API at once.

Over break with ads

  1. 1The broadcaster signals an ad break with SCTE-35 markers in the feed.
  2. 2Before the break, the ad system has already chosen ad pods for each cohort (e.g. Hindi + Tier-2 city + Android + free user) and stitched their segments into cohort-specific playlist variants.
  3. 3The packager inserts the break; each player's playlist (which encodes its cohort) points to its pod's segments, all cached on the CDN like normal video.
  4. 4Ad impression beacons are batched by the client and sent to Kafka after the break, spreading the load.
  5. 5When the next over starts, playlists switch back to the live segments.

One CDN starts failing in Maharashtra

  1. 1QoE events show rising rebuffering and errors for CDN B on two ISPs in Maharashtra within 1-2 minutes.
  2. 2The steering config is updated to move new sessions in that region to CDN A and C; the change is pushed through the cached config endpoint.
  3. 3Players already on CDN B retry failing segments on alternate CDN URLs listed in their playlist, moving without stopping playback.
  4. 4If total capacity is short, the degradation level is raised and the maximum bitrate is capped at 480p for free users to fit everyone.

7 Deep dives

Pre-scale, do not autoscale

Autoscaling reacts in minutes; cricket traffic jumps by millions in under a minute, and new instances also need warm caches and connection pools. So the platform scales ahead of time. Start from a forecast per match (teams, stage, day of week, time) built from past matches; India vs Pakistan or a final gets the top tier. Provision API, entitlement and ad services for 1.5-2x the forecast peak about an hour before the toss, pre-warm caches (config, match page, entitlement caches), and raise CDN commitments with each provider days in advance, since CDN and ISP capacity cannot be bought on the spot. Validate with load tests that simulate the real traffic shape, including surges and mass reconnects, not just a steady rate; Hotstar has spoken publicly about running large synthetic load tests before big tournaments. Know your limits per component in advance, including hidden ones: database connection limits, OTP SMS provider throughput, cloud account quotas for instances and load balancers, and NAT or IP limits. Scale down only after the match, slowly.

Graceful degradation levels (panic mode)

At 50M users something will be short of capacity, so decide in advance what to switch off. Define levels and rehearse them. Level 1: turn off personalised recommendations, watch-history writes and non-essential widgets; serve one static match page from CDN. Level 2: stop showing live viewer counts per user, increase heartbeat interval from 60 s to 5 minutes, pause profile and settings updates. Level 3: cap maximum bitrate (e.g. 720p for subscribers, 480p for free users) to fit within total CDN capacity; this is the main lever because egress is the scarcest resource. Level 4: put new logins in a waiting queue and extend validity of existing tokens so logged-in users are never kicked out. Levels are feature flags delivered through the CDN-cached config endpoint, so changing them does not need the struggling API tier. The principle: protect the video for people already watching above everything else. A client that cannot reach a non-essential API must fail silently, not show an error screen.

Multi-CDN delivery and the bitrate budget

No single CDN has 50-70 Tbps of spare capacity in India on a match night, and Indian traffic is concentrated on a few large mobile ISPs. So the stream is published to several CDNs from redundant origins in two cloud regions, each with its own encoder and packager fed by two independent paths from the stadium (with identical segment numbering so players can switch). The playback service steers sessions by weights per (ISP, region, CDN) from real-time QoE data, and playlists contain alternate CDN URLs so players can switch mid-stream on errors. Request collapsing at shields means each segment is fetched from origin only a few times per CDN. The ladder is tuned for mobile: most viewers watch on phones where 480p-720p looks good, so a good 720p at ~1.5-2 Mbps matters more than 4K. Multi-language commentary is delivered as separate audio renditions sharing the same video, which saves bandwidth and lets users switch language without rebuffering; the bitrate cap is applied per user tier through the playback token and player config.

Ads and scorecards for 25M at the same instant

Two features hit everyone at exactly the same moment. Ads: per-user ad decisions at an over break would be millions of requests per second to the ad server in a few seconds, plus per-user stitched playlists that the CDN cannot cache. Instead, segment users into a manageable number of cohorts (language, region/city tier, device, subscriber status, sometimes broad interest), decide ad pods per cohort before the break, and serve cohort-specific playlist variants that the CDN caches like any other content. Impression tracking is batched and delayed so it does not compete with the stream. Scorecard: keeping 25M WebSockets open just to push a score every 30 seconds is expensive and fragile under reconnect storms. Publish the scorecard as a small JSON file to the CDN after each ball with a short cache TTL (2-5 s), and let clients poll it with jitter, or embed score data in the video stream's timed metadata. Polling a cached file scales with the CDN, not with your servers. Spoilers matter: because video runs ~20 s behind live, the app should delay the scorecard to match the player's position.

8 Trade-offs

Higher latency for stability

Low-latency modes with 1-2 s buffers rebuffer more on congested 4G and cause more retries during surges. For a mass audience, a 15-30 s behind-live buffer gives smoother playback; the cost is spoilers from TV or social media, which you reduce by syncing the scorecard and notifications with the player position.

Cohort ads vs one-to-one targeting

Per-user targeting earns more per impression but cannot be served to 25M people at once from cache. Cohort pods give most of the value with CDN-cacheable playlists. Per-user decisions can still be used at smaller events.

Polling cached JSON vs WebSockets for the scorecard

WebSockets give instant updates but cost millions of persistent connections and are brittle under reconnect storms. Polling a CDN-cached file every few seconds is cheaper, scales with the CDN and fails gracefully.

Bitrate cap vs quality

Capping at 720p or 480p during peaks reduces quality for some viewers but prevents widespread rebuffering when total CDN capacity is short. Make the cap tier-aware and dynamic, not a blanket permanent setting.

9 Bottlenecks

Mass reconnect after a blip

If the app or a CDN glitches for 10 s, millions reconnect at once and the reconnect storm can be bigger than the original peak. Clients use exponential backoff with full jitter, tokens stay valid so reconnects skip login, and the playback API is cheap and cache-backed.

OTP and login during the match

New sign-ups before a big match can exceed SMS provider limits. Push sign-up campaigns days earlier, use multiple SMS providers and WhatsApp OTP, queue requests with a visible wait, and never force existing users to log in again during a match.

Hidden infrastructure limits

Cloud quotas, load balancer warm-up, NAT port exhaustion and database connections fail before CPU does. Find them in load tests and raise them in advance.

10 Failure handling

Primary encoder or feed path fails

Two encoder/packager chains run in two regions with aligned segments. CDNs or players fail over to the secondary origin; viewers see at most a short stall.

A CDN degrades

Real-time QoE dashboards detect it in about a minute; steering shifts new sessions and players switch to alternate URLs. If remaining capacity is not enough, the bitrate cap is lowered.

Entitlement or user database overloaded

Playback tokens are signed and carry plan information, so already-logged-in users keep watching even if the database is slow. New logins are queued; the failure mode is 'wait', not 'kicked out'.

Ad system fails

The packager falls back to a default slate or a house promo during the break. Ad failure must never break the video.

11 What impresses

  • Starts with the egress maths and realises CDN capacity in India is the binding constraint
  • Says autoscaling is too slow and describes pre-scaling, pre-warming and load testing beyond forecast
  • Defines concrete degradation levels in priority order, protecting existing viewers first
  • Solves the synchronous ad break with cohort pods that the CDN can cache
  • Handles reconnect storms with jitter and long-lived tokens
  • Mentions hidden limits: SMS OTP throughput, cloud quotas, connection pools

12 Mistakes

  • Relying on autoscaling for a surge that arrives in seconds
  • Personalising every API response so nothing can be cached
  • Using a single CDN or a single encoder
  • WebSockets to every viewer just for the score
  • Per-user ad decisions at the over break
  • Treating it like general live streaming without discussing the event-day capacity plan

13 Follow-ups

Q1How would you produce a reliable public concurrency number?
Q2How would you add multi-camera angles that users can switch between?
Q3How would you reduce latency to under 10 s without hurting stability?
Q4What is your runbook if total demand exceeds total CDN capacity by 20%?
Q5How would you run a load test that is realistic for 50M users?
Q6How would you stream to smart TVs in 4K for premium users without starving mobile users?

Saved on this device. Create a free account to keep it on every device.

Practise this with Sam

A real mock interview, out loud, with an honest scorecard. Free to start.

Start free