Select platform: [HTML5](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/get-started.md.txt "View this page for the HTML5 platform docs.") [Android](https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/get-started.md.txt "View this page for the Android platform docs.") [iOS](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/get-started.md.txt "View this page for the iOS platform docs.") [tvOS](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/client-side/get-started.md.txt "View this page for the tvOS platform docs.")

<br />


IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can
request ads from any
[VAST-compliant](https://www.iab.com/guidelines/digital-video-ad-serving-template-vast/) ad server and manage ad playback in your apps. With IMA client-side SDKs,
you maintain control of content video playback, while the SDK handles ad playback. Ads play in a
separate video player positioned on top of the app's content video player.

<br />

This guide demonstrates how to integrate IMA SDK into a video player
app. To view or follow along with a completed sample
integration, download the
[BasicExample](https://github.com/googleads/googleads-ima-tvos-client-side) from
GitHub.


**Note:** For information on integrating with other platforms, or on using the IMA DAI SDKs, see [Interactive Media Ads SDKs](https://developers.google.com/interactive-media-ads).

<br />

## IMA client-side overview

Implementing IMA client-side involves four main SDK components. This guide
demonstrates these components:

- `

  IMAAdDisplayContainer`: A container object that specifies where IMA renders ad UI elements and measures viewability, including [Active View](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/client-side/viewability) and [Open Measurement](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/client-side/omsdk).
- `
  IMAAdsLoader`: An object that requests ads and handles events from ads request responses. You should only instantiate one ads loader, which can be reused throughout the life of the application.
- `
  IMAAdsRequest`: An object that defines an ads request. Ads requests specify the URL for the VAST ad tag, as well as additional parameters, such as ad dimensions.
- `
  IMAAdsManager`: An object that contains the response to the ads request, controls ad playback, and listens for ad events fired by the SDK.

## Prerequisites

Before you begin, you need the following:

- Xcode 13 or later
- Method for installing the IMA SDK:
  - **Preferred** : [Swift Package Manager](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/)
  - A download copy of [IMA SDK for tvOS](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/dai/download)

## 1. Create a new Xcode project

In Xcode, create a new tvOS project using Objective-C or Swift. Use
**BasicExample** as the project name.

## 2. Add IMA SDK to the Xcode project

To install IMA SDK, choose a preferred method.

### Recommended: Install IMA SDK using Swift Package Manager

Interactive Media Ads SDK supports [Swift Package
Manager](https://swift.org/package-manager/) starting in version 4.8.2. Follow these
steps to import the Swift package.

1. In Xcode, install IMA SDK Swift Package by navigating to
   **File \> Add Packages...**.

2. In the prompt that appears, search for IMA SDK Swift Package GitHub
   repository:

       https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos

3. Select the version of IMA SDK Swift Package you want to use.
   For new projects, we recommend using the **Up to Next Major Version**.

Once you're finished, Xcode resolves your package dependencies and
downloads them in the background. For more details on how to add package
dependencies, see
[Apple's article](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app).

### Manually downloading and installing IMA SDK

If you don't want to use Swift Package Manager, download and manually add IMA
SDK to your project.

#### Show/hide instructions

1. From the [tvOS IMA Download page](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/client-side/download.md.txt), download and extract the latest version of tvOS IMA SDK.
2. Open **BasicExample.xcodeproj**.
3. In the left pane, click the project name.  
   ![Project name in the left pane](https://developers.google.com/static/interactive-media-ads/images/tvos-2-3-click-project-name.png)
4. In the center pane, click **Build Phases** .  
   ![Build Phases tab in Xcode](https://developers.google.com/static/interactive-media-ads/images/tvos-2-4-build-phases.png)
5. Expand the **Link Binary With Libraries** section.
6. At the bottom of the libraries list, click the plus icon **\[+\]**.
7. Click **Add Other**.
8. In the directory where you extracted the downloaded SDK, select **GoogleInteractiveMediaAds.framework** and click **Open**.
9. At the bottom of the libraries list, click the plus icon **\[+\]** again.
10. In the **Status** column, verify that `GoogleInteractiveMediaAds.framework` shows `Required`.
11. Include the `-ObjC` linker flag in your build settings. For more information, see [Apple QA1490](https://developer.apple.com/library/content/qa/qa1490/_index.html).

## 3. Import IMA SDK

Add IMA framework using an import statement.

### Objective-C

```objective-c
#import "ViewController.h"
#import <AVKit/AVKit.h>

@import GoogleInteractiveMediaAds;
```

### Swift

```swift
import AVFoundation
import GoogleInteractiveMediaAds
import UIKit

```

## 4. Create a video player and integrate IMA SDK

The following example initializes IMA SDK:

### Objective-C

```objective-c
NSString *const kContentURLString =
    @"https://storage.googleapis.com/interactive-media-ads/media/stock.mp4";
NSString *const kAdTagURLString =
    @"https://pubads.g.doubleclick.net/gampad/ads?"
    @"iu=/21775744923/external/vmap_ad_samples&sz=640x480&"
    @"cust_params=sample_ar%3Dpremidpostlongpod&ciu_szs=300x250&gdfp_req=1&ad_rule=1&"
    @"output=vmap&unviewed_position_start=1&env=vp&cmsid=496&vid=short_onecue&correlator=";

@interface ViewController () <IMAAdsLoaderDelegate, IMAAdsManagerDelegate>
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAdDisplayContainer *adDisplayContainer;
@property(nonatomic) IMAAdsManager *adsManager;
@property(nonatomic) IMAAVPlayerContentPlayhead *contentPlayhead;
@property(nonatomic) AVPlayerViewController *contentPlayerViewController;
@property(nonatomic, getter=isAdBreakActive) BOOL adBreakActive;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];
  [self setupAdsLoader];
  [self setupContentPlayer];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  [self requestAds];
}

// Add the content video player as a child view controller.
- (void)showContentPlayer {
  [self addChildViewController:self.contentPlayerViewController];
  self.contentPlayerViewController.view.frame = self.view.bounds;
  [self.view insertSubview:self.contentPlayerViewController.view atIndex:0];
  [self.contentPlayerViewController didMoveToParentViewController:self];
}

// Remove and detach the content video player.
- (void)hideContentPlayer {
  // The whole controller needs to be detached so that it doesn't capture resume events from the
  // remote and play content underneath the ad.
  [self.contentPlayerViewController willMoveToParentViewController:nil];
  [self.contentPlayerViewController.view removeFromSuperview];
  [self.contentPlayerViewController removeFromParentViewController];
}
```

### Swift

```swift
class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
  static let contentURLString =
    "https://devstreaming-cdn.apple.com/videos/streaming/examples/"
    + "img_bipbop_adv_example_fmp4/master.m3u8"
  static let adTagURLString =
    "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&"
    + "sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&"
    + "unviewed_position_start=1&env=vp&correlator="

  var adsLoader: IMAAdsLoader!
  var adDisplayContainer: IMAAdDisplayContainer!
  var adsManager: IMAAdsManager!
  var contentPlayhead: IMAAVPlayerContentPlayhead?
  var playerViewController: AVPlayerViewController!
  var adBreakActive = false

  deinit {
    NotificationCenter.default.removeObserver(self)
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.black
    setUpContentPlayer()
    setUpAdsLoader()
  }

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    requestAds()
  }
```

In this example, `viewDidLoad()` initializes the `IMAAdsLoader`, and
`viewDidAppear()` requests ads once the view is visible. Helper methods
`showContentPlayer()` and `hideContentPlayer()` toggle content visibility during
ad playback.

This example uses the `adTagURLString` constant variable to define the VAST ad
tag for the ad request, and the following components to manage IMA SDK:

- `adsLoader`: Handles ad requests and responses. We recommend using a single instance for the app's lifecycle.
- `adDisplayContainer`: Specifies the view for rendering ads.
- `adsManager`: Manages ad playback and listens for ad events.
- `contentPlayhead`: Tracks content progress to trigger mid-roll ad breaks.
- `adBreakActive`: Indicates if an ad break is playing to prevent seeking over ads.

## 5. Implement content playhead tracker and end-of-stream observer

To play mid-roll ads, IMA SDK must track the current position
of your video content. To pass the current position to IMA, create a class that
implements `IMAContentPlayhead`. If you use an `AVPlayer`, as this example
shows, IMA SDK provides the `IMAAVPlayerContentPlayhead` class to pass current
position info for you. If you don't use `AVPlayer`, implement
`IMAContentPlayhead` on a class of your own.

### Objective-C

```objective-c
- (void)setupContentPlayer {
  // Create a content video player. Create a playhead to track content progress so the SDK knows
  // when to play ads in a VMAP playlist.
  NSURL *contentURL = [NSURL URLWithString:kContentURLString];
  AVPlayer *player = [AVPlayer playerWithURL:contentURL];
  self.contentPlayerViewController = [[AVPlayerViewController alloc] init];
  self.contentPlayerViewController.player = player;
  self.contentPlayerViewController.view.frame = self.view.bounds;
  self.contentPlayhead =
      [[IMAAVPlayerContentPlayhead alloc] initWithAVPlayer:self.contentPlayerViewController.player];

  // Track end of content.
  AVPlayerItem *contentPlayerItem = self.contentPlayerViewController.player.currentItem;
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(contentDidFinishPlaying:)
                                               name:AVPlayerItemDidPlayToEndTimeNotification
                                             object:contentPlayerItem];

  // Attach content video player to view hierarchy.
  [self showContentPlayer];
}
```

### Swift

```swift
func setUpContentPlayer() {
  // Load AVPlayer with path to our content.
  let contentURL = URL(string: ViewController.contentURLString)!
  let player = AVPlayer(url: contentURL)
  playerViewController = AVPlayerViewController()
  playerViewController.player = player

  // Set up our content playhead and contentComplete callback.
  contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: player)
  NotificationCenter.default.addObserver(
    self,
    selector: #selector(ViewController.contentDidFinishPlaying(_:)),
    name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
    object: player.currentItem)

  showContentPlayer()
}
```

Set up a listener to call `contentComplete` on the `IMAAdsLoader` when
your content ends, using `AVPlayerItemDidPlayToEndTimeNotification`. Calling
`contentComplete` lets IMA SDK know when your content finishes playing to
display post-roll ads.

### Objective-C

```objective-c
- (void)contentDidFinishPlaying:(NSNotification *)notification {
  // Notify the SDK that the postrolls should be played.
  [self.adsLoader contentComplete];
}

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}
```

### Swift

```swift
@objc func contentDidFinishPlaying(_ notification: Notification) {
  adsLoader.contentComplete()
}
```

## 6. Initialize the ads loader and make an ads request

To request a set of ads, create an `IMAAdsLoader` instance.
This loader processes `IMAAdsRequest` objects associated with a
specified ad tag URL.

As a best practice, only maintain one instance of `IMAAdsLoader` for the entire
lifecycle of your app. To make additional ad requests, create a new
`IMAAdsRequest` object, but re-use the same `IMAAdsLoader`. For more
information, see the [IMA SDK FAQ](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/faq.md.txt#8).

### Objective-C

```objective-c
- (void)setupAdsLoader {
  self.adsLoader = [[IMAAdsLoader alloc] init];
  self.adsLoader.delegate = self;
}

- (void)requestAds {
  // Pass the main view as the container for ad display.
  self.adDisplayContainer = [[IMAAdDisplayContainer alloc] initWithAdContainer:self.view
                                                                viewController:self];
  IMAAdsRequest *request = [[IMAAdsRequest alloc] initWithAdTagUrl:kAdTagURLString
                                                adDisplayContainer:self.adDisplayContainer
                                                   contentPlayhead:self.contentPlayhead
                                                       userContext:nil];
  [self.adsLoader requestAdsWithRequest:request];
}
```

### Swift

```swift
func setUpAdsLoader() {
  adsLoader = IMAAdsLoader(settings: nil)
  adsLoader.delegate = self
}

func requestAds() {
  // Create ad display container for ad rendering.
  adDisplayContainer = IMAAdDisplayContainer(adContainer: self.view, viewController: self)
  // Create an ad request with our ad tag, display container, and optional user context.
  let request = IMAAdsRequest(
    adTagUrl: ViewController.adTagURLString,
    adDisplayContainer: adDisplayContainer,
    contentPlayhead: contentPlayhead,
    userContext: nil)

  adsLoader.requestAds(with: request)
}
```

## 7. Set up an ads loader delegate

On a successful load event, the `IMAAdsLoader` calls the `adsLoadedWithData`
method of its assigned delegate, passing it an instance of `IMAAdsManager`.
After you have the `IMAAdsManager` instance, initialize the ads manager,
which loads individual ads based on the ad tag URL's response.

For unsuccessful load events, set up an `IMAAdsLoader` delegate to handle
errors that occur during the loading process. If ads don't load, make sure
that media playback continues without ads to let users view the media content.

### Objective-C

```objective-c
#pragma mark - IMAAdsLoaderDelegate

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  // Initialize and listen to the ads manager loaded for this request.
  self.adsManager = adsLoadedData.adsManager;
  self.adsManager.delegate = self;
  [self.adsManager initializeWithAdsRenderingSettings:nil];
}

- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
  // Fall back to playing content.
  NSLog(@"Error loading ads: %@", adErrorData.adError.message);
  [self.contentPlayerViewController.player play];
}
```

### Swift

```swift
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
  // Grab the instance of the IMAAdsManager and set ourselves as the delegate.
  adsManager = adsLoadedData.adsManager
  adsManager.delegate = self
  adsManager.initialize(with: nil)
}

func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
  print("Error loading ads: \(adErrorData.adError.message ?? "No error message available.")")
  showContentPlayer()
  playerViewController.player?.play()
}
```

## 8. Set up an ads manager delegate

Lastly, to manage events and state changes, the ads manager requires a delegate
of its own. The `IMAAdManagerDelegate` has methods to handle ad events and
errors, as well as methods to trigger play and pause on your video content.

### Starting playback

The `didReceiveAdEvent` method handles all `IMAAdEvent` events.
For this basic example, listen for the `LOADED` event to tell the ads
manager to start playback of content and ads. The IMA SDK triggers the
`ICON_FALLBACK_IMAGE_CLOSED` event when the user closes an icon fallback
dialog after tapping an icon. After this action, ad playback resumes.

### Objective-C

```objective-c
#pragma mark - IMAAdsManagerDelegate

- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
  switch (event.type) {
    case kIMAAdEvent_LOADED: {
      // Play each ad once it has loaded.
      [adsManager start];
      break;
    }
    case kIMAAdEvent_ICON_FALLBACK_IMAGE_CLOSED: {
      // Resume ad after user has closed dialog.
      [adsManager resume];
      break;
    }
    default:
      break;
  }
}
```

### Swift

```swift
func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
  switch event.type {
  case IMAAdEventType.LOADED:
    // Play each ad once it has been loaded.
    adsManager.start()
  case IMAAdEventType.ICON_FALLBACK_IMAGE_CLOSED:
    // Resume playback after the user has closed the dialog.
    adsManager.resume()
  default:
    break
  }
}
```

### Handling errors

Add a handler for ad errors as well. If an error occurs, like in the previous
step, resume content playback.

### Objective-C

```objective-c
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error {
  // Fall back to playing content.
  NSLog(@"AdsManager error: %@", error.message);
  [self showContentPlayer];
  [self.contentPlayerViewController.player play];
}
```

### Swift

```swift
func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
  // Fall back to playing content
  print("AdsManager error: \(error.message ?? "No error message available.")")
  showContentPlayer()
  playerViewController.player?.play()
}
```

### Triggering play and pause events

The last two delegate methods you implement trigger play and
pause events on the underlying video content when IMA SDK requests them.
Triggering pause and play when IMA SDK requests them prevents the user from
missing portions of the video content when ads display.

### Objective-C

```objective-c
- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
  // Pause the content for the SDK to play ads.
  [self.contentPlayerViewController.player pause];
  [self hideContentPlayer];
  // Trigger an update to send focus to the ad display container.
  self.adBreakActive = YES;
  [self setNeedsFocusUpdate];
}

- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
  // Resume the content since the SDK is done playing ads (at least for now).
  [self showContentPlayer];
  [self.contentPlayerViewController.player play];
  // Trigger an update to send focus to the content player.
  self.adBreakActive = NO;
  [self setNeedsFocusUpdate];
}
```

### Swift

```swift
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
  // Pause the content for the SDK to play ads.
  playerViewController.player?.pause()
  hideContentPlayer()
  // Trigger an update to send focus to the ad display container.
  adBreakActive = true
  setNeedsFocusUpdate()
}

func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
  // Resume the content since the SDK is done playing ads (at least for now).
  showContentPlayer()
  playerViewController.player?.play()
  // Trigger an update to send focus to the content player.
  adBreakActive = false
  setNeedsFocusUpdate()
}
```

That's it! You're now requesting and displaying ads with IMA SDK. To learn
about additional SDK features, see the other guides or the
[samples on GitHub](https://github.com/googleads/googleads-ima-tvos-client-side).

## Next Steps

To maximize ad revenue on the tvOS platform, [request App Transparency and Tracking permission to use IDFA](https://developers.google.com/interactive-media-ads/docs/sdks/tvos/client-side/tvos14.md.txt).