The problem
Every major ad network caps a playable creative at 5 MB, and that's not a soft target. Google Ads enforces it on the ZIP itself (plus a 512-file cap), Mintegral and TikTok enforce it on their ZIP packages, and AppLovin, Meta, Unity Ads, and Vungle enforce it on a single self-contained HTML file with zero external requests. Meta and Unity Ads recommend staying nearer 2 MB, even though 5 MB is the hard number. A build that clears the bar for one network can land over it for another, from the exact same source export — and it happens even when nothing about the conversion looks wrong: the export runs, the click-through fires, the package structure matches spec, it's just heavy. That's because a Playworks/Luna build tends to start large for reasons that have nothing to do with how it's packaged afterward.
Why a Playworks/Luna export runs large in the first place
- Uncompressed source textures and audio. A Unity project accumulates full-resolution PNGs, uncompressed WAV clips, and texture atlases sized for a bigger canvas than a playable ever renders at. None of that shrinks just because it passed through Playworks/Luna — the export carries forward whatever compression the source assets already had.
- Engine and runtime overhead. A Playworks/Luna build embeds Unity's own runtime and bootstrap code alongside your creative assets — a baseline cost that exists before a single image or sound is counted, and part of why a Unity-based playable often starts heavier than a hand-built HTML5 one with equivalent visuals.
- Base64/base122 inflation on an already-large source. AppLovin, Meta, Unity Ads, and Vungle require every asset embedded inline rather than referenced by path. Base64 turns every 3 bytes of source data into 4 bytes of text — roughly 33% overhead — landing on top of assets that may already be heavier than they need to be. A build that's borderline at 4 MB raw can clear 5 MB once encoded for a network that requires it.
- Unnecessary embedded asset variants. Projects built for several aspect ratios, languages, or A/B variants sometimes ship all of them in one export instead of stripping down to what a single playable instance renders. Every unused variant still counts against the same 5 MB ceiling.
Why the raw pre-conversion ZIP size is misleading
It's tempting to check the size of your Playworks/Luna export ZIP and assume that tells you whether you're in trouble. It doesn't, in either direction. The raw export can be smaller than the real converted output, because networks like AppLovin and Meta require base64 embedding that a raw relative-path reference didn't need — the number only grows once conversion happens. It can also be larger, because a raw export often carries multiple cache generations and leftover build artifacts that get dropped during proper conversion and never ship in the final package.
Either way, the number that matters is the size of the final, network-specific, encoded package — not your raw upload. Comparing your ZIP's file size against a network's 5 MB cap and calling it done is a guess, not a measurement.
How to actually measure it
PlayableKit's free Size Checker runs your real Playworks/Luna export through the same conversion pipeline used for paid builds, once per network, and reports the real resulting byte size against each network's real cap — no estimating from the raw upload. It's the only way to know, before you submit anything, whether a specific build passes or fails for Google, Meta, AppLovin, Mintegral, TikTok, Unity Ads, and Vungle individually, since a build can pass for some and fail for others from the same source.
If the build also has a missing entry file or missing engine asset alongside the size problem, that's a separate issue — see Unity Playworks/Luna export missing assets for what causes that.
Fixing it
- Compress source assets before export, not after. No conversion step downstream can shrink an oversized texture or an uncompressed audio clip — that has to happen in the Unity project itself, in the import settings, before Playworks/Luna ever exports it.
- Trim unused assets and variants. Strip textures, audio, and aspect-ratio/language variants that the specific playable instance you're shipping doesn't actually reference. Leftover assets from earlier iterations are a common, easy-to-miss contributor.
- Check per network, not once. Because the 5 MB cap applies differently depending on ZIP vs. single-file packaging and base64 vs. more compact embedding, a build that's fine for Google can still fail for Meta. Run the Size Checker per network rather than assuming one pass/fail applies everywhere.
- Re-check after every asset change. A build that passes today can regress the moment a new texture or audio clip gets added upstream. Treat the size check as a step before every submission, not a one-time gate.
For a deeper look at exactly how base64 inflation, per-network encoding differences, and the 5 MB/2 MB numbers interact, see Playable ad compression and size limits, explained honestly.