diff --git a/README.md b/README.md
index 0fff60dae8..c66f205994 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ repo to install.
## Available Skills
+
- **Getting started with Google Cloud**
- [**Authenticating to Google Cloud**](./skills/cloud/google-cloud-recipe-auth)
- [**Google Cloud Recipe: Foundation Builder**](./skills/cloud/google-cloud-recipe-foundation-builder)
@@ -89,18 +90,19 @@ repo to install.
- **Web and app hosting**
- [**Cloud Run Basics**](./skills/cloud/cloud-run-basics)
- [**Firebase Basics**](./skills/cloud/firebase-basics)
-- **Advertising**
- - [**AI Migration Agent Instructions for the Google Mobile Ads SDK**](./skills/ads/google-mobile-ads/google-mobile-ads-android-migrate-to-next-gen)
- - [**Data Manager API Audience Ingestion**](./skills/ads/data-manager-api/data-manager-api-audience-ingestion)
- - [**Data Manager API Event Ingestion**](./skills/ads/data-manager-api/data-manager-api-event-ingestion)
- - [**Data Manager API Setup**](./skills/ads/data-manager-api/data-manager-api-setup)
- - [**Google Ads API MCP Server Installation**](./skills/ads/google-ads-api/google-ads-api-mcp-setup)
- - [**Google Ads API Quickstart**](./skills/ads/google-ads-api/google-ads-api-quickstart)
- - [**Google Mobile Ads SDK - Banner Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-banner)
- - [**Google Mobile Ads SDK - Install**](./skills/ads/google-mobile-ads/google-mobile-ads-get-started)
- - [**Google Mobile Ads SDK - Interstitial Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-interstitial)
- - [**Google Mobile Ads SDK - Rewarded Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-rewarded)
- - [**IMA SDK basics**](./skills/ads/interactive-media-ads/ima-sdk-basics)
+- **Advertising**
+ - [**AI Migration Agent Instructions for the Google Mobile Ads SDK**](./skills/ads/google-mobile-ads/google-mobile-ads-android-migrate-to-next-gen)
+ - [**Data Manager API Audience Ingestion**](./skills/ads/data-manager-api/data-manager-api-audience-ingestion)
+ - [**Data Manager API Event Ingestion**](./skills/ads/data-manager-api/data-manager-api-event-ingestion)
+ - [**Data Manager API Setup**](./skills/ads/data-manager-api/data-manager-api-setup)
+ - [**Google Ads API MCP Server Installation**](./skills/ads/google-ads-api/google-ads-api-mcp-setup)
+ - [**Google Ads API Quickstart**](./skills/ads/google-ads-api/google-ads-api-quickstart)
+ - [**Google Mobile Ads SDK - Banner Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-banner)
+ - [**Google Mobile Ads SDK - Install**](./skills/ads/google-mobile-ads/google-mobile-ads-get-started)
+ - [**Google Mobile Ads SDK - Interstitial Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-interstitial)
+ - [**Google Mobile Ads SDK - Rewarded Ads**](./skills/ads/google-mobile-ads/google-mobile-ads-rewarded)
+ - [**IMA SDK client-side**](./skills/ads/ima-sdk-client-side)
+ - [**IMA SDK DAI Basics**](./skills/ads/ima-dai-sdk)
- **Others**
- [**Getting Started with Google Analytics Admin API**](./skills/analytics/google-analytics-admin-api-basics)
- [**Getting Started with Google Analytics Data API**](./skills/analytics/google-analytics-data-api-basics)
diff --git a/skills/ads/ima-dai-sdk/SKILL.md b/skills/ads/ima-dai-sdk/SKILL.md
new file mode 100644
index 0000000000..bc8dd71831
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/SKILL.md
@@ -0,0 +1,89 @@
+---
+name: ima-dai-sdk
+description: >-
+ Integrates the Google Interactive Media Ads (IMA) DAI SDK into websites, web apps,
+ mobile apps, or TV apps for Google Dynamic Ad Insertion (DAI) with HLS or DASH streams.
+
+ Use when:
+ - Integrating the IMA DAI SDK for Google Dynamic Ad Insertion (DAI), Server-Side Ad Insertion (SSAI), Full Service DAI, or DAI Pod Serving redirect.
+ - Requesting HLS (.m3u8) or MPEG-DASH (.mpd) DAI streams on Web, Android, iOS/tvOS, or Roku platforms.
+
+ Don't use for:
+ - Client-side ad insertion (CSAI) with VAST and VMAP requests (use the `ima-sdk-client-side` skill instead).
+
+license: Apache-2.0
+metadata:
+ author: Google LLC
+ version: "1.0.0"
+---
+
+# IMA SDK DAI Basics
+
+The Google IMA DAI SDK lets you load a single stream containing both content and
+ads into websites, apps, TVs and other digital platforms. Use an IMA SDK to
+request an HLS or MPEG DASH stream from a video stitcher or stream origin.
+
+## Mandatory Prerequisites
+
+Correct integration requires identifying the streaming protocol, DAI type, and target platform up front. Review the relevant reference guides below to ensure proper setup:
+
+1. **Identify the Streaming Protocol:**
+
+ * **HLS (HTTP Live Streaming):** Stream URLs end in `.m3u8`. Read the [HLS Guide](references/hls.md).
+ * **MPEG DASH:** Stream URLs end in `.mpd`. Read the [DASH Guide](references/dash.md).
+
+2. **Identify the DAI Type:**
+
+ * **Full Service DAI:** Request a Google DAI stream URL using an `assetKey` (Live) or `cmsId`/`videoId` (VOD). Read the [Full Service Guide](references/full-service.md).
+ * **Pod Serving DAI:** Request a Google DAI `streamId` using an `assetKey`/`customAssetKey` (linear stream, livestream) or `cmsId`/`videoId` (VOD). Construct a playback stream URL with the `streamId`. Read the [Pod Serving Guide](references/pod-serving.md).
+
+3. **Identify the Target Platform:**
+
+ * **Web/NodeJs/ReactJs:** Native JavaScript/TypeScript environments (browsers, Smart TVs). Read the [Web Guide](references/web.md).
+ * **Android/AndroidTV:** Native Java/Kotlin environments. Read the [Android Guide](references/android-ima-extension.md).
+ * **iOS/tvOS:** Native Swift/Objective-C environments. Read the [iOS/tvOS Guide](references/ios-tvos.md).
+ * **Roku:** Native BrightScript/SceneGraph environments. Read the [Roku Guide](references/roku.md).
+
+--------------------------------------------------------------------------------
+
+## Quick Start (General Workflow)
+
+For all apps, the integration follows this general logical flow:
+
+1. Import the SDK: Set up prerequisites and dependencies.
+2. Initialization: Early setup, Warmup, Settings Configuration, and Ad UI Setup.
+3. Ad Stream request: Create the livestream or VOD stream request.
+4. Ad Stream Load Success/Failure: Handle the stream load event to obtain the `StreamManager` or handle early fatal errors.
+5. Stream Playback Events: Listen to timed metadata events for forwarding ID3/emsg tags to the IMA DAI SDK, and handle non-fatal LOG events or fatal stream errors.
+6. Cleanup: Properly destroy the `StreamManager` to release resources and prevent memory leaks.
+
+### Basic Web Live Stream Integration Example
+
+```typescript
+import { LiveStreamRequest, StreamManager, StreamEvent } from '@google/ima-dai-sdk';
+
+const videoElement = document.getElementById('video-player') as HTMLVideoElement;
+const adUiElement = document.getElementById('ad-ui') as HTMLElement;
+
+// 1. Initialize StreamManager
+const streamManager = new StreamManager(videoElement, adUiElement);
+
+// 2. Listen for stream loaded event
+streamManager.addEventListener(
+ StreamEvent.Type.LOADED,
+ (event: StreamEvent) => {
+ const streamUrl = event.getStreamData().url;
+ videoElement.src = streamUrl;
+ videoElement.play();
+ }
+);
+
+// 3. Request live stream
+const streamRequest = new LiveStreamRequest();
+streamRequest.assetKey = 'YOUR_ASSET_KEY';
+streamRequest.networkCode = 'YOUR_NETWORK_CODE';
+streamManager.requestStream(streamRequest);
+```
+
+For detailed, platform-specific implementation details, refer to the guides in the **Mandatory Prerequisites** section.
+
diff --git a/skills/ads/ima-dai-sdk/references/android-ima-extension.md b/skills/ads/ima-dai-sdk/references/android-ima-extension.md
new file mode 100644
index 0000000000..9ffcb41c09
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/android-ima-extension.md
@@ -0,0 +1,162 @@
+# Google IMA SDK DAI - Media3 IMA Extension Integration Guide
+
+This guide covers integrating the Google IMA SDK for Android DAI using the
+**Media3 IMA Extension** (`androidx.media3:media3-exoplayer-ima`) and
+`ImaServerSideAdInsertionMediaSource`.
+
+Using the extension is the recommended approach for Media3 ExoPlayer
+integrations as it handles stream wrapping, ad UI overlays, and ad event
+synchronization automatically without requiring a custom `VideoStreamPlayer`
+implementation.
+
+--------------------------------------------------------------------------------
+
+## 1. Dependencies and Configuration
+
+Add the Media3 IMA extension dependency to your app's `build.gradle.kts` file.
+
+Use latest version of the IMA SDK, which is published at
+https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/download.md.txt.
+Use the latest version of the ExoPlayer and IMA extension at
+https://developer.android.com/jetpack/androidx/releases/media3.md.txt.
+
+```kotlin
+android {
+ defaultConfig {
+ minSdk = 23
+ }
+}
+
+dependencies {
+ implementation("androidx.media3:media3-ui:$latestVersion")
+ implementation("androidx.media3:media3-exoplayer:$latestVersion")
+
+ // CRITICAL: Add the Media3 IMA Extension
+ implementation("androidx.media3:media3-exoplayer-ima:$latestVersion")
+}
+```
+
+--------------------------------------------------------------------------------
+
+### 2. Initialization
+
+Configure the SDK early to minimize latency, and reuse the SDK settings.
+
+* **Early Warmup & Settings Reuse (Best Practice):** Call
+ `ImaSdkFactory.initialize()` in your `Application.onCreate()` to preload SDK
+ resources.
+* Reuse the same `ImaSdkSettings` instance when creating the
+ `ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setImaSdkSettings` to
+ avoid cache misses that cause latency spikes.
+
+```kotlin
+// 1. Application class for early warmup
+class MyApplication : Application() {
+ companion object {
+ lateinit var sdkFactory: ImaSdkFactory
+ lateinit var imaSettings: ImaSdkSettings
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ sdkFactory = ImaSdkFactory.getInstance()
+
+ // Configure settings early
+ imaSettings = sdkFactory.createImaSdkSettings().apply {
+ language = YOUR_LANGUAGE_CODE // Use 2 lowercase letters to identify
+ // the language of your app UI.
+ isDebugMode = true
+ }
+
+ sdkFactory.initialize(this, imaSettings)
+ }
+}
+...
+
+private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
+ val adsLoaderBuilder = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);
+
+ return adsLoaderBuilder
+ .setImaSdkSettings(getImaSdkSettings())
+ .build();
+}
+```
+
+### 3. Build DAI Request UIRs
+
+Create an `ImaServerSideAdInsertionUriBuilder` to build an SSAI livestream URL.
+
+Make sure to use an `assetKey`, which is a string of alphanumeric characters as
+a URL-safe base64 encoded value. For example, here are the assetKeys of DAI
+sample streams: `c-rArva4ShKVIAkNfy6HUQ`,
+`XYrjlG09QTa8pxAo5Fzjww`,`PSzZMzAkSXCmlJOWDmRj8Q`.
+
+```kotlin
+import android.net.Uri
+import androidx.media3.common.C
+import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionUriBuilder
+
+// Example 1: HLS Live Stream
+val hlsLiveUri: Uri = ImaServerSideAdInsertionUriBuilder()
+ .setAssetKey("YOUR_LIVE_ASSET_KEY")
+ .setFormat(C.CONTENT_TYPE_DASH)
+ .build()
+
+// Example 2: HLS VOD Stream
+val hlsVodUri: Uri = ImaServerSideAdInsertionUriBuilder()
+ .setContentSourceId("YOUR_CMS_ID")
+ .setVideoId("YOUR_VIDEO_ID")
+ .setFormat(C.CONTENT_TYPE_DASH)
+ .build()
+```
+
+### 4. Create an ads-aware `MediaSourceFactory`
+
+When using the ExoPlayer IMA extension, you must use the
+`ImaServerSideAdInsertionMediaSource.AdsLoader` class instead of the
+`ImaAdsLoader` class.
+
+When creating the `ImaServerSideAdInsertionMediaSource.AdsLoader`, you must
+provide the `PlayerView` object for rendering ad UI elements.
+
+You must create a `DefaultMediaSourceFactory` object for your content and call
+the `DefaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory()`
+method with the `ImaServerSideAdInsertionMediaSource.AdsLoader` object.
+
+```kotlin
+// Construct the AdsLoader instance
+val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, playerView)
+ .build()
+
+// Instantiate the factory and bind the AdsLoader for SSAI handling
+val mediaSourceFactory = DefaultMediaSourceFactory(context)
+ .setServerSideAdInsertionMediaSourceFactory(adsLoader)
+```
+
+### 5. Set Up ExoPlayer
+
+Create the ExoPlayer instance with your ad-aware media source factory and
+provide the ExoPlayer instance to the `AdsLoader` for monitoring ad events.
+
+```kotlin
+// Construct the player using the configured factory
+val player = ExoPlayer.Builder(context)
+ .setMediaSourceFactory(mediaSourceFactory)
+ .build()
+
+// Bind the player to the AdsLoader immediately
+adsLoader.setPlayer(player)
+```
+
+### 6. Load the media item
+
+### 6. Load Media and Manage the Lifecycle
+
+Pass your constructed SSAI URI directly into the player as a `MediaItem`.
+
+When destroying the player activity or handling background events, you must
+execute a strict teardown sequence to preserve the user's session. Call
+`release()` on the `AdsLoader` before releasing the ExoPlayer instance. Capture
+the returned `AdsLoader.State` object and store it securely (e.g., in a
+`ViewModel`). Provide this saved state back to the `AdsLoader.Builder` during
+reinitialization to ensure ad playback resumes exactly where it left off.
diff --git a/skills/ads/ima-dai-sdk/references/dash.md b/skills/ads/ima-dai-sdk/references/dash.md
new file mode 100644
index 0000000000..66fd5fc24e
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/dash.md
@@ -0,0 +1,31 @@
+# Google IMA SDK DAI - DASH Integration Guide
+
+This guide covers DASH stream request configuration with IMA DAI SDK.
+
+When requesting a DASH stream, you set the stream format as follows.
+
+* **Web (TypeScript):**
+
+ ```typescript
+ const streamRequest = new google.ima.dai.api.LiveStreamRequest();
+ streamRequest.format = 'dash'; // the format property is also available for
+ // VODStreamRequest,
+ // PodStreamRequest, PodVodStreamRequest.
+ ```
+
+* **Android (Kotlin):**
+
+ ```kotlin
+ val request = sdkFactory.createLiveStreamRequest(...)
+ request.format = StreamFormat.DASH
+ ```
+
+ Or if using Media3 SSAI Uri Builder:
+
+ ```kotlin
+ val ssaiUri = ImaServerSideAdInsertionUriBuilder()
+ .setAssetKey(assetKey)
+ .setFormat(androidx.media3.common.C.CONTENT_TYPE_DASH)
+ // ...
+ .build()
+ ```
diff --git a/skills/ads/ima-dai-sdk/references/full-service.md b/skills/ads/ima-dai-sdk/references/full-service.md
new file mode 100644
index 0000000000..321456190a
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/full-service.md
@@ -0,0 +1,259 @@
+# Google IMA SDK DAI - Full Service Integration Guide
+
+In a Full Service integration, Google Ad Manager handles the entire server-side
+ad insertion (SSAI) workflow, including selecting ads, transcoding them, and
+stitching them directly into your video manifest. The SDK requests the stream
+directly from Google DAI servers and returns a fully stitched stream URL (or
+handles playback internally).
+
+--------------------------------------------------------------------------------
+
+## 1. Web Integration
+
+### A. Requesting a Stream
+
+You can request either a Live stream (requires `assetKey`) or a VOD stream
+(requires `contentSourceId`/CMS ID and `videoId`).
+
+```typescript
+const videoElement = document.getElementById('video') as HTMLVideoElement;
+const adUiElement = document.getElementById('adUi') as HTMLElement;
+let streamManager: google.ima.dai.api.StreamManager;
+
+function initializeDAI(): void {
+ streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
+ setupStreamManagerListeners();
+}
+
+function requestLiveStream(assetKey: string, networkCode: string, apiKey?: string): void {
+ const streamRequest = new google.ima.dai.api.LiveStreamRequest();
+ streamRequest.assetKey = assetKey;
+ streamRequest.networkCode = networkCode;
+
+ if (apiKey) {
+ streamRequest.apiKey = apiKey;
+ }
+ streamManager.requestStream(streamRequest);
+}
+
+function requestVODStream(cmsId: string, videoId: string, networkCode: string, apiKey?: string): void {
+ const streamRequest = new google.ima.dai.api.VODStreamRequest();
+ streamRequest.contentSourceId = cmsId;
+ streamRequest.videoId = videoId;
+ streamRequest.networkCode = networkCode;
+ if (apiKey) {
+ streamRequest.apiKey = apiKey;
+ }
+ streamManager.requestStream(streamRequest);
+}
+```
+
+### B. Handling Stream Events
+
+Listen for the `LOADED` event to get the stitched stream URL, and `ERROR` to
+fallback to a backup stream.
+
+```typescript
+function setupStreamManagerListeners(): void {
+ streamManager.addEventListener(
+ google.ima.dai.api.StreamEvent.Type.LOADED,
+ onStreamLoaded,
+ false
+ );
+ streamManager.addEventListener(
+ google.ima.dai.api.StreamEvent.Type.ERROR,
+ onStreamError,
+ false
+ );
+}
+
+function onStreamLoaded(e: google.ima.dai.api.StreamEvent): void {
+ const streamData = e.getStreamData();
+ if (streamData) {
+ const streamUrl = streamData.url;
+ playStream(streamUrl); // Load into your player (hls.js, dash.js, etc.)
+ }
+}
+
+function onStreamError(e: google.ima.dai.api.StreamEvent): void {
+ const streamData = e.getStreamData();
+ if (streamData) {
+ console.error('DAI Error:', streamData.errorMessage);
+ }
+ playBackupStream(); // Fallback to unmonetized content
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 2. Android Integration
+
+You can integrate using the Media3 ExoPlayer SSAI extension (recommended) or
+using custom player APIs.
+
+### A. Media3 ExoPlayer SSAI Extension (Recommended)
+
+The `media3-exoplayer-ima` extension handles player setup and metadata
+extraction automatically.
+
+```kotlin
+private fun initializePlayer() {
+ // 1. Create the SSAI AdsLoader
+ adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView).build()
+
+ // 2. Set up MediaSource Factory with SSAI support
+ val mediaSourceFactory = DefaultMediaSourceFactory(this)
+ val adsMediaSourceFactory =
+ ImaServerSideAdInsertionMediaSource.Factory(adsLoader, mediaSourceFactory)
+ mediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory)
+
+ // 3. Create ExoPlayer
+ player = ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build()
+ playerView.player = player
+ adsLoader.setPlayer(player)
+
+ // 4. Build SSAI URI (Live example)
+ val ssaiUri = ImaServerSideAdInsertionUriBuilder()
+ .setAssetKey("YOUR_ASSET_KEY")
+ .setFormat(androidx.media3.common.C.CONTENT_TYPE_HLS)
+ .build()
+
+ val ssaiMediaItem = MediaItem.fromUri(ssaiUri)
+ player.setMediaItem(ssaiMediaItem)
+ player.prepare()
+ player.play()
+}
+```
+
+### B. Custom Player Integration
+
+If not using the extension, you must implement `VideoStreamPlayer` and request
+the stream manually.
+
+```kotlin
+val sdkFactory = ImaSdkFactory.getInstance()
+val displayContainer =
+ ImaSdkFactory.createStreamDisplayContainer(adUiContainer, videoStreamPlayer)
+val adsLoader = sdkFactory.createAdsLoader(context, settings, displayContainer)
+
+adsLoader.addAdsLoadedListener { event ->
+ val streamManager = event.streamManager
+ streamManager.init() // SDK automatically calls VideoStreamPlayer.loadUrl()
+}
+
+val request =
+ sdkFactory.createVodStreamRequest("CMS_ID", "VIDEO_ID", null, "NETWORK_CODE")
+adsLoader.requestStream(request)
+```
+
+The SDK will call your `VideoStreamPlayer.loadUrl(url, subtitles)` where you
+must load the URL into your player.
+
+--------------------------------------------------------------------------------
+
+## 3. iOS/tvOS Integration (AVPlayer)
+
+### A. Requesting the Stream
+
+Use `IMALiveStreamRequest` or `IMAVODStreamRequest` and wrap `AVPlayer` with
+`IMAAVPlayerVideoDisplay`.
+
+```swift
+override func viewDidLoad() {
+ super.viewDidLoad()
+ setupPlayer()
+ adsLoader = IMAAdsLoader(settings: nil)
+ adsLoader?.delegate = self
+ adDisplayContainer = IMAAdDisplayContainer(adContainer: videoView, viewController: self, companionSlots: nil)
+ imaVideoDisplay = IMAAVPlayerVideoDisplay(avPlayer: videoPlayer) // Handles HLS ID3 automatically
+}
+
+func requestStream() {
+ if isLive {
+ let request = IMALiveStreamRequest(assetKey: "YOUR_ASSET_KEY", networkCode: "YOUR_NETWORK_CODE", adDisplayContainer: adDisplayContainer!, videoDisplay: imaVideoDisplay, userContext: nil)
+ adsLoader?.requestStream(with: request)
+ } else {
+ let request = IMAVODStreamRequest(contentSourceID: "YOUR_CMS_ID", videoID: "YOUR_VIDEO_ID", networkCode: "YOUR_NETWORK_CODE", adDisplayContainer: adDisplayContainer!, videoDisplay: imaVideoDisplay, userContext: nil)
+ adsLoader?.requestStream(with: request)
+ }
+}
+```
+
+### B. Handling Stream Load
+
+In `IMAAdsLoaderDelegate`, initialize the `StreamManager`. For Full Service, the
+SDK automatically loads the stream into the `AVPlayer` and starts playback.
+
+```swift
+func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
+ streamManager = adsLoadedData.streamManager
+ streamManager?.delegate = self
+ streamManager?.initialize(with: nil)
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 4. Passing Custom Parameters (Targeting)
+
+You can pass custom parameters (such as targeting key-values) to the ad request
+by setting ad tag parameters on the stream request.
+
+### A. Web (TypeScript)
+
+Set `adTagParameters` on the `StreamRequest` object.
+
+```typescript
+function requestLiveStreamWithTargeting(assetKey: string, networkCode: string): void {
+ const streamRequest = new google.ima.dai.api.LiveStreamRequest();
+ streamRequest.assetKey = assetKey;
+ streamRequest.networkCode = networkCode;
+
+ // Pass custom parameters
+ streamRequest.adTagParameters = {
+ 'genre': 'action',
+ 'age': '25'
+ };
+
+ streamManager.requestStream(streamRequest);
+}
+```
+
+### B. Android (Kotlin)
+
+#### Using Media3 ExoPlayer SSAI Extension
+
+Use `setAdTagParameters` on `ImaServerSideAdInsertionUriBuilder`.
+
+```kotlin
+val adTagParameters = mapOf("genre" to "action", "age" to "25")
+val ssaiUri = ImaServerSideAdInsertionUriBuilder()
+ .setAssetKey("YOUR_ASSET_KEY")
+ .setFormat(androidx.media3.common.C.CONTENT_TYPE_HLS)
+ .setAdTagParameters(adTagParameters)
+ .build()
+```
+
+### C. iOS/tvOS (Swift)
+
+Set `adTagParameters` on the `IMAStreamRequest` object.
+
+```swift
+func requestStreamWithTargeting() {
+ let request = IMALiveStreamRequest(
+ assetKey: "YOUR_ASSET_KEY",
+ networkCode: "YOUR_NETWORK_CODE",
+ adDisplayContainer: adDisplayContainer!,
+ videoDisplay: imaVideoDisplay,
+ userContext: nil
+ )
+
+ // Pass custom parameters
+ request.adTagParameters = [
+ "genre": "action",
+ "age": "25"
+ ]
+
+ adsLoader?.requestStream(with: request)
+}
+```
diff --git a/skills/ads/ima-dai-sdk/references/hls.md b/skills/ads/ima-dai-sdk/references/hls.md
new file mode 100644
index 0000000000..d44dd4a439
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/hls.md
@@ -0,0 +1,31 @@
+# Google IMA SDK DAI - HLS Integration Guide
+
+This guide covers HLS stream request configuration with IMA DAI SDK.
+
+When requesting an HLS stream, you set the stream format as follows.
+
+* **Web (TypeScript):**
+
+ ```typescript
+ const streamRequest = new google.ima.dai.api.LiveStreamRequest();
+ streamRequest.format = 'hls'; // the format property is also available for
+ // VODStreamRequest,
+ // PodStreamRequest, PodVodStreamRequest.
+ ```
+
+* **Android (Kotlin):**
+
+ ```kotlin
+ val request = sdkFactory.createLiveStreamRequest(...)
+ request.format = StreamFormat.HLS
+ ```
+
+ Or if using Media3 SSAI Uri Builder:
+
+ ```kotlin
+ val ssaiUri = ImaServerSideAdInsertionUriBuilder()
+ .setAssetKey(assetKey)
+ .setFormat(androidx.media3.common.C.CONTENT_TYPE_HLS)
+ // ...
+ .build()
+ ```
diff --git a/skills/ads/ima-dai-sdk/references/ios-tvos.md b/skills/ads/ima-dai-sdk/references/ios-tvos.md
new file mode 100644
index 0000000000..b37395d2f0
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/ios-tvos.md
@@ -0,0 +1,156 @@
+# Google IMA SDK DAI - iOS & tvOS Integration Guide
+
+This guide covers the general integration steps for the Google IMA SDK for iOS
+and tvOS DAI. The two SDKs share the same core API and lifecycle flow.
+
+For protocol-specific details, see [HLS Guide](hls.md). For DAI workflows, see
+[Full Service Guide](full-service.md) and [Pod Serving Guide](pod-serving.md).
+
+--------------------------------------------------------------------------------
+
+## 1. Installation
+
+By default, use Swift Package Manager to add the the main branch of
+https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios
+or
+https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
+
+If the app must use CocoaPods, install the `GoogleAds-IMA-iOS-SDK` or
+`GoogleAds-IMA-tvOS-SDK` pod.
+
+## 2. Implement IMA protocols
+
+* **`IMAAdsLoaderDelegate`**: Required for your app to receive events when ads
+ successfully load or if they fail to load.
+* **`IMAStreamManagerDelegate`**: Required for your app to handle events
+ during ad playback (e.g., when an ad starts, pauses, completes, or when the
+ user clicks an ad).
+
+```swift
+class PlayerViewController: IMAAdsLoaderDelegate, IMAStreamManagerDelegate
+
+```
+
+--------------------------------------------------------------------------------
+
+## 3. Initialize AdsLoader Early
+
+You must create the `AdsLoader` object early, such as when your view did load.
+Set the `IMASettings` to match your app UI localization needs. Reuse the
+`AdsLoader` and `IMASettings` objects.
+
+```swift
+import AVFoundation
+import GoogleInteractiveMediaAds
+
+class PlayerViewController: ..., IMAAdsLoaderDelegate, IMAStreamManagerDelegate {
+ private var adsLoader: IMAAdsLoader?
+ // ...
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ ...
+
+ let settings = IMASettings()
+ settings.language = LANGUAGE_CODE // Use 2 letter language code to match the ad UI with your app UI's language.
+
+ // 2. Initialize AdsLoader WITH the configured settings
+ adsLoader = IMAAdsLoader(settings: settings)
+ }
+}
+```
+
+## 4. Create Ad Display Container
+
+You must create the `IMAAdDisplayContainer` object for the SDK to render the ad
+UI during ad playback. Pass your `videoView` so the SDK knows where to overlay
+the ad UI on top of the video player.
+
+```swift
+adDisplayContainer = IMAAdDisplayContainer(adContainer: videoView)
+```
+
+## 5. Create `IMAAVPlayerVideoDisplay` object
+
+You must create the `IMAAVPlayerVideoDisplay` object and provide your `AVPlayer`
+object. You must provide the `AVPlayer` object that is intended to play the ads
+if you have multiple instances of the `AVPlayer` class in your app. The SDK
+needs to listen for the timed metadata (ID3 tags) embedded in the HLS manifest
+from the ad player to trigger ad events.
+
+```swift
+imaVideoDisplay = IMAAVPlayerVideoDisplay(avPlayer: adVideoPlayer)
+```
+
+## 6. Make DAI Stream Request
+
+Refer to the [full-service DAI guide](full-service.md) and
+[pod-serving DAI guide](pod-serving.md) to determine the exact DAI stream
+request.
+
+--------------------------------------------------------------------------------
+
+## 7. tvOS-Specific Requirements
+
+Integrating on tvOS requires handling Apple TV remote focus and gestures.
+
+### A. Safe Area Layout
+
+Align your ad UI container with the safe area layout guide to prevent TV
+overscan clipping.
+
+```swift
+func setupAdContainer(in viewController: UIViewController, overlaying videoView: UIView) -> UIView {
+ let adContainerView = UIView()
+ adContainerView.translatesAutoresizingMaskIntoConstraints = false
+ viewController.view.addSubview(adContainerView)
+
+ // Align with safe area
+ let safeArea = viewController.view.safeAreaLayoutGuide
+ NSLayoutConstraint.activate([
+ adContainerView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
+ adContainerView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor),
+ adContainerView.topAnchor.constraint(equalTo: safeArea.topAnchor),
+ adContainerView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor)
+ ])
+ return adContainerView
+}
+```
+
+### B. Focus Management (Siri Remote)
+
+The SDK automatically manages the focus of the "Skip" button. You must override
+`preferredFocusEnvironments` to prefer the ad container when an ad is active:
+
+```swift
+var adIsPlaying = false // Update this based on IMAAdEvents
+
+override var preferredFocusEnvironments: [UIFocusEnvironment] {
+ if adIsPlaying, let adContainer = adContainerView {
+ return [adContainer]
+ }
+ return super.preferredFocusEnvironments
+}
+```
+
+### C. Remote Control Gestures
+
+Disable custom remote gestures (like swipe or click-to-pause) during ad playback
+to prevent users from skipping ads.
+
+```swift
+func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
+ switch event.type {
+ case .AD_BREAK_STARTED:
+ adIsPlaying = true
+ disableAppGestures() // Disable custom gestures
+ setNeedsFocusUpdate()
+ case .AD_BREAK_ENDED:
+ adIsPlaying = false
+ enableAppGestures() // Re-enable custom gestures
+ setNeedsFocusUpdate()
+ default:
+ break
+ }
+}
+```
diff --git a/skills/ads/ima-dai-sdk/references/pod-serving.md b/skills/ads/ima-dai-sdk/references/pod-serving.md
new file mode 100644
index 0000000000..3995383815
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/pod-serving.md
@@ -0,0 +1,159 @@
+# Google IMA SDK DAI - Pod Serving Integration Guide
+
+In Pod Serving, you use Google DAI with a third-party manifest manipulator or
+video technology partner (VTP). Google DAI builds the ad pods, but your manifest
+manipulator stitches the ad pods with content to give you a final, single ad
+stitched stream.
+
+The SDK registers a session, receives a `streamId`, and you use this ID to
+construct the stream URL that your player will play.
+
+--------------------------------------------------------------------------------
+
+## 1. Web Integration
+
+### A. Requesting the Stream
+
+Use `PodStreamRequest` (Livestream) or `PodVodStreamRequest` (VOD).
+
+```typescript
+let streamManager: google.ima.dai.api.StreamManager;
+
+function requestStream(): void {
+ const streamRequest = new google.ima.dai.api.PodStreamRequest();
+ streamRequest.networkCode = 'YOUR_NETWORK_CODE';
+ streamRequest.customAssetKey = 'YOUR_CUSTOM_ASSET_KEY';
+ streamManager.requestStream(streamRequest);
+
+ // For VOD stream, use the code lines below
+ // const streamRequest = new google.ima.dai.api.PodVodStreamRequest();
+ // streamRequest.networkCode = 'YOUR_NETWORK_CODE';
+ // streamManager.requestStream(streamRequest);
+ }
+```
+
+### B. Handling `STREAM_INITIALIZED` & Playback
+
+Listen for `STREAM_INITIALIZED` to get the `streamId`, build the URL, and play.
+
+```typescript
+streamManager.addEventListener(
+ google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED,
+ onStreamInitialized,
+ false
+);
+
+function onStreamInitialized(e: google.ima.dai.api.StreamEvent): void {
+ const streamData = e.getStreamData();
+ if (!streamData) return;
+
+ const streamId = streamData.streamId;
+ const url = YOUR_STREAM_URL.replace('[[STREAMID]]', streamId);
+ playStream(url);
+}
+```
+
+For VOD, you must pass the `streamId` to your manifest manipulator, call
+`loadStreamMetadata()` to fetch the ad cue points, and retrieve or construct the
+stream URL to the video player.
+
+```typescript
+function onStreamInitializedVOD(e: google.ima.dai.api.StreamEvent): void {
+ const streamData = e.getStreamData();
+ if (!streamData) return;
+
+ const streamId = streamData.streamId;
+
+ // 1. Send the DAI stream ID to your video stitcher to retrieve a stream URL
+ getStreamUrl({ streamId: streamId }).then((streamUrl: string) => {
+ // 2. Load the ad metadata from Google
+ streamManager.loadStreamMetadata();
+
+ // 3. Play the stream
+ playStream(streamUrl);
+ });
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 2. Android Integration
+
+*Note: Media3 SSAI extension does not support Pod Serving out-of-the-box. You
+must use the Custom Player integration method.*
+
+### A. Requesting the Stream
+
+```kotlin
+val request: StreamRequest =
+ sdkFactory.createPodStreamRequest(NETWORK_CODE, CUSTOM_ASSET_KEY, API_KEY)
+ // or VOD: sdkFactory.createPodVodStreamRequest(NETWORK_CODE)
+
+request.format = StreamFormat.HLS // or DASH
+adsLoader.requestStream(request)
+```
+
+### B. Handling Load & Playback
+
+Extract the `streamId`, construct the URL, and load it. For Live, play directly.
+For VOD, load via `StreamManager`.
+
+```kotlin
+override fun onAdsManagerLoaded(event: AdsManagerLoadedEvent) {
+ val streamManager = event.streamManager
+ streamManager.init()
+ val streamId = streamManager.streamId
+
+ if (isLive) {
+ val liveStreamUrl = getLiveStreamURL(streamId)
+ videoPlayer.setStreamUrl(liveStreamUrl)
+ videoPlayer.play() // SDK does NOT call VideoStreamPlayer.loadUrl for live pod serving
+ } else {
+ val vodStreamUrl = getVODStreamURL(streamId)
+ // Note: Android SDK does not have a separate loadStreamMetadata() method.
+ // loadThirdPartyStream() automatically retrieves ad metadata and loads the stream.
+ streamManager.loadThirdPartyStream(vodStreamUrl, emptyList()) // Triggers VideoStreamPlayer.loadUrl()
+ }
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 3. iOS/tvOS Integration
+
+### A. Requesting the Stream
+
+Use `IMAPodStreamRequest` or `IMAPodVODStreamRequest`.
+
+```swift
+func requestPodStream() {
+ if isLive {
+ let request = IMAPodStreamRequest(networkCode: "YOUR_NETWORK_CODE", customAssetKey: "YOUR_CUSTOM_ASSET_KEY", adDisplayContainer: adDisplayContainer!, videoDisplay: imaVideoDisplay, pictureInPictureProxy: nil, userContext: nil)
+ adsLoader?.requestStream(with: request)
+ } else {
+ let request = IMAPodVODStreamRequest(networkCode: "YOUR_NETWORK_CODE", adDisplayContainer: adDisplayContainer!, videoDisplay: imaVideoDisplay, pictureInPictureProxy: nil, userContext: nil)
+ adsLoader?.requestStream(with: request)
+ }
+}
+```
+
+### B. Handling Load & Playback
+
+```swift
+func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
+ streamManager = adsLoadedData.streamManager
+ streamManager?.delegate = self
+ streamManager?.initialize(with: nil)
+
+ guard let streamID = streamManager?.streamId else { return }
+ let urlString = getStreamUrl(streamId: streamID)
+ guard let streamUrl = URL(string: urlString) else { return }
+
+ if isLive {
+ imaVideoDisplay.loadStream(streamUrl, withSubtitles: [])
+ imaVideoDisplay.play()
+ } else {
+ streamManager?.loadThirdPartyStream(streamUrl, streamSubtitles: [])
+ }
+}
+```
diff --git a/skills/ads/ima-dai-sdk/references/roku.md b/skills/ads/ima-dai-sdk/references/roku.md
new file mode 100644
index 0000000000..8cef9c207e
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/roku.md
@@ -0,0 +1,131 @@
+# Google IMA SDK DAI - Roku Integration Guide
+
+This guide covers the integration steps for the Google IMA SDK for Roku DAI,
+which is designed for Roku SceneGraph (RSG) applications using BrightScript.
+
+--------------------------------------------------------------------------------
+
+## 1. SDK Setup
+
+Download Roku IMA SDK zip package using the following commands:
+
+```bash
+curl -L -O https://pubads.g.doubleclick.net/html5/shared/js/sdks/roku/v3/roku_ima_sdk.zip
+```
+
+Install the IMA SDK to your app.
+
+--------------------------------------------------------------------------------
+
+## 2. Initialization
+
+The Roku IMA SDK runs as a background `Task` node to prevent blocking the main
+render thread.
+
+```brightscript
+sub init()
+ m.video = m.top.findNode("myVideo")
+
+ ' Create the IMA SDK Task node
+ m.imaTask = createObject("RoSGNode", "ImaSdkTask")
+ m.imaTask.observeField("sdkLoaded", "onSdkLoaded")
+ m.imaTask.observeField("errors", "onSdkErrors")
+ m.imaTask.observeField("adEvents", "onAdEvent")
+
+ ' Start the task
+ m.imaTask.control = "RUN"
+end sub
+```
+
+--------------------------------------------------------------------------------
+
+## 3. Requesting a Stream
+
+Pass the stream request parameters to the SDK Task.
+
+### A. Live Stream Request
+
+```brightscript
+sub requestLiveStream()
+ request = {
+ assetKey: "YOUR_ASSET_KEY"
+ apiKey: "YOUR_API_KEY" ' Optional
+ networkCode: "YOUR_NETWORK_CODE"
+ type: "live"
+ }
+ m.imaTask.requestStream = request
+end sub
+```
+
+### B. VOD Stream Request
+
+```brightscript
+sub requestVodStream()
+ request = {
+ contentSourceId: "YOUR_CMS_ID"
+ videoId: "YOUR_VIDEO_ID"
+ apiKey: "YOUR_API_KEY" ' Optional
+ networkCode: "YOUR_NETWORK_CODE"
+ type: "vod"
+ }
+ m.imaTask.requestStream = request
+end sub
+```
+
+--------------------------------------------------------------------------------
+
+## 4. Handling Stream Load & Playback
+
+When the stream is loaded, the SDK Task will return the stream URL via
+`streamInfo`. You must pass this URL to your `Video` node.
+
+```brightscript
+sub onSdkLoaded(event as Object)
+ streamInfo = event.getData()
+ if streamInfo <> invalid and streamInfo.url <> invalid
+ ' Set the stream URL to the Video node
+ videoContent = createObject("RoSGNode", "ContentNode")
+ videoContent.url = streamInfo.url
+ videoContent.streamFormat = "hls"
+
+ m.video.content = videoContent
+ m.video.control = "play"
+
+ ' Important: Pass the Video node to the SDK so it can monitor playback progress
+ m.imaTask.videoNode = m.video
+ end if
+end sub
+```
+
+--------------------------------------------------------------------------------
+
+## 5. Ad Event Handling
+
+Monitor `adEvents` to manage player controls (like disabling trickplay/seeking
+during ads).
+
+```brightscript
+sub onAdEvent(event as Object)
+ adEvent = event.getData()
+ if adEvent <> invalid
+ if adEvent.type = "AD_BREAK_STARTED"
+ ' Disable seek/rewind/fast-forward
+ m.video.enableTrickPlay = false
+ else if adEvent.type = "AD_BREAK_ENDED"
+ ' Re-enable trickplay
+ m.video.enableTrickPlay = true
+ end if
+ end if
+end sub
+```
+
+--------------------------------------------------------------------------------
+
+## 6. Roku-Specific Considerations
+
+* **Trickplay Control:** You must explicitly disable `enableTrickPlay` on the
+ `Video` node during ad breaks, as Roku does not automatically block user
+ seek inputs.
+* **Keep-Alive:** The `ImaSdkTask` must remain running for the duration of the
+ stream to handle tracking pings. Do not destroy it until the video is
+ closed.
diff --git a/skills/ads/ima-dai-sdk/references/web.md b/skills/ads/ima-dai-sdk/references/web.md
new file mode 100644
index 0000000000..0421b46ac1
--- /dev/null
+++ b/skills/ads/ima-dai-sdk/references/web.md
@@ -0,0 +1,233 @@
+# Google IMA SDK DAI - Web Integration Guide
+
+This guide covers the general lifecycle and integration steps for the Google IMA
+DAI SDK on the Web (HTML5/JavaScript).
+
+For protocol-specific details, see [HLS Guide](hls.md) and
+[DASH Guide](dash.md). For DAI workflows, see
+[Full Service Guide](full-service.md) and [Pod Serving Guide](pod-serving.md).
+
+--------------------------------------------------------------------------------
+
+## 1. SDK Setup
+
+Include the IMA DAI SDK script in your HTML:
+
+```html
+
+```
+
+--------------------------------------------------------------------------------
+
+## 2. Initialization
+
+Instantiate the `StreamManager` early. It requires the content video element and
+the Ad UI container element (which overlays the video).
+
+```javascript
+const videoElement = document.getElementById('video');
+const adUiElement = document.getElementById('adUi');
+let streamManager;
+
+function initializeDAI() {
+ // The Ad UI element must be positioned directly over the video element
+ streamManager = new google.ima.dai.api.StreamManager(videoElement, adUiElement);
+ setupStreamManagerListeners();
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 3. Event Handling
+
+You must listen for lifecycle events to manage playback and UI.
+
+```javascript
+function setupStreamManagerListeners() {
+ // Stream loaded (Full Service)
+ streamManager.addEventListener(google.ima.dai.api.StreamEvent.Type.LOADED, onStreamLoaded, false);
+
+ // Stream initialized (Pod Serving)
+ streamManager.addEventListener(google.ima.dai.api.StreamEvent.Type.STREAM_INITIALIZED, onStreamInitialized, false);
+
+ // Error handling
+ streamManager.addEventListener(google.ima.dai.api.StreamEvent.Type.ERROR, onStreamError, false);
+
+ // Ad Break events
+ streamManager.addEventListener(
+ [
+ google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED,
+ google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED
+ ],
+ onAdBreakEvent,
+ false
+ );
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 4. Ad Break UI Management
+
+During ad breaks, you **must** disable custom player controls (seeking, pausing,
+etc.) to prevent users from bypassing ads, and display the Ad UI overlay.
+
+```javascript
+function onAdBreakEvent(e) {
+ switch (e.type) {
+ case google.ima.dai.api.StreamEvent.Type.AD_BREAK_STARTED:
+ videoElement.controls = false; // Hide native controls
+ adUiElement.style.display = 'block'; // Show Ad UI overlay
+ // Disable custom UI controls here
+ break;
+ case google.ima.dai.api.StreamEvent.Type.AD_BREAK_ENDED:
+ videoElement.controls = true; // Restore controls
+ adUiElement.style.display = 'none'; // Hide Ad UI overlay
+ // Enable custom UI controls here
+ break;
+ }
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 5. Cleanup
+
+Destroy the `StreamManager` when the player is disposed to release resources.
+
+````javascript
+function destroyDAI() {
+ if (streamManager) {
+ streamManager.destroy();
+ streamManager = null;
+ }
+}
+
+--------------------------------------------------------------------------------
+
+## 6. HLS Integration (Timed Metadata)
+
+When playing HLS streams, you must extract timed metadata (ID3 tags) and pass it to the SDK.
+
+### A. hls.js (Cross-Browser)
+Listen for `Hls.Events.FRAG_PARSING_METADATA` and pass the raw ID3 data to `StreamManager.processMetadata()`.
+
+```javascript
+import Hls from 'hls.js';
+
+function setupHlsPlayer(streamUrl) {
+ const hls = new Hls();
+ hls.loadSource(streamUrl);
+ hls.attachMedia(videoElement);
+
+ hls.on(Hls.Events.FRAG_PARSING_METADATA, (event, data) => {
+ if (streamManager && data) {
+ data.samples.forEach((sample) => {
+ // Parameters: Type ('ID3'), Raw Data (Uint8Array), PTS (Presentation Timestamp)
+ streamManager.processMetadata('ID3', sample.data, sample.pts);
+ });
+ }
+ });
+}
+````
+
+If dash.js, ShakaPlayer is used, read and follow the official guide for
+extracting and processing timed metadata at
+https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/html5/timed-metadata
+
+### B. Native Safari (iOS/macOS)
+
+Safari handles HLS natively. Listen for `cuechange` events on the metadata
+`TextTrack` and pass the parsed metadata to `StreamManager.onTimedMetadata()`.
+
+```javascript
+function setupNativePlayer(streamUrl) {
+ videoElement.src = streamUrl;
+ videoElement.textTracks.addEventListener('addtrack', (event) => {
+ const track = event.track;
+ if (track.kind === 'metadata') {
+ track.mode = 'hidden';
+ track.addEventListener('cuechange', () => {
+ for (const cue of track.activeCues) {
+ const metadata = {};
+ metadata[cue.value.key] = cue.value.data;
+ streamManager.onTimedMetadata(metadata);
+ }
+ });
+ }
+ });
+}
+```
+
+--------------------------------------------------------------------------------
+
+## 7. Iframe Integration
+
+When hosting the video player and the IMA SDK inside an `