Why two formats exist in the first place

Every playable ad ends up running inside a mobile app's WebView, but ad networks disagree on how that WebView is allowed to fetch content. Some networks assume the sandboxed environment on the receiving end might block, delay, or simply never see a second network request after the initial load — so they require the entire creative, every image, audio clip, and font included, to already be sitting inside one HTML document as embedded data. No separate files, no relative paths, no <img src="assets/logo.png"> — just one document that's fully self-sufficient the instant it's parsed.

Other networks are comfortable with a structured package instead: a ZIP archive containing an entry HTML file plus a folder of loose assets referenced by ordinary relative paths, unpacked and served together by their own ad-serving infrastructure. That's a materially easier format to build for, but it comes with its own packaging rules about file naming, folder structure, and file count that a single HTML file simply doesn't have to worry about.

Neither format is "the standard" — they're two different answers to the same constraint, and a Unity Playworks/Luna export is naturally shaped like whichever one you built it for. Shipping that same export unmodified to a network expecting the other format is one of the most common reasons a playable fails silently instead of failing loudly.

Which networks require which format

This is sourced directly from each network's actual packaging spec, not a general rule of thumb — and the split isn't 50/50:

NetworkRequired formatEntry fileExternal requests
AppLovinSingle self-contained HTMLapplovin.htmlProhibited
Meta (Facebook)Single self-contained HTMLmeta.htmlProhibited
Unity AdsSingle self-contained HTMLunity.htmlProhibited
Vungle (Liftoff)Single self-contained HTMLvungle.htmlProhibited
Google AdsZIP (≤512 files)index.htmlGoogle-hosted libraries only
MintegralZIP (archive/folder/HTML names must match)mintegral/mintegral.htmlLocal ZIP resources allowed
TikTokZIP (first-level config.json required)index.htmlProhibited

Four networks — AppLovin, Meta, Unity Ads, and Vungle — flatly require a single file with a hard cap of one, with a maximum file count of 1 baked into the spec itself. Google Ads and Mintegral accept a ZIP and explicitly allow local resource files inside it. TikTok is the outlier worth calling out on its own: it requires a ZIP for its config.json/index.html structure, but it still prohibits external requests and dynamic loading at runtime — so a TikTok package looks like a ZIP from the outside, but the assets inside still need to behave like a closed, self-sufficient bundle rather than something that fetches or redirects externally at play time.

What single-file format actually costs you

Building for AppLovin, Meta, Unity Ads, or Vungle means every asset the playable uses — sprites, sound effects, background music, custom fonts — has to be converted into a base64 or base122 data URI and embedded directly in the HTML, decoded by JavaScript at load time instead of fetched by the browser. That has two direct consequences. First, base64 encoding inflates binary data by roughly a third over its raw size, so a build that comfortably fits under a 5 MB cap as separate files can blow past that same cap once every asset is embedded — which is exactly why Meta and Unity Ads separately recommend staying closer to 2 MB rather than the hard limit. Second, there's no partial loading: the entire file has to parse before anything renders, so heavier creatives feel slower to open even before any interaction happens.

What ZIP format actually costs you

Google Ads, Mintegral, and TikTok trade that inlining tax for a different set of structural rules. A ZIP is more forgiving on asset size — no base64 inflation, and files can be referenced by ordinary relative paths — but each network adds its own packaging constraints that a flat single-file build never has to satisfy. Google caps the archive at 512 files and expects a proper DOCTYPE, orientation meta tag, and index.html in the right place. Mintegral requires the archive's file name, its top-level folder name, and the HTML file inside it to all match exactly — a naming rule that has nothing to do with how the creative plays and everything to do with how Mintegral's ingestion pipeline unpacks the file. TikTok requires a first-level config.json declaring orientation plus its own Playable-sdk.js, and won't accept the MRAID click pattern the single-file networks rely on. Miss any one of these and the ZIP itself gets rejected before the creative is even evaluated.

How PlayableKit handles this automatically

PlayableKit reads which output shape each selected network requires and produces it from the same source Playworks/Luna export — no manual re-authoring per format. For AppLovin, Meta, Unity Ads, and Vungle, it inlines every asset as an embedded data URI and compresses to stay under that network's byte cap. For Google Ads and Mintegral, it keeps assets as local files and builds the ZIP with the correct file count, folder layout, and naming match. For TikTok, it generates the config.json, places index.html correctly, and bundles the Playable SDK so the archive still behaves as a closed, self-contained package despite being delivered as a ZIP. One upload, the correct shape per network, every time.

Worth knowing: for the full technical breakdown of what changes inside the file itself — click-through APIs, orientation handling, and asset encoding beyond just the format question — see the HTML5 playable converter page.