Published 2026-04-18 · 7 min read · HTML5 / IAB

The 2026 HTML5 Ad IAB Compliance Checklist

Most HTML5 bundles that fail in production fail the same handful of checks. Here's the complete list — the hard numbers plus the non-obvious gotchas — and how to verify each one before you hand the zip to a publisher.

The hard thresholds

IAB's Display Creative Guidelines (most recent substantive update pre-2026) give you a single set of numbers every publisher treats as the floor. Miss any one of them and the bundle will either be rejected at upload or throttled in delivery.

Check Threshold Measured how
Initial load weight ≤ 150 KB Sum of all bytes transferred before load event
Polite load (total) ≤ 300 KB (display) / 1 MB (expandable) Sum of all bytes over the creative lifetime
Load time ≤ 4 s to fully rendered Time from first byte to load
HTTP requests ≤ 15 (display) / ≤ 30 (rich media) Total requests including images, scripts, fonts, pixels
Script count ≤ 5 Count of <script> tags loaded after first paint
CPU usage < 30% sustained Chrome DevTools Performance panel
Frame rate ≥ 24 fps during animation Animation sampling, 15-second window

These are the display thresholds. Third-party tags (DCM, Flashtalking, Sizmek, etc.) get higher limits because the vendor wrapper adds weight before the creative runs — we use 500 KB / 1 MB / 10 s / 30 requests / 15 scripts for tags inside CreativeValidator.

The checks that actually reject bundles

1. clickTag wiring

Every HTML5 bundle needs a top-level clickTag variable readable by the ad server. GAM, DCM, Flashtalking, and Sizmek all scrape it at upload. Common mistakes:

<script>
var clickTag = "https://example.com"; // placeholder, overwritten at runtime
</script>
<a href="javascript:window.open(window.clickTag)">...</a>

2. Initial weight must include fonts

The most common 150 KB overage: a 90 KB HTML + 40 KB JS bundle that pulls in a 120 KB custom WOFF2 font from Google Fonts. The font counts. Either subset it down to the actual glyphs used or switch to a system font.

3. document.write is disallowed

Publishers running inside SafeFrame or using post-load injection will break if the creative calls document.write after DOMContentLoaded. Many legacy ad-server wrappers still do it — including some DCM iframe/legacy tags. This is a hard reject for Google Ad Manager.

4. Mixed content

Every resource the bundle pulls in must be served over HTTPS. Modern browsers block mixed content entirely inside SafeFrame, but you'll often find:

5. Console errors

A creative that throws a JS exception during its first animation frame may still render the first keyframe, but everything after silently dies. Ad servers don't check this — but publishers do, and campaigns get pulled mid-flight.

6. Network-request leaks

Watch for creatives that fire a request every animation tick (lazy img.src reassignment, or a debug-mode analytics hook). A bundle at 12 requests per second will pass the initial threshold and fail the 30-second sustained check.

CreativeValidator runs all 16 IAB checks automatically — weights, requests, scripts, load time, clickTag, SSL, console errors — against your .zip bundle.

Validate an HTML5 bundle →

The non-obvious gotchas

7. ClickTag must be escaped

If the creative uses window.open(clickTag) and the ad server passes the URL unescaped, special characters in the landing page (e.g., query strings with &) can truncate the URL. Always wire through encodeURIComponent or use the ad server's escape macro.

8. Hidden iframes count toward request limits

A common trick for loading tracking pixels — injecting a 1x1 iframe pointing at a third-party domain — still counts as a network request. Teams often miss this because DevTools groups iframe requests under the iframe's document, not the parent.

9. Fonts and @font-face

If you use an @font-face rule, every variant declared fires a preload regardless of whether it's used. If you only use regular-400, declare only regular-400.

10. Local storage and cookies

Most publishers strip third-party cookies already, and many SafeFrame implementations block localStorage. Relying on either for state persistence within the creative is fragile — use in-memory state instead.

11. GSAP and animation libraries

The full GSAP bundle is around 60 KB gzipped. That's 40% of your initial weight budget. Use the TweenLite/TweenMax subset that matches what you actually call, or switch to CSS animations for simple cases.

12. Fallback image requirements

Every HTML5 creative needs a static fallback image at the same dimensions. Publishers serve the fallback on browsers without JS, or as a backup if the HTML5 fails to render. Missing fallbacks don't block upload, but they do block serving in certain placements.

13. meta ad.size declaration

The HTML should include <meta name="ad.size" content="width=300,height=250"> inside <head>. Some adservers enforce this; others use it to auto-detect size. Missing it makes you pick the size manually at upload, which is fine, but easy to mismatch.

14. CPU-expensive transforms

Animating left/top/margin forces layout recalculation on every frame. Animating transform/opacity is compositor-only. A 5-second animation of left: 0 → 500px will spike CPU; the same motion via transform: translateX(500px) won't.

15. Absolute URLs for all assets

If you use relative paths (./image.png), they resolve against the iframe's base URL — which for ad-served HTML5 is the ad server's CDN, not your zip bundle. Always use absolute paths or the adserver's asset macro.

16. Heavy ad guidelines (Chrome)

Since 2020 Chrome has unloaded iframes that use >4 MB total network, >60 seconds CPU, or >15 seconds wall time. These are less strict than IAB's, but once an ad is unloaded, no further tracking or click-through fires. A bundle that was "within tolerance" during QA can still get silently killed in the wild.

The QA pass that catches most of it

  1. Run the zip through an automated validator for all 16 checks.
  2. Manually open the fallback image and confirm dimensions match.
  3. Load the ad in a clean Chrome profile. Record the network tab for 30 seconds. Sum the bytes, count the requests.
  4. Open DevTools Console. Confirm zero errors during the first animation loop.
  5. Click through. Verify landing URL resolves, SSL is valid, no redirect loops.
  6. Resize the browser. Confirm the creative either scales cleanly or is locked to its declared size.

All of the above — plus 40 more checks — in a single drag-and-drop scan.

Upload HTML5 zip →