IMA SDK for Video Players: Complete Integration Guide for Web, Android, and iOS

The Google IMA SDK provides a client-side solution for loading and playing video ads across six lifecycle stages: SDK import, initialization, ad request, load handling, playback events, and cleanup.

The IMA SDK for video players enables developers to monetize content with interactive media ads across multiple platforms. According to the google/skills repository, the SDK supports web browsers, Android devices, iOS/tvOS systems, and connected TVs through a unified architecture adapted to each native environment.

IMA SDK Lifecycle Overview

The SDK follows a consistent six-stage workflow regardless of platform. Understanding these stages ensures reliable ad delivery and prevents memory leaks.

Stage 1: Import the SDK

Load the JavaScript library from the Google CDN to make the google.ima namespace available.

<script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"></script>

Mobile platforms use package managers: Gradle for Android (com.google.ads.interactivemedia:interactivemedia:3.31.0), CocoaPods/SPM for iOS.

Stage 2: Initialization

Configure global settings via google.ima.settings before creating containers. This sets locale, VPAID mode, and other preferences that apply to all ad requests.

Key objects created:

  • AdDisplayContainer: Binds an HTML element for ads to your content video
  • AdsLoader: Handles the ad-request lifecycle

Stage 3: Ad Request

Construct an AdsRequest, set the ad tag URL, and declare playback capabilities:

const request = new google.ima.AdsRequest();
request.adTagUrl = 'https://example.com/adtag.xml';
request.setAdWillAutoPlay(true);
request.setAdWillPlayMuted(false);
adsLoader.requestAds(request);

Stage 4: Ad Load Success or Failure

Listen for AdsManagerLoadedEvent (success) and AdErrorEvent (failure). On success, retrieve the AdsManager, initialize with player dimensions, and start playback.

Stage 5: Ad Playback Events

The AdsManager emits critical events including CONTENT_PAUSE_REQUESTED and CONTENT_RESUME_REQUESTED. Hook these to synchronize your content player with ad playback.

Stage 6: Cleanup

Always destroy resources to prevent memory leaks:

adsManager?.destroy();
adsLoader.contentComplete();
adDisplayContainer.destroy();

Web Integration (HTML5 TypeScript)

The web implementation relies on SKILL.md and ima-sdk-web-guide.md in the google/skills repository for best practices.

HTML Structure

<div id="playerContainer" style="position:relative;width:640px;height:360px;">
  <video id="contentVideo" style="width:100%;height:100%;"></video>
  <div id="adContainer"
       style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;"></div>
</div>

Complete TypeScript Implementation

let adsLoader: google.ima.AdsLoader;
let adDisplayContainer: google.ima.AdDisplayContainer;
let adsManager: google.ima.AdsManager | null = null;

// Configure global settings early
google.ima.settings.setLocale('en');
google.ima.settings.setVpaidMode(google.ima.ImaSdkSettings.VpaidMode.ENABLED);

// Create UI containers
const adDiv = document.getElementById('adContainer') as HTMLElement;
const video = document.getElementById('contentVideo') as HTMLVideoElement;
adDisplayContainer = new google.ima.AdDisplayContainer(adDiv, video);
adsLoader = new google.ima.AdsLoader(adDisplayContainer);

// Hook loader events
adsLoader.addEventListener(
  google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
  onAdsManagerLoaded
);
adsLoader.addEventListener(
  google.ima.AdErrorEvent.Type.AD_ERROR,
  onAdError
);

function requestAd(adTagUrl: string, autoPlay: boolean, muted: boolean) {
  adDisplayContainer.initialize();  // Must follow user gesture
  const request = new google.ima.AdsRequest();
  request.adTagUrl = adTagUrl;
  request.setAdWillAutoPlay(autoPlay);
  request.setAdWillPlayMuted(muted);
  adsLoader.requestAds(request);
}

