Skip to content

FRONTEND SYSTEM DESIGN

Design a Video-streaming frontend

Design the client for a video platform: adaptive playback, buffering resilience, and cross-device continuity.

Video-streaming frontend architecture diagram

THE INTERVIEW SEQUENCE

How to drive this discussion

01

Clarify scope

02

Set requirements

03

Draw data flow

04

Defend trade-offs

Start with the smallest coherent design. After the main path works, introduce failure, scale, accessibility, observability, and release strategy one constraint at a time.

01Concrete scale assumptions

Video-on-demand first; live latency is a separate mode with different buffer targets.

10M daily viewers, 100k concurrent sessions at peak, with CDN delivery for every media byte.

Startup target below 2 seconds on typical broadband; rebuffer ratio below 1% of watch time.

Desktop, mobile, and TV controls share a player contract but may use different native playback capabilities.

02Architecture decisions and rationale

Isolate a player core

The UI consumes a stable state and command API while HLS/DASH, MSE, native playback, DRM, and device quirks remain inside adapters.

Make playback a state machine

Idle, loading, ready, playing, paused, seeking, stalled, ended, and fatal states prevent controls from guessing behavior from scattered events.

Separate critical and adjacent traffic

Manifest and segments have priority over recommendations, artwork, analytics, and prefetch so secondary UI cannot cause rebuffering.

Checkpoint progress asynchronously

Progress writes are coalesced and eventually consistent; playback never blocks on them, while a final lifecycle beacon improves resume accuracy.

03Client contracts and data boundaries

Player boundary

Commands are intents; events are the authoritative playback facts emitted by the adapter.

TypeScript
type PlayerCommand = { type: 'play' | 'pause' } | { type: 'seek'; seconds: number };type PlayerEvent =  | { type: 'ready'; duration: number }  | { type: 'time'; current: number; buffered: number }  | { type: 'quality'; bitrate: number }  | { type: 'stalled' } | { type: 'fatal'; code: string };

04Failure-mode analysis

Segment request fails

Impact: Playback drains its buffer and stalls.

Mitigation: Retry with jitter, switch CDN or rendition, preserve current time, and surface fatal UI only after bounded recovery.

Progress service unavailable

Impact: Cross-device resume becomes stale.

Mitigation: Queue the latest checkpoint locally and retry without delaying playback.

DRM or codec unsupported

Impact: The selected asset cannot start.

Mitigation: Capability-test before selecting a rendition and offer a compatible fallback or explicit error.

UI thread long task

Impact: Controls and captions lag despite healthy media buffering.

Mitigation: Keep player events lightweight, defer adjacent UI, and measure interaction delay separately from media QoE.

05Observability and operations

  • Measure manifest time, time to first frame, rebuffer count/duration, fatal rate, and bitrate switches per device/network cohort.
  • Correlate player session id across client events, CDN requests, and progress writes without logging protected media data.
  • Sample high-volume time events but send every fatal transition and recovery outcome.
  • Canary codec, DRM, and ABR changes behind flags with automatic rollback thresholds.

06Security and accessibility boundaries

  • Use signed short-lived media URLs and enforce entitlement on trusted services; hiding controls is not authorization.
  • Treat subtitle and metadata payloads as untrusted and parse without HTML injection.
  • Provide keyboard-operable controls, visible focus, captions, audio-track selection, and non-color state indicators.
  • Honor reduced motion and never let autoplay with sound bypass user-agent policy or user preference.

ANSOne full answer, start to finish

Drive the discussion yourself first. This is one strong answer delivered the way you would say it in the room — a model, not the only correct design.

