Playable ads inside TikTok For Business
TikTok For Business runs playable ads as an interactive creative format inside its app-install and app-engagement campaign objectives, most commonly served in-feed alongside organic video. Instead of a static image or a passive video, the user gets a short, tappable demo of the app or game before the install prompt — which is why the format shows up so often in gaming and utility-app user acquisition, where "let them try it first" converts better than a trailer.
Because playables run inside TikTok's own in-app browser rather than a generic mobile web view, TikTok controls the runtime end-to-end: its own SDK, its own click-through method, and its own packaging rules. That's the root reason the spec below doesn't map cleanly onto Google's, Meta's, or AppLovin's — TikTok didn't converge on the informal MRAID conventions most other networks share, it built its own.
Technical requirements
These come directly from TikTok's playable spec, not a generic mobile-web checklist. Every one of them is a distinct failure mode if missed:
| Requirement | What TikTok expects |
|---|---|
| Package format | A ZIP archive — not a single HTML file |
| Size limit | 5 MB or smaller, measured after compression (the packaged ZIP, not the raw asset folder) |
| Entry file | A first-level index.html — not nested in a subfolder, not renamed |
| Manifest | A first-level config.json declaring Playable_orientation |
| SDK | TikTok's own Playable-sdk.js, loaded locally |
| Click-through CTA | window.openAppStore() — the only supported call |
| MRAID | Prohibited outright — not accepted as an alternative format |
| External loading | No dynamic external material loading and no JS redirects; everything ships inside the package |
Notice what's absent from that list compared with most other networks: there's no requirement that everything live in a single self-contained HTML file. TikTok is fine with a multi-file ZIP — its packaging rule is about structure (flat, first-level, config.json present), not about collapsing every asset into one document the way Meta or AppLovin ask for.
The config.json requirement, specifically
This is the single most distinctive part of TikTok's spec, and the detail that most reliably separates a TikTok-ready package from a generic one. Google Ads, Meta, AppLovin, Mintegral, Unity Ads, and Vungle all work from a single HTML entry point with no companion manifest — TikTok is the outlier that requires a first-level config.json declaring Playable_orientation alongside index.html. A build authored for any other network simply won't have this file, because nothing in those specs ever asked for it.
There's no way to catch a missing or malformed config.json by opening the creative in a browser — the HTML runs fine either way. It only surfaces once TikTok's review pipeline parses the package, which is exactly why it's worth checking before submission rather than treating a rejection as the first signal.
Accepted formats and size limits
- Format: ZIP archive containing, at minimum, a first-level
index.htmland a first-levelconfig.json. A single loose HTML file with no manifest is not an accepted package shape. - Compressed size cap: 5 MB after compression. This is checked against the final ZIP, so a build that looks reasonable unzipped can still fail once it's packaged — always verify the compressed number, not the unpacked asset total.
- No format substitution: TikTok doesn't accept an MRAID-format playable as a fallback if the native TikTok format isn't ready — MRAID is explicitly prohibited, full stop.
Common upload errors
| Error | Why it happens |
|---|---|
Missing config.json | The most common and most distinctive rejection. Teams reuse a package built for another network, and since no other network asks for this file, it's simply never been created. |
| Wrong CTA | Shipping mraid.open(), a clickTag variable, or a plain window.open() call instead of window.openAppStore(). TikTok's SDK listens specifically for its own method — anything else fails silently or doesn't trigger the install flow at all. |
| MRAID-format build | A playable authored around AppLovin's or Unity Ads' MRAID conventions carries MRAID API calls that TikTok's spec prohibits outright, not just discourages. |
index.html not at the top level | The entry file is nested inside a project subfolder or renamed to match the source engine's export naming, rather than sitting first-level as index.html. |
| Compressed size over 5 MB | Uncompressed assets can look fine locally; the failure only shows up once the archive is actually zipped and measured. |
| Runtime asset fetches or JS redirects | Any asset loaded on demand from a URL, or any script-driven redirect, violates the "no dynamic external material loading" rule — everything has to be packaged in, not fetched. |
Best practices
- Set
Playable_orientationto match the build, not a guess. If the playable is locked to portrait or landscape in the source engine,config.jsonneeds to say so explicitly — a mismatch between the declared orientation and the actual layout is a bad first impression even if it doesn't hard-fail review. - Wire the CTA to
window.openAppStore()and nothing else. Don't leave a fallbackmraid.open()orclickTagcall in the code path even as dead code — clean it out so there's no ambiguity about which method actually fires. - Zip and measure before you assume you're under the cap. Check the compressed size of the actual archive you're about to upload, not the folder of source assets.
- Keep everything local. No CDN-hosted fonts, no remote image fetches, no analytics pings mid-playable — TikTok's "no dynamic external material loading" rule means the package has to be fully self-sufficient.
- Don't reuse an MRAID build as-is. If the same creative also ships to AppLovin, Unity Ads, or Mintegral, treat the TikTok version as a separate build target rather than trying to make one MRAID-based package pass on both.
- Validate structure before submitting. A missing
config.jsonor misplaced entry file won't show up in a local preview — only in TikTok's review queue. Checking package shape ahead of time saves a review cycle.
config.json, or broken inline script, and use the size checker to confirm the compressed archive is actually under TikTok's 5 MB cap before you upload. Both run with no signup.
Exporting a TikTok-ready package with PlayableKit
If your build originates from Unity Playworks/Luna (or another engine export), PlayableKit generates the config.json, relocates the entry file to a first-level index.html, injects TikTok's Playable-sdk.js, rewires the CTA to window.openAppStore(), strips any MRAID-format code and external asset fetches, and checks the zipped size against the 5 MB cap — automatically, from the same source build you already have. The full step-by-step version of that workflow, including a side-by-side of manual vs. automated, is on the Playworks/Luna-to-TikTok export page.
TikTok is available on PlayableKit's Studio plan ($560/month, 100 builds) and above — Scale ($800/month, 2 seats, 300 builds) and Enterprise include it too. It's not part of the Starter plan's network list, so if TikTok is one of your targets, confirm your plan covers it before you build.