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:

RequirementWhat TikTok expects
Package formatA ZIP archive — not a single HTML file
Size limit5 MB or smaller, measured after compression (the packaged ZIP, not the raw asset folder)
Entry fileA first-level index.html — not nested in a subfolder, not renamed
ManifestA first-level config.json declaring Playable_orientation
SDKTikTok's own Playable-sdk.js, loaded locally
Click-through CTAwindow.openAppStore() — the only supported call
MRAIDProhibited outright — not accepted as an alternative format
External loadingNo 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.html and a first-level config.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

ErrorWhy it happens
Missing config.jsonThe 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 CTAShipping 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 buildA 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 levelThe 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 MBUncompressed assets can look fine locally; the failure only shows up once the archive is actually zipped and measured.
Runtime asset fetches or JS redirectsAny 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_orientation to match the build, not a guess. If the playable is locked to portrait or landscape in the source engine, config.json needs 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 fallback mraid.open() or clickTag call 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.json or 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.
Two free checks before you submit: run the package through PlayableKit's Playable Ad Validator to catch a missing entry file, missing 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.