VAST XML for Google IMA SDK
Google's Interactive Media Ads (IMA) SDK is the most widely deployed video ad SDK in the world — used across web, Android, iOS, tvOS, Chromecast, and Fire TV. It handles VAST tag fetching, wrapper chain resolution, media selection, and event tracking. This guide covers exactly what your VAST tag needs to look like for IMA to deliver it without errors.
Quick reference
| VAST versions | 2.0, 3.0, 4.0, 4.1, 4.2, 4.3 |
| VPAID | Web only (desktop). Blocked on Android, iOS, CTV. |
| Wrapper chain limit | 4 hops |
| Required media format | MP4 H.264 (all platforms); WebM optional on web |
| HTTPS | Required on all platforms |
SDK architecture
Implementing IMA client-side involves four main SDK objects:
- AdDisplayContainer — The container element where IMA renders ad UI and measures viewability (Active View, OMID). Position it over the video element. Do not move this element after instantiation.
- AdsLoader — Requests ads from the VAST tag URL and fires
ADS_MANAGER_LOADEDorAD_ERRORevents. Instantiate once and reuse throughout the page lifecycle. - AdsRequest — Defines the ad request: VAST tag URL, slot dimensions, and other parameters. Create a new
AdsRequestper ad request. - AdsManager — Controls ad playback and fires ad events. Returned via the
ADS_MANAGER_LOADEDcallback. CalladsManager.init()andadsManager.start()to begin playback.
// Minimal IMA HTML5 setup
function setUpIMA() {
adDisplayContainer = new google.ima.AdDisplayContainer(
document.getElementById('adContainer'), videoContent);
adsLoader = new google.ima.AdsLoader(adDisplayContainer);
adsLoader.addEventListener(
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
onAdsManagerLoaded);
adsLoader.addEventListener(
google.ima.AdErrorEvent.Type.AD_ERROR, onAdError);
// Signal content ended so IMA can play post-rolls
videoContent.onended = () => {
if (!isAdPlaying) adsLoader.contentComplete();
};
const adsRequest = new google.ima.AdsRequest();
adsRequest.adTagUrl = 'https://pubads.g.doubleclick.net/gampad/ads?...';
adsRequest.linearAdSlotWidth = 640;
adsRequest.linearAdSlotHeight = 400;
adsRequest.nonLinearAdSlotWidth = 640;
adsRequest.nonLinearAdSlotHeight = 150;
adsLoader.requestAds(adsRequest);
}
function onAdsManagerLoaded(adsManagerLoadedEvent) {
adsManager = adsManagerLoadedEvent.getAdsManager(videoContent);
adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,
() => videoContent.pause());
adsManager.addEventListener(google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
() => videoContent.play());
adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdLoaded);
adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError);
}Supported VAST versions
IMA SDK supports all six versions of the IAB VAST spec: 2.0 through 4.3. The SDK detects the version from the version attribute on the root <VAST> element and applies version-appropriate parsing rules automatically.
If your tag uses VAST 4.x elements (such as <UniversalAdId>, <Verification>, or <ViewableImpression>) but declares version="3.0", IMA will still attempt delivery but may silently ignore the 4.x elements. Always declare the correct version.
<!-- ✅ Correct: version matches the elements used -->
<VAST version="4.2">
<Ad id="1">
<InLine>
<AdSystem>My Ad Server</AdSystem>
<AdTitle>My Video Ad</AdTitle>
<Impression><![CDATA[https://track.example.com/impression]]></Impression>
<UniversalAdId idRegistry="Ad-ID">8465903</UniversalAdId>
<Creatives>...</Creatives>
</InLine>
</Ad>
</VAST>VPAID policy
VPAID 2.0 JavaScript creatives (apiFramework="VPAID") are supported only on desktop web. They are completely blocked on:
- Android (IMA SDK for Android)
- iOS (IMA SDK for iOS)
- Apple tvOS
- Chromecast / Google Cast
- Any CTV or OTT environment
When a VPAID tag reaches a blocked environment, the IMA SDK silently discards the creative. No error fires, the slot goes dark, and your impression goes unfilled. The fix is to provide a native VAST creative alongside or instead of VPAID.
Google officially deprecated VPAID support in 2022 in favour of SIMID for interactive creatives and OMID for viewability measurement. For any new campaigns, use VAST-native MP4 creatives with <Verification> blocks for OMID.
→ vastlint rule: VAST-4.1-vpaid-in-interactive-context
Wrapper chain limit
IMA SDK enforces a maximum of 4 wrapper hops before it expects to resolve to an inline ad. If the chain exceeds 4 levels, the SDK abandons the request and the slot goes unfilled — no error is reported to the end user.
Each hop adds latency. In practice, chains longer than 2–3 hops on CTV environments frequently hit timeout limits (typically 3 seconds on Roku, 5 seconds on Fire TV) before ever reaching the inline ad.
<!-- ❌ Chain too deep — IMA will abandon at hop 5 -->
<!-- Wrapper 1 → Wrapper 2 → Wrapper 3 → Wrapper 4 → Wrapper 5 → InLine -->
<!-- ✅ Keep chains at 3 hops or fewer for reliable CTV delivery -->
<!-- Wrapper 1 → Wrapper 2 → InLine -->Required media formats
Every inline ad must contain at least one <MediaFile> that IMA can play on the target platform. Provide multiple <MediaFile> entries at different bitrates and resolutions; IMA will pick the best fit.
| Platform | Required | Recommended |
|---|---|---|
| Web (Chrome, Firefox, Safari) | MP4 H.264 | + WebM VP9 |
| Android | MP4 H.264 | Multiple bitrates (360p, 720p) |
| iOS / iPadOS | MP4 H.264 | HLS for long-form |
| tvOS / Apple TV | MP4 H.264 | HLS, 1080p |
| Chromecast | MP4 H.264 | + WebM |
→ vastlint rules: VAST-2.0-mediafiles-empty, VAST-2.0-mediafile-url
HTTPS requirement
All URLs in a VAST tag served by IMA must use https:// — media files, impression pixels, click-through URLs, tracking events, and companion assets. HTTP URLs trigger mixed-content blocking on web and are rejected outright by IMA on mobile and CTV.
Duration format
IMA requires <Duration> to follow the HH:MM:SS or HH:MM:SS.mmm format. Bare integers (30) and ISO 8601 durations (PT30S) are both rejected.
<!-- ❌ Rejected by IMA -->
<Duration>30</Duration>
<Duration>PT30S</Duration>
<!-- ✅ Accepted -->
<Duration>00:00:30</Duration>→ vastlint rule: VAST-2.0-duration-format
Skippable ads
To make an ad skippable in IMA, set the skipoffset attribute on the <Linear> element. The value must be a time offset (HH:MM:SS) or a percentage (20%).
<!-- Skip button appears after 5 seconds -->
<Linear skipoffset="00:00:05">
...
</Linear>→ vastlint rule: VAST-3.0-skipoffset-format
Companion ads
IMA SDK renders companion ads when the publisher page has registered companion ad slots. Companion ads are optional in VAST; if present, they must include either a <StaticResource>, <HTMLResource>, or <IFrameResource>. Missing dimensions (width, height) on <CompanionAd> prevent IMA from matching the correct slot.
OMID (Open Measurement)
IMA SDK natively supports OMID viewability measurement. Include a <Verification> block inside <AdVerifications> with your OMID vendor script. IMA will execute it at the appropriate point in the ad lifecycle. This replaces VPAID-based measurement.
<AdVerifications>
<Verification vendor="doubleverify.com-omid">
<JavaScriptResource apiFramework="omid" browserOptional="true">
<![CDATA[https://cdn.doubleverify.com/dvtp_src.js]]>
</JavaScriptResource>
</Verification>
</AdVerifications>Non-linear ads (overlays)
Non-linear ads display as overlays on top of the content video while it continues to play. To support non-linear ads, listen for the LOADED event on the AdsManager and check whether the ad is linear before pausing content:
adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdLoaded);
function onAdLoaded(adEvent) {
const ad = adEvent.getAd();
if (!ad.isLinear()) {
// Non-linear ad (overlay): content continues playing
videoContent.play();
}
}VMAP and ad rules
To use Google Ad Manager ad rules (pre/mid/post-roll scheduling managed server-side), request a VMAP response by setting output=xml_vmap1 in your GAM tag. The IMA SDK handles the entire ad schedule automatically —adsManager.init() starts VMAP ad playback and individual breaks fire on cue.
VMAP is supported on web (HTML5 IMA) and iOS/Android with custom ad playback. VMAP on iPhone requires custom ad playback mode.
Mobile: user gesture required
On mobile browsers (iOS Safari, Chrome for Android), ad playback must be triggered by a user interaction. The adDisplayContainer.initialize() and adsManager.init() calls must happen inside a user event handler (e.g. a play button click), not on page load.
// Must be triggered by user action (click, tap)
playButton.addEventListener('click', function() {
videoContent.load();
adDisplayContainer.initialize(); // must be in gesture handler
adsManager.init(640, 360);
adsManager.start();
});JavaScript framework compatibility
When using a JavaScript framework such as React or Angular with IMA HTML5 SDK, these frameworks often move DOM elements during rendering, which can break IMA. IMA expects the DOM to be static when the SDK is initiated.
The HTML element passed as containerElement to AdDisplayContainer must not be moved after instantiation. Initialize IMA only after the framework has finished its initial render (e.g. in useEffect in React, or ngAfterViewInit in Angular).
AirPlay caveat
The IMA SDK does not support Apple AirPlay. When a user AirPlays video content, ad requests and tracking stop working correctly. Either disable AirPlay on your video element or detect AirPlay and skip ad requests when it is active.
// Option 1: disable AirPlay entirely
videoContent.setAttribute('disableRemotePlayback', '');
// Option 2: detect AirPlay and skip IMA setup
if (!videoContent.webkitCurrentPlaybackTargetIsWireless) {
setUpIMA();
}Pre-flight checklist for Google IMA SDK
- VAST version attribute matches elements used
- No VPAID if targeting Android, iOS, or CTV
- Wrapper chain depth ≤ 4 (ideally ≤ 3)
- At least one MP4 H.264
<MediaFile> - All URLs use HTTPS
<Duration>inHH:MM:SSformat<Impression>element presentskipoffsetinHH:MM:SSor percentage format (if skippable)- Non-linear: set both
linearAdSlotHeightandnonLinearAdSlotHeightonAdsRequest - Mobile:
adDisplayContainer.initialize()called in user gesture handler - JS frameworks: initialize IMA after framework DOM mutations complete
- AirPlay: disabled on video element or detected and ad requests skipped
References
- IMA SDK for HTML5 — Getting started
- IMA SDK HTML5 — SDK support and compatibility (VAST version matrix, VPAID support table)
- IMA SDK for Android — Getting started
- IMA SDK for iOS — Getting started
- IMA SDK for tvOS — Getting started
- IMA SDK — Enable VPAID 2 JS creatives (HTML5 desktop only)
- IMA SDK — Enable Open Measurement (OMID)
- IMA SDK — Specify bitrate and media format
- IMA Video Suite Inspector — test VAST tags in the browser