Why a ZIP fails review for reasons that have nothing to do with the creative
Several ad networks want a ZIP archive rather than a single HTML file, and each of them parses that archive with its own strict, unforgiving rules about what's inside it and how it's arranged. None of these are creative-quality checks — they're structural checks that run before a human or an automated reviewer even looks at what the playable does. Four causes show up over and over:
- Wrong entry file path. Every network that accepts a ZIP expects the HTML entry point at a specific location — sometimes the archive root, sometimes a named first-level folder. If the loader looks in the wrong place, the creative doesn't render at all, and that reads as a broken ad, not a packaging mistake.
- Mismatched archive, folder, and HTML names. Some networks require the ZIP filename, the top-level folder inside it, and the HTML file itself to all share the same name. Rename one of the three during a rebuild — which is easy to do by accident — and the whole package fails a naming check before anything else is inspected.
- Exceeding a file count limit. A ZIP that plays fine locally can still contain far more individual files than a network allows once you count every texture, audio clip, and font as a separate entry. Limits here are about the archive's file count, not its byte size.
- Missing a required config file. Some networks expect a small JSON manifest alongside the HTML — declaring things like orientation — as a first-level file in the archive. Leave it out, or nest it one folder too deep, and the package fails even though the creative itself is fine.
All four are invisible if you only open the ZIP and preview the playable in a browser. They only surface once the target network's own package parser gets involved — which, without checking beforehand, means the first time you find out is during review.
What the free validator actually checks on a ZIP today
To be precise rather than promotional: PlayableKit's free Playable Ad Validator is a static-analysis check built around the raw Unity Playworks/Luna export — the same source ZIP regardless of which network you're eventually targeting — not a per-network ZIP-packaging linter. On a ZIP upload, it currently runs five checks:
- Entry file present at the archive root. It confirms
index.htmlexists at the top level of the ZIP. If your export nests the entry file in a subfolder, this check catches that. - Engine/cache assets present. It confirms either
engine/scripts.jsor a complete Lunacache/<id>/{scripts,jsons,blobs}.jsset exists — a sign the ZIP is an intact Playworks/Luna export rather than a partial or corrupted one. - Click-through hook (informational). It scans for a recognizable pattern like
clickTagormraid.open. This doesn't affect pass/fail — a raw export normally has none of these yet. - Inline script syntax. It parses every inline
<script>block for JavaScript syntax errors, without executing anything. - Package structure summary. It reports total file count and total uncompressed size as information alongside the other findings.
What it does not do — and this matters if the title of this page made you expect otherwise — is check any of the network-specific packaging rules above. It doesn't compare your file count against Google's 512-file cap, it doesn't check whether your archive name, folder name, and HTML filename match for Mintegral, and it doesn't look for a config.json for TikTok. Those rules apply to the final, per-network package — not to the raw source export the validator is built to sanity-check — and today they're enforced by PlayableKit's actual conversion step producing a correctly-shaped package for each network, rather than by a standalone pass/fail check on an arbitrary ZIP you hand it. If you're hand-assembling a ZIP for a specific network yourself, the checklist below is what to verify manually.
Common ZIP-structure mistakes by network
These are the specific packaging rules that most often trip up a hand-built or hand-edited ZIP, drawn from each network's own packaging requirements:
| Network | ZIP-structure rule | What commonly goes wrong |
|---|---|---|
| Google Ads | ZIP must contain no more than 512 files, 5 MB or smaller, with an orientation meta tag in the entry HTML. | Unpacked texture/audio assets push the file count over 512 even when total size is well under the byte cap. |
| Mintegral | For ZIP upload, the archive name, the top-level folder name inside it, and the HTML file name should all match. | A rebuild or rename changes one of the three (often the ZIP filename after a re-export) while the folder and HTML inside stay the same, breaking the match. |
| TikTok | The main HTML file in the first-level directory must be named index.html, and that same first-level directory must contain a config.json declaring orientation. | config.json gets left out entirely, or ends up nested inside a subfolder instead of sitting at the first level next to index.html. |
None of these three are about the creative's assets, code, or click-through wiring — they're purely about how the archive is laid out. That's exactly why they're easy to overlook: everything can look correct when you preview the unpacked HTML locally, and still fail the moment the network's packager inspects the ZIP itself.
Where PlayableKit fits
PlayableKit's conversion pipeline generates each network's ZIP (or single-HTML file, for the networks that require one) already shaped to that network's own rules — matching names, file counts, and config files included — rather than leaving you to rebuild and rename by hand for every target. The free validator above is the quick first check on your raw export before any of that; the per-network packaging itself happens during actual conversion.