Convert your first playable ad in 5 minutes
Playable Kit turns a Unity Luna or Playworks export ZIP into validated, ready-to-submit creatives for every major mobile ad network — automatically. No manual repackaging, no per-network scripts.
This guide covers the web dashboard workflow. For the CLI, jump to CLI reference.
Prerequisites
- A Unity Luna or Playworks build exported as a
.zipfile - A Playable Kit account — sign up free
- Your iOS App Store URL and Android Play Store URL (for CTA links)
- Node.js 22+ if you plan to use the CLI locally
Installation
Web dashboard (recommended)
No installation needed. Log in and upload your ZIP directly in the browser.
CLI (local / CI)
# Install globally
npm install -g playable-kit
# Or use npx without installing
npx playable-kit --help
Upload a build
Export from Unity Luna
In your Unity project with the Luna plugin installed, go to Luna → Build and select Playable Ad. Choose Development or Release and click Build. This produces a .zip containing index.html, engine scripts, and asset files.
Create an app in Playable Kit
In the dashboard, click New App, give it a name (e.g. Car Dealer Q2), and select your target networks. You can change the network selection later.
Upload your ZIP
Drag and drop your Luna export .zip onto the upload area or click Browse. Playable Kit inspects the archive, detects shader profiles, and validates the entry file automatically.
The ZIP must contain index.html at the root level. Nested zips are not supported.
Add store URLs
Enter your Android URL (Google Play) and iOS URL (App Store). These are injected into each network adapter's CTA handler. You can set a single URL and leave the other blank — the platform auto-selects by user agent.
Generate & download
Click Generate. Playable Kit converts and validates your build for every selected network in parallel. Each network produces a .zip you can submit directly to the ad platform. Check marks and warnings appear per network once processing completes.
Supported networks
Playable Kit targets all 12 major mobile ad networks from a single upload. Each output is fully self-contained — no external CDN dependencies.
| Network | Output format | Max size | Entry file |
|---|---|---|---|
| Google Ads | Single HTML or ZIP | 5 MB | index.html |
| Meta Ads | ZIP | 2 MB | index.html |
| AppLovin | Single HTML | 2 MB | {name}.html |
| TikTok | Single HTML | 5 MB | index.html |
| Mintegral | ZIP | 4 MB | mintegral.html |
| Liftoff / Vungle | ZIP | 5 MB | index.html |
| Chartboost | ZIP | 5 MB | index.html |
| ironSource | ZIP | 5 MB | index.html |
| Unity Ads | ZIP | 5 MB | index.html |
| Snap Ads | ZIP | 5 MB | index.html |
| InMobi | ZIP | 5 MB | index.html |
| Digital Turbine | ZIP | 5 MB | index.html |
Output modes
Each network supports two output modes. Choose based on what the ad platform requires.
Folder mode (default)
Outputs a ZIP containing a standard directory structure — index.html at the root with separate JS, asset, and cache folders alongside it. Use this when the network accepts a multi-file creative package.
Single HTML mode
Inlines all scripts, fonts, audio, images, and videos directly into a single .html file. The file is entirely self-contained with no external dependencies. Required for Google Ads single-file submissions and AppLovin.
Single HTML mode automatically applies the WebGL2 upgrade guard, AudioContext resume guard, and Google ExitAPI injection for compliant Google Ads submissions.
CLI options
Run conversions from your terminal or CI pipeline without opening the dashboard.
npx playable-kit \
--input MyGame_build.zip \
--out dist/ \
--networks google,applovin,tiktok \
--android-url "https://play.google.com/store/apps/details?id=com.example" \
--ios-url "https://apps.apple.com/app/id123456789"
| Option | Type | Default | Description |
|---|---|---|---|
--input |
required | — | Path to the Luna/Playworks export .zip |
--out |
optional | dist/ |
Output directory. Created if it doesn't exist. |
--networks |
optional | all | Comma-separated list: google, mintegral, applovin, tiktok |
--mode |
optional | folder |
folder or single-html |
--android-url |
optional | — | Google Play Store URL injected into CTA handlers |
--ios-url |
optional | — | App Store URL injected into CTA handlers |
--package-name |
optional | network id | Base name for the output ZIP and HTML files |
--cache-id |
optional | auto | Specific Luna cache folder to use in single-HTML mode |
--orientation |
optional | portrait,landscape |
Comma-separated: portrait, landscape, or both |
CLI examples
Google Ads — single HTML, portrait only
npx playable-kit \
--input build.zip \
--networks google \
--mode single-html \
--orientation portrait \
--android-url "https://play.google.com/..." \
--ios-url "https://apps.apple.com/..."
All networks, custom output folder
npx playable-kit \
--input MyGame_v3.zip \
--out releases/v3/ \
--android-url "https://play.google.com/..."
Inspect a build without converting
npx playable-kit inspect --input build.zip
Build checks
After conversion, Playable Kit runs a suite of automated checks on each output. A failed check blocks submission to that network.
Google Ads checks
| Check | What it verifies |
|---|---|
clickTag | A var clickTag or window.clickTag assignment is present |
ExitApi | Google's exitapi.js is loaded from the approved URL |
CTA handler | CTA routes through window.clickTag or ExitApi.exit() |
Direct media | No inline data-URI media tags (base122-encoded only) |
WebGL2 guard | WebGL upgrade shim is present for zero-dimension canvases |
Audio guard | AudioContext.resume() is deferred until user gesture |
Shader profile | Reports WebGL1/2 shader counts from shaders.json |
Mintegral checks
| Check | What it verifies |
|---|---|
CTA call | window.install, mraid.open, or pi.logCta is called |
Game ready | gameReady is signalled after Luna starts |
Game start | gameStart or luna:start event is present |
Game end | gameEnd is exposed or called |
Game close | gameClose wrapper is present |
TikTok checks
| Check | What it verifies |
|---|---|
TikTok SDK | Playable-sdk.js is loaded |
openAppStore | CTA uses TikTok's openAppStore() |
WebGL & audio compliance
WebGL2 upgrade guard
Some mobile browsers only expose WebGL1 even when WebGL2 is available. Playable Kit automatically patches HTMLCanvasElement.prototype.getContext to transparently upgrade webgl and experimental-webgl requests to webgl2 — improving shader compatibility on Android Chrome without any code changes in your Unity project.
AudioContext resume guard
Mobile browsers block AudioContext playback until a user gesture occurs. Playable Kit injects a lightweight guard that queues all AudioContext.resume() calls and drains them on the first interaction (click, touchstart, pointerdown, or keydown). This prevents silent audio failure on iOS Safari and Android Chrome.
Both guards are injected automatically when using single-HTML mode for Google Ads. No changes to your Unity project are required.
FAQ
Which Unity Luna versions are supported?
Playable Kit supports all Luna SDK versions that produce a standard ZIP with index.html at the root. Both WebGL1 and WebGL2 shader profiles are supported.
Can I use Playworks builds instead of Luna?
Yes. Any Playworks export ZIP with the standard structure works identically to a Luna export.
What happens if a check fails?
The conversion still completes and you can download the output, but the failed check is listed as an error in the report. Submitting a creative with a failed check may cause rejection by the ad network.
How does single-HTML inlining handle large assets?
Audio and video are compressed using fflate and stored as base122-encoded data attributes on hidden elements. They are decoded and attached via URL.createObjectURL at runtime, avoiding inline data URIs which are not permitted by Google Ads.
Can I automate conversions in CI?
Yes. Install the CLI (npm install -g playable-kit) and add a step to your GitHub Actions or GitLab CI pipeline. The CLI exits with code 0 on success and non-zero if any network has a failing check.
What is the maximum ZIP input size?
There is no hard limit on the input ZIP. Output size is constrained by the target network (e.g. 5 MB for Google Ads). Playable Kit will warn you if the output exceeds the network's limit.
Contact support
Can't find what you're looking for? Our team responds within one business day.
Email us at [email protected] or open a support ticket from inside the dashboard.