This answer goes wrong when you open with 'I'd use HLS'. Do it in order: pin down what kind of video and what 'good' means, draw a small number of boxes, then spend most of the time on the one genuinely hard part — keeping playback smooth when the network wobbles — and only then talk about failure and scale. Here is that walk, in the words you would actually use.

  1. Step 1 · Clarify what you are building

    Say: 'Before I design anything, a few questions. Is this video-on-demand, live, or both? Roughly how many concurrent viewers at peak? Which devices — just web, or also mobile and TV? And what is the bar for good: startup time, how often it is allowed to buffer?' Then state your assumptions so they can correct you: 'I will assume on-demand first, about 100,000 concurrent viewers at peak, web and mobile, startup under two seconds, buffering under one percent of watch time.' Two minutes here stops you designing the wrong thing.

  2. Step 2 · Turn that into requirements

    Split into what the user sees and what shapes the design underneath. User-facing: play, pause, seek, choose quality, pick captions and audio track, and resume where you left off on any device. Underneath: adaptive quality so it does not buffer, recover from a failed chunk without a hard error, and never let the recommendations rail or analytics slow the player. Write these where the interviewer can see them.

  3. Step 3 · Draw the boxes, keep it small

    Four boxes. One: a player core that wraps the messy parts — the streaming format like HLS or DASH, the browser Media Source API, DRM, device quirks — behind a clean 'commands in, events out' interface. Two: a thin UI shell (controls, overlays, recommendations) that only reacts to the player's state events and never touches the video element directly. Three: a CDN that serves every video byte. Four: a small watch-progress service the client checkpoints to periodically. Say why the core is isolated: 'so device and format complexity live in one place, and I can swap the playback engine without rewriting the controls.'

  4. Step 4 · Deep-dive: adaptive bitrate, the actual hard part

    Spend the most time here. 'The client fetches a manifest that lists the video at several quality levels, each cut into short segments. Before each segment, an algorithm on the client picks a quality from two signals: how fast recent downloads have been, and how much buffer is left. If the buffer is draining it steps down; if it is healthy and the network looks good it steps up — but conservatively, because viewers hate quality that flip-flops every few seconds more than they mind a slightly lower resolution.'

  5. Step 5 · Failure: a segment does not load

    'If a segment request fails I do not show an error straight away. I retry with a little random delay, and if it keeps failing I try a different CDN or drop to a lower quality that might arrive in time — all while keeping the current playback position. Only after a bounded number of failed recovery attempts do I show a real error. And progress writes never block playback: if that service is down I keep the latest position locally and retry later.'

  6. Step 6 · Scale and the main-thread trap

    'The scaling insight is that the video bytes go to the CDN, not my servers — my application servers only handle manifests, entitlement, metadata, and progress, which is a tiny fraction of the bytes. The other thing I watch is the main thread: if the UI does heavy work the controls and captions lag even when the video buffer is fine, so I keep the player's event handling lightweight and defer the recommendations and analytics.'

  7. Step 7 · Name what you would measure

    'I would track time to first frame, how often and how long it rebuffers, the fatal-error rate, and the number of quality switches — all split by device and network type, because a problem on slow mobile hides in an average. Every fatal error and recovery is logged; the routine time-update events are sampled.'

How to close

'To sum up: on-demand, web and mobile, 100k concurrent, two-second startup bar. The design is a player core that hides format and device complexity behind commands and events, a thin UI that only reacts to player state, a CDN for all media bytes, and an async progress service. The hard part is adaptive bitrate — pick quality per segment from throughput and buffer health, switch conservatively. Failures recover in the background and keep the position before ever showing an error. The first metric I would watch after launch is rebuffer ratio by network cohort.' Then stop and let them ask.

QAInterview questions and model answers

It contains device and protocol complexity behind one contract, lets UI state follow authoritative events, and permits adapter replacement without rewriting controls.

Primary references

DESIGN CHECKLIST

Build your answer from first principles

Use this checklist to rehearse the case without reading the worked answer above.

CLARIFYING QUESTIONS

