Hacking Hollywood's HTML5: A Netflix iPad App Analysis

Intended Audience: Web Developers

Estimated Reading Time: 15 minutes

How does Netflix actually build their iPad app? I decided to find out by intercepting every network request and reverse-engineering their HTML5 codebase. What I found was a masterclass in hybrid app architecture — and a lesson I wish I'd learned sooner.

The Setup

I was working as a software engineer at Match.com, building the mobile web app. Netflix fascinated me — they delivered streaming video across dozens of device types, from smart TVs to phones to tablets. The iPad app in particular had a reputation for polish. I wanted to understand how it worked.

The architecture question: was this a native app, an HTML5 app, or something in between? The answer would reveal how one of the most sophisticated engineering teams in the industry approached mobile.

The Problem: Everything Is Encrypted

To inspect network traffic, I used Fiddler — Eric Lawrence's free proxy tool that intercepts HTTP requests between a device and the internet. Point your iPad's proxy settings at your development machine, and every request flows through Fiddler's inspector.

Except Netflix encrypts everything with HTTPS. Fiddler saw only SSL tunnels — the requests were there, but their contents were opaque.

The Workaround: A Vintage iPad

Modern iOS devices are strict about SSL certificates. But I had a vintage original iPad running iOS 5.1.1 — the last version that device ever received. Older iOS was more permissive about trusted root certificates.

I installed Fiddler as a trusted root certificate authority on the iPad. This enabled full man-in-the-middle SSL decryption — Fiddler could now read every request and response as if there were no encryption at all.

This is exactly the kind of thing that should raise red flags in a security context. I wasn't attacking anyone; I was satisfying my own curiosity about architecture. But the technique itself is worth understanding — if your app's security depends solely on SSL, a determined observer with device access can still see everything.

What the Network Revealed

With traffic decrypted, the hybrid architecture became immediately visible. Two User-Agent strings appeared in the requests: the Netflix native app UA and Mobile Safari (UIWebView). The native shell handled video playback and DRM. Everything else — the UI, the browsing experience, the profile selection — was HTML5 running in an embedded web view.

Third-party services appeared first. Before any Netflix content loaded, the app hit Urban Airship (push notifications, device analytics) and Crittercism (mobile app performance monitoring). These services saw the device before Netflix did.

API structure was clean. After authentication, the app requested profiles, then movie lists (Continue Watching, Popular, Top Picks, Because You Watched), then individual list details. Box art images came from Netflix's CDN, 10-20KB each.

Adaptive bitrate streaming was elegant. Video playback happened outside the HTML5 layer entirely, hitting complex subdomains on nflxvideo.net. The stream used inverse multiplexing — separate AAC audio requests interleaved with video chunks. Initial chunks were small (80-237KB), gradually scaling up to 2MB+ as the client assessed connection quality. This explained the low-def to hi-def transition visible when starting playback.

DRM was per-chunk. Thousands of individual requests, each with a separate random encryption key. Every few seconds of video was encrypted differently per authorized user. Even if you intercepted the stream, reassembling it without the keys would be impractical.

The HTML5 UI Deep Dive

With the network layer understood, I turned to the actual HTML, CSS, and JavaScript.

index.html: The Bootstrap

The HTML was minimal — mostly empty elements with specific IDs for JavaScript to populate. It was bootstrapping and UI hooks, not content. Many A/B test features were visible that I wasn't in the test group for: social connect features, an elaborate Netflix Kids tablet interface.

One element kept appearing: squid_overlay. What was squid?

presentation.css: Webkit-Only

The CSS contained 708 -webkit- prefixed properties. Zero references to Mozilla, Microsoft, or Opera. This wasn't a cross-browser stylesheet — it was entirely WebKit-targeted, implying Netflix had separate client codebases per platform team.

The scrolling was handled with -webkit-overflow-scrolling: touch — a Mobile Safari-specific property for momentum scrolling on movie lists.

The animations were extensive: keyframes named targetPlaybackHeaderPulse, wiggle, fade, wobble, spin. Hardware-accelerated UI polish, all CSS3.

More squid references appeared: squid-path, squid-spin, squid-loop animations, and references to a sprite sheet on Netflix's CDN.

behavior.js: 60,000 Lines of Custom JavaScript

The JavaScript file was 1,100+ KB minified. Too large for jsbeautifier.org — it crashed my browser.

I forked a C# JavaScript Beautifier project on GitHub and added a command-line utility to handle the file. The beautified result: 2,100+ KB, 60,000+ lines of JavaScript.

What I found inside:

No frameworks. No jQuery, no Zepto, no Ember, no Angular. Netflix had built an entirely custom internal stack.

Extensive logging. Custom logging infrastructure with hooks to CI tools — consistent with Netflix's DevOps philosophy.

localStorage Device Bridge. An abstraction layer for persisting state across sessions.

DOM prototype extensions. Custom data binding by extending native DOM objects.

A/B testing facade. Methods to check participation in each possible test — the same tests visible in the HTML.

Reactive Extensions (RxJS). One of the earlier production uses of reactive programming I'd seen in a major consumer app.

Custom debug module. Rewrote the viewport meta tag for pinch/zoom, serialized DOM and memory objects, added a pixel-measuring "ruler" for UI troubleshooting. This was a team that had built serious internal tooling.

The Squid revealed. Triggered from the JustForKidsCard controller — the squid was the Netflix Kids mascot. A TV-headed squid character with tentacles, loaded from a sprite sheet and animated with CSS. The mystery threaded through all three file types finally paid off.

The Interview I Should Have Done This For

Here's the part I didn't include in the original talk.

Before I did any of this reverse-engineering, I interviewed at Netflix. Full-day onsite for a position on their iPad team — the very team whose code I later dissected. I got through the first half of the day, roughly four hours of technical interviews. I didn't advance to the executives.

The take-home assignment was the stumbling block. I over-emphasized .NET technologies — ASP.NET MVC 3 — rather than demonstrating fluency in the stack Netflix actually used.

The irony is obvious now. If I had done this reverse-engineering work before the interview instead of after, it would have been a completely different conversation. I would have walked in knowing their hybrid architecture, their RxJS usage, their custom internal framework with no jQuery or Angular, their localStorage Device Bridge abstraction, their A/B testing facade pattern, their CSS animation approach, and what the squid was.

Instead, I showed up leading with my strongest hand — .NET — rather than speaking their language.

A second irony: I had been ambivalent about the role going in. Two visits to the Netflix campus, and it wasn't until four hours into the onsite that the ambivalence evaporated and I actually wanted the offer. The wanting arrived at the same moment the opportunity was slipping away.

Lessons

Preparation is respect. Deeply understanding a company's technical choices before interviewing shows you care about their problems, not just your own skills. This talk demonstrates exactly the kind of curiosity Netflix would have valued — just delivered too late.

Hybrid apps were real. The "native vs. HTML5" debate of that era missed the point. Netflix built both — native video playback with DRM, HTML5 for everything else. The architecture let them iterate on UI without App Store review cycles.

Custom stacks exist for reasons. No jQuery, no Angular — Netflix built their own framework. At their scale, the tradeoffs are different. They needed logging, A/B testing, and debugging infrastructure that off-the-shelf frameworks didn't provide.

The squid is always worth finding. Every codebase has a squid — some detail that threads through multiple layers and finally makes sense when you've seen enough. The detective work is its own reward.

Code

The C# JavaScript Beautifier fork is on my GitHub: mikerandrup

Back to Home