Why playables matter in Google Ads app campaigns
Google App campaigns don't let you target individual placements or pick which creative shows where — you upload assets (including HTML5 playables) and Google's automation decides the combination and the surface. Within that system, playables are one of the highest-signal asset types you can supply. A static image or short video tells a user what your app does; a playable lets them do it, for a few seconds, before ever installing. That pre-install interaction is what tends to produce stronger install-intent signal and, in practice, better cost-per-install and post-install retention than image or video creative alone, particularly for game apps.
Because App campaigns are automated, there's no manual QA step where a human reviewer flags a malformed playable before it goes live — the packaging rules are enforced mechanically at upload, and a creative that fails them simply doesn't serve. That makes "does this ZIP meet Google's spec" a binary, checkable question rather than a judgment call, which is exactly why the requirements below are worth getting precise about.
Technical requirements
This is the complete set of rules Google checks a playable ZIP against on upload:
| Requirement | Rule |
|---|---|
| Output type | ZIP archive |
| Max ZIP size | 5 MB |
| Max files in ZIP | 512 |
| Entry file | index.html, at the root of the archive |
| Document structure | Valid <!DOCTYPE> declaration plus proper <html> and <body> tags |
| Orientation | An orientation <meta> tag declaring the intended device orientation |
| Asset references | Local relative paths inside the ZIP, plus a short Google-approved external allow-list (below) |
| Click-through | A clickTag variable, exited via ExitApi.exit() |
| Audio | Must remain muted until the user has interacted with the creative |
Every one of these is checked programmatically, not editorially — there's no reviewer who'll wave through a ZIP that's 511KB over the limit because the creative is otherwise strong. Miss one line item and the upload is rejected outright.
The external-asset allow-list
Google is more permissive here than most networks: it doesn't require every asset to be inlined as base64. Local relative paths are fine, and on top of that, Google specifically permits a small list of externally hosted resources:
- Google's own exit API script —
https://tpc.googlesyndication.com/pagead/gadgets/html5/api/exitapi.js - Google Fonts
- Google-hosted jQuery, CreateJS, or GreenSock (GSAP)
Anything else that's externally hosted — a CDN font, a third-party analytics snippet, an arbitrary library pulled from a public CDN — is not on the allow-list, and referencing it puts the whole upload at risk even though the creative would render correctly for you locally.
Accepted formats and size limits
Google accepts exactly one packaging shape for HTML5 playables: a ZIP archive, capped at 5 MB and 512 files, with index.html as the root entry point. There's no separate single-file HTML option the way AppLovin or Meta offer — the ZIP container is mandatory, and it's also the mechanism Google uses to enforce the file-count ceiling, since a single HTML file trivially satisfies it.
In practice, the 5 MB ceiling is rarely the binding constraint on a well-built creative — it's the 512-file count that catches people off guard. A Unity export that bundles its runtime, individual texture files, and per-frame audio assets can rack up file count fast even while staying well under the byte limit. Both limits are enforced together, so a ZIP has to clear both, not just one.
Common upload errors
Most Google playable rejections trace back to a small set of recurring mistakes:
- Missing or broken
clickTag. Google's click-through model isclickTagplusExitApi.exit()— a convention carried over from Google's display-ad ecosystem. A playable with noclickTagvariable, or one that never callsExitApi.exit(), has no functioning click-through and gets flagged. - Referencing assets by relative path to something outside the ZIP and outside the allow-list. A relative path to a file inside the archive is fine. A path or URL pointing at an external CDN, a self-hosted asset server, or any library not on Google's three-item allow-list is not — even if it loads perfectly in a browser during local testing.
- Missing orientation meta tag. Google requires an explicit orientation declaration in the document head. Exports that were never built with a specific network in mind commonly leave this out entirely.
- Exceeding 512 files in the ZIP. This one is easy to miss because it has nothing to do with total size — a ZIP well under 5 MB can still fail if it's carrying more than 512 individual files, which happens routinely with engine exports that don't bundle or atlas their assets.
- Audio that autoplays with sound before interaction. Google requires creatives to stay muted until the user engages with them; an export that plays sound immediately on load — normal behavior for a standalone app — violates this the moment it's dropped into an ad surface unmodified.
- Missing DOCTYPE or malformed HTML structure. A missing
<!DOCTYPE>, or a document that never properly opens<html>/<body>, fails the structural check independent of everything else being correct.
Best practices
- Check size and file count before you upload, not after rejection. A quick automated check catches the 512-file problem long before Google's upload flow does.
- Keep the first frame interactive-looking, even before load completes. Google's automated placements can surface a playable in contexts where a slow first paint reads as a broken ad.
- Test the exit call in isolation. Confirm
ExitApi.exit()actually fires and readsclickTagcorrectly — a silently broken click-through won't throw an error, it'll just never convert. - Don't assume other networks' rules carry over. A build that's correctly self-contained for AppLovin or Meta (everything inlined, zero external requests) is still missing Google's specific
clickTag/ExitApiwiring and orientation meta tag — the two rule sets solve different problems and neither is a superset of the other. - Re-check after every asset change. Adding one more texture or sound effect late in production is a common way a previously-compliant build quietly crosses the 512-file or 5 MB line.
Exporting a Google-ready package with PlayableKit
If your playable started life as a Unity Playworks/Luna export, none of the above is handled automatically by Unity's exporter — it produces a generic HTML5 build, not a Google-specific one. PlayableKit takes that same export and adds the clickTag/ExitApi.exit() wiring, orientation meta tag, muted-audio gating, and DOCTYPE/html/body structure, then verifies the result against the 5 MB and 512-file ceilings before zipping it. You upload one build, select Google Ads as a target, and get back a package built to this exact spec. For the full step-by-step workflow, see Export Unity Playworks/Luna to Google Ads.
Google Ads is included on every paid PlayableKit plan, alongside Meta, AppLovin, and Unity Ads on the Starter tier, with Mintegral, TikTok, and Vungle unlocking on Studio and Scale. Full breakdown on the pricing page.