Do not design yet. Use these questions to make hidden assumptions explicit and prevent solving the wrong problem.

  1. 01

    Live streaming, video-on-demand, or both?

  2. 02

    What device classes must be supported (TV, mobile, low-end Android, desktop)?

  3. 03

    Is offline download/playback in scope?

  4. 04

    What's the acceptable startup latency and rebuffering budget?

FUNCTIONAL REQUIREMENTS

These are the user-visible capabilities the design must support. They define the first version's scope.

  1. 01

    Play video with adaptive bitrate switching based on network conditions.

  2. 02

    Resume playback position across sessions and devices.

  3. 03

    Support captions/subtitles and multiple audio tracks.

  4. 04

    Surface recommendations and search without blocking playback of the current video.

NON-FUNCTIONAL REQUIREMENTS

These qualities shape the architecture even though users do not click them directly: latency, resilience, accessibility, consistency, and scale.

  1. 01

    Fast startup: first frame should render well under a few seconds on typical connections.

  2. 02

    Resilience to network drops without a full player crash.

  3. 03

    Consistent experience across a wide range of device performance tiers.

ARCHITECTURE

Now assign responsibilities to clear boundaries. Each part should have one reason to change and an explicit contract with the next part.

  1. 01

    A player core wrapping HLS/DASH playback (via Media Source Extensions or a native player on constrained platforms), isolated behind a stable internal API from the rest of the UI.

  2. 02

    A thin UI shell (controls, overlays, recommendations rail) that reacts to player state events rather than driving the player imperatively from many places.

  3. 03

    A telemetry pipe that beacons startup time, rebuffer events, and bitrate switches for both product and reliability monitoring.

  4. 04

    A watch-progress service synced periodically (and on pause/unload) so resume position is available across devices.

DATA FLOW

Trace one important user action from input to rendered result. This exposes ownership, race conditions, retries, and stale-data paths.

  1. 01

    Client requests a manifest describing available quality renditions and segment URLs.

  2. 02

    An adaptive bitrate algorithm on the client picks a rendition per segment based on measured throughput and buffer health.

  3. 03

    Playback position is checkpointed to a backend service on an interval and on key lifecycle events (pause, backgrounding, unload).

  4. 04

    On load, the client fetches last known position from that service to offer 'resume where you left off.'

TRADE-OFFS

There is no perfect architecture. State what each choice optimizes, what it costs, and the signal that would make you revisit it.

  1. 01

    Aggressive upfront buffering reduces mid-playback rebuffering but increases startup latency and wasted bandwidth if the user abandons quickly.

  2. 02

    Client-driven ABR is simpler to ship but reacts slower to sudden network changes than a server-assisted approach; the complexity cost has to be justified by measured rebuffer rates.

  3. 03

    Preloading recommendations/thumbnails improves perceived next-video speed but competes with the current video for bandwidth on constrained connections.

SCALING

Scale the measured bottleneck rather than every box. Frontend scaling includes payload size, main-thread time, rendering work, cacheability, and release safety.

  1. 01

    Push segment delivery to a CDN; the app server never serves video bytes directly.

  2. 02

    Keep the watch-progress write path cheap and eventually consistent — losing a few seconds of resume accuracy is acceptable, blocking playback on it is not.

  3. 03

    Feature-flag new player behavior (new ABR heuristic, new codec) and roll out gradually while watching rebuffer/error telemetry.

COMMON PITFALLS

Interviewers often probe these failure modes. Name them before being prompted and explain the guardrail you would add.

  1. 01

    Treating the player as a black box with no exposed state, forcing the UI to guess playback state from timers instead of real events.

  2. 02

    Blocking the play button on non-essential requests (analytics, recommendations) that have nothing to do with starting playback.

  3. 03

    Not distinguishing a genuine network failure from a temporary rebuffer, leading to premature error UI during normal adaptive behavior.

Your closing summary

Restate the critical user flow, the most important quality target, the architecture boundary that protects it, and the trade-off you accepted. Then name the first metric you would watch after launch.

Back to all cases →