Playable ads guide

HTML5 Playable Ads: What's Inside the File & How to Build One

Every major ad network calls its playable format 'HTML5', but HTML5 is a technology, not a format. What networks require is a specific subset of HTML5: self-contained, offline-capable, wired to that network's own store-exit call, under its size limit (2 MB of HTML on Meta, 5 MB on most others), and able to run correctly in a native app's webview. Knowing what goes into that file explains what a playable ad maker does for you.

Anatomy of a Playable Ad HTML File

A correctly built playable HTML file has four layers that all live in one document:

  • Structure (HTML): the layout of the ad (background container, text elements, CTA button, overlay elements).
  • Style (CSS): layout, fonts, animation keyframes, responsive sizing that fills the device viewport.
  • Interaction (JavaScript): event listeners for tap/hold/swipe, MRAID lifecycle hooks, device detection for the CTA URL.
  • Assets (embedded): images base64-encoded directly in the HTML, fonts inlined as data URIs, any animation data or SVG embedded in the script.

When a network serves this file, it loads in an iframe or webview inside the host app. Because everything is embedded, it works even if the device is offline or on a throttled connection. There's no second network request for a missing image. Networks require self-contained files because they load reliably.

What MRAID Does and Why It Matters

MRAID (Mobile Rich Media Ad Interface Definitions) is the JavaScript API that lets your HTML ad talk to the native container. Without MRAID, clicking a link in the ad opens the in-app browser, not the App Store. With MRAID, calling mraid.open('https://apps.apple.com/...') opens the correct system handler, the App Store or Play Store app, which is necessary for a tracked install.

Not every network uses MRAID the same way. Unity, AppLovin, Chartboost and InMobi expect a mraid.js tag, which their container fills in, and exit with mraid.open(); InMobi asks for MRAID 3.0. Vungle loads MRAID too but exits by posting a "download" message to its container, and Liftoff waits for MRAID and then calls Liftoff.open() with no URL. Google uses ExitApi.exit() from its own exitapi.js. Meta and Moloco forbid mraid.js and use FbPlayableAd.onCTAClick(). TikTok and Pangle use window.openAppStore(), and Mintegral window.install(). A no-code playable ad maker that exports per network takes care of this variation: each exported file has the right exit call and packaging for that specific network.

CSS Animation vs JavaScript Animation

Animations inside a playable HTML file can be driven by CSS (keyframe animations, transitions) or JavaScript (requestAnimationFrame loops, library-based tweening). CSS animations are preferred because they run on the browser's compositor thread, which is separate from the main JavaScript thread. This means they stay smooth even if the JavaScript is doing other work, and they don't contribute to the ad's CPU profile in ways that could trigger battery warnings.

Complex effects (particle systems, per-character text animation, physics-based interactions) require JavaScript. The Particle FX system and Kinetic Text animations in Playable Ads Maker are built to hold 60fps on mid-range phones.

What Happens From Load to Click

Every playable follows the same sequence once a network serves it, and most bugs sit at one of its transitions.

  1. The container opens a webview and loads the HTML. Because every asset is inlined, nothing else is fetched.
  2. The network's bridge becomes available (MRAID, ExitApi, the Pangle SDK or another) and the creative waits for it to report ready.
  3. The creative waits until it is actually on screen, then starts its entrance animation and any timed content.
  4. The viewer interacts. Taps, holds and drags drive the scene, and nothing should depend on sound, since many placements start muted.
  5. The viewer taps the CTA. The creative works out whether it is running on iOS or Android and passes the matching store URL to the network's exit call.
  6. The container takes over, opens the store and records the click for attribution.

A creative that skips a step usually still works in a desktop browser, where steps two and three never happen and step six has nowhere to go. That is why playables have to be tested inside a real container, or a faithful simulation of one, and not only in a browser tab.

Single File or ZIP

Networks disagree on packaging. Unity and AppLovin take a single HTML file with everything inside it. Google, TikTok, Pangle, Mintegral and Vungle take a ZIP, with the HTML at a specific place in the archive and, in TikTok's case, a config.json beside it. Meta accepts either, with a separate limit on the HTML inside its ZIP. The content is the same idea either way, one self-contained creative, but the wrapper must match the network exactly, and a file packaged for one is rarely accepted by another.

Rendering: DOM, Canvas or WebGL

Inside the file, the scene can be drawn in three ways. Plain HTML elements styled with CSS are simplest and fine for a static end card. A 2D canvas draws everything as pixels, which suits games and particle effects. WebGL hands drawing to the GPU, which keeps many moving objects smooth on mid-range phones. Most builders, and most hand-built playables of any complexity, draw on a canvas or WebGL and keep HTML elements for the few things that need them. The choice is invisible to the network; what it sees is still one self-contained file.

How to Inspect a Playable You Didn't Build

  • Open the file in a text editor and search for http. Any address that points outside the file is a request the network will refuse.
  • Look for the exit call (mraid.open, ExitApi.exit, FbPlayableAd.onCTAClick, window.openAppStore or window.install) to see which network the build was made for.
  • Check the size and, for a ZIP, what is inside it and where the HTML sits.
  • Open it on a phone and play it through to the CTA with the sound off.

The playable ad spec checker looks at the same things against a chosen network's requirements.

Common Misconceptions About HTML5 Playables

  • It is just a web page. It runs like one, but without network access, often without dependable storage, and inside a container that controls when it starts and where its links go. Do not rely on cookies, local storage or anything fetched at run time.
  • Any HTML5 game can ship as it is. Most need their assets inlined, their size cut and their exit wired to the network before they qualify; see turning an HTML5 game into a playable ad.
  • One file works everywhere. Packaging and exit calls differ by network, so each needs its own build.
  • Sound is part of the experience. Many placements start muted, so the creative has to make sense silently.
  • Higher resolution always looks better. Art beyond the size it is drawn at adds weight without adding visible detail.

When to Use a No-Code Tool vs Custom HTML5

Custom HTML5 development is the right choice when you need mechanics a no-code tool doesn't support: a specific physics simulation, a proprietary animation system, or deep integration with your game's exact assets and logic. For end cards, video-plus-end-card playables and simple mini-games, a no-code tool is faster and makes fewer packaging mistakes than handwritten HTML5, because it is built around each network's format.

Create playable end cards in minutes—no code required.

Open Playable Ads Maker

Check a build against these specs

The free Playable Ad Spec Checker grades an HTML or ZIP against every network’s size cap, packaging, MRAID rules and store-exit calls. It runs entirely in your browser — no upload, no sign-up.