Design a YouTube Mobile Client
Getting video to start fast and never stall — on a billion phones, across every network from fiber to one flickering bar.
Getting video to start fast and never stall — on a billion phones, across every network from fiber to one flickering bar.
Scope and API (§1–2) frame a consumption-only client; the architecture (§3) makes clear the CDN does the heavy lifting. The deep dives are the substance: adaptive streaming that survives changing networks (§4), intelligent feed prefetching (§5), and mobile-native player touches (§6). Anything marked [+] is context added beyond the source chapter; the rest is a rewrite. Diagrams are original.
Consumption, not creation#
The first scoping call narrows an enormous product to something tractable: video consumption only — browsing and playback. No uploads, no live streaming, no likes/comments/playlists. And crucially, playback rides an existing adaptive protocol (HLS or DASH) rather than one built from scratch.
Functional requirements#
- Browse recommended videos in a home feed.
- Watch with a feature-rich player: play/pause/seek, quality (360p, 720p…), subtitles, alternate audio.
- Prefetch feed data so content appears instantly.
Non-functional requirements#
- Scalability — ~1 billion daily active users, every network from fast Wi-Fi to spotty cellular.
- Performance — smooth scrolling and playback, efficient delivery across device types.
- Availability — uninterrupted access, multi-language, global.
The Home screen (tailored recommendations) and the Video Player screen (the selected video with controls). Everything below serves one of these two.
An API that fetches only what it needs#
Client-server calls use REST over HTTP with JSON — simple, universally supported. At this scale, gRPC with Protocol Buffers would serialize more compactly, but REST is chosen for familiarity. The design borrows from the real YouTube Data API, which has one instructive twist.
part parameter — GraphQL's benefit without GraphQL
A Video resource is heavy: metadata, view counts, content restrictions, playback info. No mobile screen
needs all of it. The part parameter lets the client name which field groups it wants —
snippet for titles/thumbnails, statistics for view counts — so responses carry
only what's used. [+] It's coarser than GraphQL's field-by-field selection (you
pick from predefined sets, not arbitrary fields), but it kills over-fetching with none of GraphQL's added
complexity — and on mobile, every byte counts.
The endpoints#
- Popular feed (signed-out home): GET
/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=20®ionCode=US - Video details (on tap): GET
/youtube/v3/videos?id=VIDEO_ID&part=snippet,player,contentDetails,statistics— metadata, playback info, and engagement in one call. - Playback: GET
…/videos/playback?codecs=…&protocols=…&language=…&subtitles=…→ a streaming manifest (DASH or HLS) tailored to the device, plus subtitle options.
Third-party apps must use YouTube's IFrame Player API, but as YouTube's own client, this app feeds manifests straight to the platform's native video player. [+] A manifest is a small text file listing the available quality renditions and the URLs of each media segment — the map the player reads to stream adaptively.
The client and the CDN behind it#
Same layered client as the other case studies, but with one component doing outsized work: the CDN. Video bytes never come from the origin — they come from a cache node near the user. The API Gateway and Backend handle metadata and routing; the CDN handles the streams and thumbnails.
CDNs cut latency (content from a nearby node, not a distant origin), absorb load (millions streaming the same video hit many edge servers, not one), and cut cost (fewer trips to origin). But at scale the CDN bill itself becomes huge — so Netflix built its own, Open Connect, and others place servers directly inside ISP networks to cut delivery cost and improve quality.
The client's data layer runs Browsing, Video, and History repositories, each with a remote source over the Network Dispatcher. Prefetching adds more components later.
Streaming that adapts to the network#
Streaming is not downloading. Instead of waiting for a whole file, the player pulls the video in small segments: playback starts after the first few arrive, more load in the background, played segments are freed, and — the key part — quality adjusts to the connection. That model suits mobile perfectly: low memory, any length, resilient to changing networks.
The protocols#
| Protocol | What it is | Fit |
|---|---|---|
| HLS ✓ | Apple's HTTP chunked streaming; WebVTT subtitle tracks in the .m3u8 playlist. | Ubiquitous, strong on Apple; supports adaptive bitrate. |
| DASH ✓ | Open standard, codec-agnostic; WebVTT/TTML tracks in the .mpd manifest. | Flexible; strong outside Apple; supports adaptive bitrate. |
| CMAF | A unified container that lets one set of segments serve both HLS and DASH. | Cuts storage and duplication. |
| WebRTC · SRT · RTSP · RTMP | Real-time / low-latency / legacy protocols. | Conferencing, ingest, older systems — not the main VOD path. |
HLS and DASH lead for apps like YouTube, Twitch, and Netflix; both do adaptive bitrate streaming, with low-latency variants (LL-HLS, LL-DASH) when delay matters. Most platforms ship several — YouTube supports HLS, DASH, RTMP, and RTMPS so clients can pick.
You don't need the low-level protocol internals. What matters: different protocols support different formats and players, and that shapes your architecture choices.
How adaptive bitrate works#
Each video is encoded at several qualities (480p / 720p / 1080p), every quality is split into the same short segments (2–10s), and the player picks a quality per upcoming segment based on live conditions. Because each choice only affects the next segment, the system reacts immediately.
The player decides using download speed, buffer level, and CPU/GPU — in practice a buffer-based or hybrid algorithm. [+] On device, use the native players: ExoPlayer (Android) and AVPlayer (iOS) — they handle HLS/DASH with hardware decoding and deep platform integration.
HLS and DASH keep video, audio, and text as independent, time-synced streams. That cuts bandwidth (text is tiny), enables multi-language without duplicating video, meets accessibility needs, and lets captions update without re-encoding video.
Two approaches. Sprite sheets pack many thumbnails into one image (fewer requests, but you pre-generate and store extra assets). Adaptive low-res frames — YouTube mobile's choice — reuse the streaming stack to fetch actual 144p/240p frames at the scrubbed timestamp: real motion, no extra storage, accurate previews.
Memory: adaptive buffer sizing, frame recycling, degrade under pressure, release on background. Battery: lower quality on low battery, hardware decode, pause/suspend when hidden (Android Battery Saver API, iOS low-power notifications). Network: bandwidth adaptation, retries with exponential backoff + jitter [+] (randomized delay so retries don't thundering-herd), pre-download on Wi-Fi, connection-aware buffering. Advanced: prioritize audio continuity, predictive buffering, cache subtitle tracks.
Reddit customized ExoPlayer for short videos (MP4 under 45s, tuned caching/buffering), cutting load times and rebuffering. Netflix uses shot-based encoding for better 4K at lower bitrate, a Unicode subtitle pipeline, and studio-quality audio work.
Prefetching the feed intelligently#
Users expect the feed to be there the instant they open the app. Prefetching loads feed data ahead of time — but it spends network, battery, and memory, so when to prefetch is the whole game.
| Strategy | Trigger | Trade-off |
|---|---|---|
| Time-based | Fetch on a fixed interval. | Simple, predictable; wastes data, ignores behavior. |
| Event-based | Fetch on app foreground/background. | Aligns with usage; may miss optimal moments. |
| Intelligent ✓ | Combine device state, usage patterns, relevance, resources. | Best UX and efficiency; most complex, needs tuning + monitoring. |
At a billion users with rich signals, decide from the client using device state (charging, network type), user patterns (typical open times), content relevance, and resources (battery). A remote configuration system [+] lets the backend tune client behavior — how much to prefetch, the interval, whether cellular is allowed — without an app update.
The backend scores each recommendation with a relevanceScore (0–100, how well it matches the user)
and a ttl (how long it stays valid). Scores aren't static — when preferences shift, the backend
updates them and the client refreshes its cache.
A background scheduler runs it — Android's WorkManager (built-in Wi-Fi/charging constraints),
iOS's Background Tasks framework (earliestBeginDate plus your own condition
checks). Both may delay or batch tasks, so the implementation must handle that gracefully. A feedback loop then
adapts: prefetch more during high engagement, pause during quiet periods.
Restrict to Wi-Fi by default (opt-in cellular), pause under ~20% battery, do less on low-end devices, cap the cache and downsample thumbnails, clear on memory pressure. Then prove it works: track time-to-first-recommendation, engagement with prefetched vs not, percentage of prefetched videos actually watched, and bytes prefetched but never viewed — the clearest measure of waste.
Facebook's app watches an in-memory pool of videos as you scroll; when it drops below a threshold, it fetches and ranks fresh personalized candidates with user signals, then caches them for smooth playback.
Player experiences built for mobile#
A common follow-up: how do you make the player feel native? Three features, meant to work as one system.
Gesture controls#
Buttons and sliders feel clunky on a small screen. Direct gestures — swipe to seek, vertical drags for volume and brightness — feel immersive. Three pieces: a GestureDetector interprets touch (swipe/tap/pinch), a VideoControlHandler turns gestures into player commands, and visual feedback confirms what happened. The hard parts are disambiguating similar gestures, resolving overlaps, and accessibility for users who can't perform them.
Background audio#
Music, podcasts, and news are valuable audio-only. On backgrounding: listen for lifecycle events, release video rendering while keeping audio, and switch to audio-only streams to save data. Android uses a foreground service with a media notification (Jetpack Media3); iOS uses AVAudioSession with the right category. Respect preferences — an on/off toggle, cellular audio-only mode, and often a premium-only gate.
Picture-in-Picture#
PiP floats the video in a small window while the user does other things. Native APIs: iOS
AVPictureInPictureController, Android enterPictureInPictureMode. Optimize it:
auto-enter on home/app-switch, simplify controls to play/pause/close, drop quality to save bandwidth, pause
non-essential work, and restore exact state on return.
Gestures should behave the same full-screen or in PiP; switching to background audio must preserve playback position so the user resumes seamlessly. The value is in the unified experience, not the three features in isolation.
Recap#
part parameterField-group selection kills over-fetching without
GraphQL's complexity.A streaming client's whole job is continuous adaptation to conditions it doesn't control — the network, the battery, the device. Adaptive bitrate adapts quality to bandwidth per segment; intelligent prefetch adapts fetching to device state; the player adapts buffers and decoders to what's available. Nothing is fixed up front; everything is a decision made fresh, moment to moment, to keep the video playing.
Further reading#
All 37 links below were fetched and confirmed live on 24 August 2026, grouped by topic.
Scale & APIs
- YouTube demographicsThe 2.5-billion-user, 80+-language scale that motivates the design.
- YouTube statisticsMobile's 70%+ share of watch time — why the mobile experience is the priority.
- YouTube Data API — videosThe real API behind §2, including the
partparameter. - Video resource definitionThe rich metadata model that field selection trims down.
- YouTube IFrame Player APIWhat third-party clients must use — and what the internal client bypasses.
- YouTube ingestion protocol comparisonRTMP/RTMPS/HLS/DASH compared — why platforms support several.
Streaming protocols & ABR
- Netflix Open ConnectNetflix's own CDN — the "build your own delivery" strategy.
- HLSApple's chunked-over-HTTPS protocol.
- DASHThe codec-agnostic open-standard counterpart.
- CMAFThe unified container that lets one set of segments serve HLS and DASH.
- WebRTCUltra-low-latency, conferencing-oriented — the real-time end of the spectrum.
- SRTSecure reliable transport, often used at ingest.
- RTSPAn older real-time control protocol.
- RTMPThe legacy Flash-era ingest protocol still used for live.
- Streaming protocols, how to chooseA practical protocol-selection guide.
- Streaming protocols explainedA broad protocol survey with latency/security trade-offs.
- Adaptive bitrate streamingThe core technique behind §4's Figure 2.
Players, thumbnails & optimization
- ExoPlayer (Media3)Android's native adaptive player.
- AVPlayeriOS's native player.
- Texture atlasThe sprite-sheet concept for packed seek thumbnails.
- Sprite sheets for previewsA how-to on the sprite-sheet thumbnail approach.
- Reddit — improving ExoPlayer playbackA deep, metric-driven account of caching, buffering, and prefetch tuning.
- Netflix — shot-based 4K encodesBetter quality at lower bitrate via per-shot encoding.
- Netflix — timed text pipelineScalable subtitle/caption processing across languages.
- Netflix — high-quality audioDelivering studio-quality audio to viewers.
Prefetch, background & PiP
- Android WorkManagerConstraint-aware background scheduling for prefetch.
- iOS Background TasksThe iOS side of background prefetch scheduling.
- Inside Facebook's video deliveryThe scroll-triggered, pool-based prefetch model from §5.
- Facebook Feed recommendationsHow relevance scoring ranks feed content.
- Android foreground servicesKeeping background audio playback alive.
- Jetpack Media3The modern Android media APIs for playback and notifications.
- AVAudioSessioniOS background-audio configuration.
- Picture-in-PictureThe PiP concept.
- AVPictureInPictureControlleriOS PiP API.
- Android Picture-in-PictureAndroid PiP API.
- Live streamingBackground for the wrap-up's live extension.
- PlaylistBackground for the wrap-up's playlist extension.