function onAdsManagerLoaded(e: google.ima.AdsManagerLoadedEvent) {
  const renderingSettings = new google.ima.AdsRenderingSettings();
  adsManager = e.getAdsManager(video, renderingSettings);
  
  adsManager.addEventListener(
    google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED,
    () => video.pause()
  );
  adsManager.addEventListener(
    google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
    () => video.play()
  );
  adsManager.addEventListener(
    google.ima.AdErrorEvent.Type.AD_ERROR,
    onAdError
  );

  try {
    adsManager.init(640, 360, google.ima.ViewMode.NORMAL);
    adsManager.start();
  } catch (err) {
    onAdError(err);
  }
}

function onAdError(event: any) {
  console.error('IMA error:', event);
  cleanupAds();
  video.play();
}

function cleanupAds() {
  adsManager?.destroy();
  adsManager = null;
  adsLoader.contentComplete();
  adDisplayContainer.destroy();
}

Android Integration (Kotlin)

Android implementations use the ima-sdk-android-guide.md reference. The Kotlin API mirrors the web lifecycle with native Android patterns.

// Gradle dependency
implementation("com.google.ads.interactivemedia:interactivemedia:3.31.0")

// Activity implementation
private lateinit var adDisplayContainer: AdDisplayContainer
private lateinit var adsLoader: AdsLoader
private var adsManager: AdsManager? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    IMASdkFactory.getInstance().settings.locale = "en"
    IMASdkFactory.getInstance().settings.vpaidMode = IMASettings.VpaidMode.ENABLED

    val adContainer = findViewById<FrameLayout>(R.id.adContainer)
    val videoView = findViewById<VideoView>(R.id.contentVideo)
    adDisplayContainer = AdDisplayContainer(adContainer, videoView)
    adsLoader = AdsLoader(this, adDisplayContainer)

    adsLoader.addAdsLoadedListener { manager -> onAdsManagerLoaded(manager) }
    adsLoader.addAdErrorListener { error -> onAdError(error) }
}

private fun requestAd(adTagUrl: String) {
    val request = AdsRequest().apply {
        this.adTagUrl = adTagUrl
        setAdWillAutoPlay(true)
        setAdWillPlayMuted(false)
    }
    adsLoader.requestAds(request)
}

private fun onAdsManagerLoaded(manager: AdsManager) {
    adsManager = manager
    manager.addAdEventListener { event ->
        when (event.type) {
            AdEvent.Type.CONTENT_PAUSE_REQUESTED -> videoView.pause()
            AdEvent.Type.CONTENT_RESUME_REQUESTED -> videoView.start()
        }
    }
    manager.addAdErrorListener { error -> onAdError(error) }
    manager.init(640, 360, ViewMode.NORMAL)
    manager.start()
}

private fun onAdError(error: AdError) {
    Log.e("IMA", "Error: ${error.message}")
    adsManager?.destroy()
    adsLoader.contentComplete()
    videoView.start()
}

iOS Integration (Swift)

iOS developers reference ima-sdk-ios-guide.md and ima-sdk-tvos-guide.md for platform-specific guidance. The Swift implementation uses delegate patterns familiar to iOS developers.

import GoogleInteractiveMediaAds

class PlayerViewController: UIViewController {
    private var adDisplayContainer: IMAAdDisplayContainer!
    private var adsLoader: IMAAdsLoader!
    private var adsManager: IMAAdsManager?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        IMASettings.shared().locale = "en"
        IMASettings.shared().vpaidMode = .enabled

        let adContainer = UIView(frame: view.bounds)
        view.addSubview(adContainer)
        
        let contentPlayer = AVPlayerViewController()
        addChild(contentPlayer)
        view.addSubview(contentPlayer.view)

        adDisplayContainer = IMAAdDisplayContainer(
            adContainer: adContainer,
            companionSlots: nil
        )
        adsLoader = IMAAdsLoader(settings: IMASettings.shared())
        adsLoader.delegate = self
    }

    func requestAd(tagUrl: String) {
        let request = IMAAdsRequest(
            adTagUrl: tagUrl,
            adDisplayContainer: adDisplayContainer,
            contentPlayhead: nil,
            userContext: nil
        )
        request.adWillAutoPlay = true
        request.adWillPlayMuted = false
        adsLoader.requestAds(with: request)
    }
}

