Export format
Programmatic HTML5, ready for any DSP or ad server.
Every exchange rewrites the click its own way, so the creative has to accept a click macro, keep clickTag as a fallback, and stay safe inside a cross-origin iframe. Do that once and the same file runs across Display & Video 360, The Trade Desk and a plain ad server.
This is the IAB shell we wrap programmatic builds in: inline assets only, no document.write, no top-level navigation, and a fixed stage that scales into whatever slot the exchange serves it into.
The spec
Programmatic HTML5 (IAB)
- Delivery
- ZIP with index.html at the root, uploaded to the DSP or ad server as an HTML5 creative.
- Size
- Any IAB slot; the stage is fixed and scaled by transform to fit.
- Weight
- Keep the compressed bundle under 200 KB where the exchange enforces IAB LEAN.
- Click through
- The exchange click macro is prepended to the landing URL, with clickTag kept as a fallback.
- SSL
- Everything is inline, so the creative is https-safe by construction.
- Sandbox
- No document.write, no top-level navigation, no cookies — safe inside a cross-origin iframe.
- Sizing
- The 320x480 stage scales into whatever slot the exchange serves.
- Destination
- Any website, tracked by the DSP's own click macro.
The template
playable_programmatic_320x480.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<!-- IAB HTML5 display creative. Declare the slot size for the ad server. -->
<meta name="ad.size" content="width=320,height=480">
<title>Playable — 320x480</title>
<style>
html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #0f0f12; }
* { -webkit-tap-highlight-color: transparent; box-sizing: border-box; }
#stage { position: relative; width: 320px; height: 480px; margin: 0 auto; transform-origin: top center; }
#exit { position: absolute; inset: 0; z-index: 9999; background: transparent; border: 0; padding: 0; cursor: pointer; }
</style>
</head>
<body>
<script type="text/javascript">
// Click macro. Most DSPs rewrite %%CLICK_URL_UNESC%% at serve time;
// clickTag / clickTAG are read as a fallback by legacy ad servers.
var CLICK_MACRO = "%%CLICK_URL_UNESC%%";
var clickTag = "";
var clickTAG = clickTag;
var LANDING_URL = "https://example.com";
</script>
<div id="stage">
<!-- PLAYABLE BODY: generated markup, CSS and JS are inlined here. -->
<button id="exit" type="button" aria-label="Visit site" hidden></button>
</div>
<script type="text/javascript">
function resolveClickUrl() {
var macro = CLICK_MACRO.indexOf("%%") === 0 ? "" : CLICK_MACRO;
var target = clickTag || clickTAG || LANDING_URL;
return macro ? macro + encodeURIComponent(target) : target;
}
function fireCTA() {
var url = resolveClickUrl();
if (url) { window.open(url, "_blank"); }
}
document.getElementById("exit").addEventListener("click", fireCTA, false);
window.showEndCard = function () {
document.getElementById("exit").hidden = false;
};
// Fit a fixed 320x480 stage inside any slot the exchange serves it into.
function scaleStage() {
var stage = document.getElementById("stage");
var scale = Math.min(window.innerWidth / 320, window.innerHeight / 480);
stage.style.transform = "scale(" + scale + ")";
}
window.addEventListener("resize", scaleStage, false);
window.addEventListener("orientationchange", scaleStage, false);
scaleStage();
</script>
</body>
</html>How this fits the build
The studio generates one self-contained playable, then wraps it in the shell above: the click plumbing, the size declaration and the end-card exit surface are the parts a validator actually checks, and they are identical on every build.
Because this is display inventory rather than app-install inventory, the click can land on your website. No App Store or Google Play listing is required.