extension PlayerViewController: IMAAdsLoaderDelegate {
    func adsLoader(_ loader: IMAAdsLoader, didReceive adsLoadedData: IMAAdsLoadedData) {
        adsManager = adsLoadedData.adsManager
        adsManager?.delegate = self
        adsManager?.initialize(with: IMAAdsRenderingSettings())
        adsManager?.start()
    }

    func adsLoader(_ loader: IMAAdsLoader, didFailWithErrorData errorData: IMAAdLoadingErrorData) {
        print("IMA load error: \(errorData.adError.message)")
    }
}

extension PlayerViewController: IMAAdsManagerDelegate {
    func adsManager(_ manager: IMAAdsManager, didReceive event: IMAAdEvent) {
        switch event.type {
        case .contentPauseRequested:
            // Pause content player
            break
        case .contentResumeRequested:
            // Resume content player
            break
        default:
            break
        }
    }

    func adsManager(_ manager: IMAAdsManager, didReceive error: IMAAdError) {
        print("IMA playback error: \(error.message)")
        manager.destroy()
    }
}

Platform-Specific Reference Files

The google/skills repository organizes IMA SDK documentation by platform:

Platform Reference File Purpose
Web ima-sdk-web-guide.md HTML5/JS integration, lifecycle events
Android ima-sdk-android-guide.md Kotlin/Java implementation patterns
iOS ima-sdk-ios-guide.md Swift/Objective-C integration
tvOS ima-sdk-tvos-guide.md Apple TV-specific considerations
Special ima-sdk-web-iframe-mode.md AMP and iframe environments
Special ima-sdk-web-mobile-safari.md Autoplay and muted policy handling

Critical Implementation Details

User Gesture Requirements

Call adDisplayContainer.initialize() only after a user interaction. This satisfies browser autoplay policies and mobile Safari restrictions documented in ima-sdk-web-mobile-safari.md.

Error Handling Strategy

Distinguish between non-fatal LOG events (diagnostics only) and fatal AD_ERROR events (require cleanup and content fallback). Always implement both AdErrorEvent listeners on AdsLoader and AdsManager.

Memory Management

Nullify references after destroy() calls:

adsManager.destroy();
adsManager = null;  // Prevent stale reference usage

Summary

  • Import early: Load the SDK and configure google.ima.settings before creating containers
  • Initialize after gesture: AdDisplayContainer.initialize() requires user interaction on web
  • Request with context: Set adWillAutoPlay and adWillPlayMuted accurately for optimal ad selection
  • Listen comprehensively: Handle both AdsManagerLoadedEvent and AdErrorEvent on the loader
  • Synchronize playback: Respond to CONTENT_PAUSE_REQUESTED and CONTENT_RESUME_REQUESTED to coordinate ad and content playback
  • Destroy completely: Call destroy() on all three main objects (AdsManager, AdsLoader.contentComplete(), AdDisplayContainer) to prevent memory leaks

Frequently Asked Questions

What is the minimum IMA SDK version for modern mobile browsers?

The google/skills repository does not specify minimum versions in the analyzed files. However, the Android example uses version 3.31.0 as a current stable reference point. Check the official IMA SDK release notes for deprecation schedules and feature availability.

Why does my ad fail to load on mobile Safari?

Mobile Safari enforces strict autoplay and muted policies. The ima-sdk-web-mobile-safari.md file documents that you must call adDisplayContainer.initialize() within a user gesture handler, and accurately declare setAdWillPlayMuted(true) when appropriate. Incorrect capability reporting causes silent failures.

How do I implement IMA SDK in a React or Angular application?

The web integration patterns in ima-sdk-web-guide.md apply directly to framework implementations. Create the AdDisplayContainer and AdsLoader in a component's initialization lifecycle, store references in instance variables or refs, and call destroy() in cleanup handlers (useEffect return or ngOnDestroy).

Can I use the IMA SDK within an iframe or AMP page?

Yes. The ima-sdk-web-iframe-mode.md file provides specific guidance for constrained environments where the standard integration pattern is restricted. This includes message-passing configurations and reduced API surface areas for AMP compatibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →