> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Video Ad Tracking

> Track video advertisement engagement and performance

Track video advertisement viewing to understand ad engagement and enable ad-based segmentation.

<CardGroup cols={2}>
  <Card title="Implementation" href="#tracking-video-ads" icon="rectangle-ad" />

  <Card title="IMA Integration" href="#google-ima-integration" icon="google" />
</CardGroup>

## Overview

Video ad tracking enables:

* **Ad impression tracking** when ads start
* **Ad completion tracking** when ads finish
* **Ad engagement metrics** for targeting
* **Ad-based cohort qualification**

## Tracking Video Ads

Track video ad events using the standard event tracking API:

<CodeGroup>
  ```swift Swift theme={"dark"}
  import Permutive_iOS

  class VideoAdTracker {

      func trackAdImpression(ad: Ad, position: AdPosition) {
          try? Permutive.shared.track(
              event: "VideoAdImpression",
              properties: try? EventProperties([
                  "ad_id": ad.id,
                  "ad_title": ad.title,
                  "ad_duration": ad.duration,
                  "ad_position": position.rawValue,  // "pre-roll", "mid-roll", "post-roll"
                  "advertiser": ad.advertiser,
                  "campaign_id": ad.campaignId
              ])
          )
      }

      func trackAdComplete(ad: Ad, watchedPercentage: Float) {
          try? Permutive.shared.track(
              event: "VideoAdComplete",
              properties: try? EventProperties([
                  "ad_id": ad.id,
                  "ad_title": ad.title,
                  "watched_percentage": watchedPercentage,
                  "completed": watchedPercentage >= 0.95
              ])
          )
      }

      func trackAdSkipped(ad: Ad, skippedAtSeconds: Double) {
          try? Permutive.shared.track(
              event: "VideoAdSkipped",
              properties: try? EventProperties([
                  "ad_id": ad.id,
                  "skipped_at_seconds": skippedAtSeconds,
                  "total_duration": ad.duration
              ])
          )
      }

      func trackAdClicked(ad: Ad) {
          try? Permutive.shared.track(
              event: "VideoAdClicked",
              properties: try? EventProperties([
                  "ad_id": ad.id,
                  "click_url": ad.clickThroughUrl
              ])
          )
      }
  }

  enum AdPosition: String {
      case preRoll = "pre-roll"
      case midRoll = "mid-roll"
      case postRoll = "post-roll"
  }
  ```

  ```objectivec Objective-C theme={"dark"}
  @interface VideoAdTracker : NSObject
  - (void)trackAdImpressionWithAd:(Ad *)ad position:(NSString *)position;
  - (void)trackAdCompleteWithAd:(Ad *)ad watchedPercentage:(float)watchedPercentage;
  - (void)trackAdSkippedWithAd:(Ad *)ad skippedAtSeconds:(double)skippedAtSeconds;
  - (void)trackAdClickedWithAd:(Ad *)ad;
  @end

  @implementation VideoAdTracker

  - (void)trackAdImpressionWithAd:(Ad *)ad position:(NSString *)position {
      NSError *error = nil;
      PermutiveEventProperties *props = [[PermutiveEventProperties alloc]
          init:@{
              @"ad_id": ad.adId,
              @"ad_title": ad.title,
              @"ad_duration": @(ad.duration),
              @"ad_position": position,
              @"advertiser": ad.advertiser,
              @"campaign_id": ad.campaignId
          }
          error:&error];

      [Permutive.shared trackWithEvent:@"VideoAdImpression" properties:props error:&error];
  }

  - (void)trackAdCompleteWithAd:(Ad *)ad watchedPercentage:(float)watchedPercentage {
      NSError *error = nil;
      PermutiveEventProperties *props = [[PermutiveEventProperties alloc]
          init:@{
              @"ad_id": ad.adId,
              @"watched_percentage": @(watchedPercentage),
              @"completed": @(watchedPercentage >= 0.95)
          }
          error:&error];

      [Permutive.shared trackWithEvent:@"VideoAdComplete" properties:props error:&error];
  }

  @end
  ```
</CodeGroup>

## Google IMA Integration

Integrate with Google Interactive Media Ads (IMA) SDK:

```swift theme={"dark"}
import GoogleInteractiveMediaAds
import Permutive_iOS

class VideoPlayerViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
    private var adsLoader: IMAAdsLoader!
    private var adsManager: IMAAdsManager?

    override func viewDidLoad() {
        super.viewDidLoad()
        setupAdsLoader()
    }

    private func setupAdsLoader() {
        adsLoader = IMAAdsLoader(settings: nil)
        adsLoader.delegate = self
    }

    func requestAds() {
        // Include Permutive targeting in ad request
        let adRequest = GAMRequest()
        adRequest.customTargeting = Permutive.shared.googleCustomTargeting(
            adTargetable: pageTracker  // Include if using PageTracker
        )

        let adDisplayContainer = IMAAdDisplayContainer(
            adContainer: adContainerView,
            viewController: self
        )

        let request = IMAAdsRequest(
            adTagUrl: adTagUrl,
            adDisplayContainer: adDisplayContainer,
            contentPlayhead: contentPlayhead,
            userContext: nil
        )

        adsLoader.requestAds(with: request)
    }

    // MARK: - IMAAdsManagerDelegate

    func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
        switch event.type {
        case .STARTED:
            trackAdStarted(event.ad)

        case .COMPLETE:
            trackAdCompleted(event.ad)

        case .SKIPPED:
            trackAdSkipped(event.ad)

        case .CLICKED:
            trackAdClicked(event.ad)

        case .FIRST_QUARTILE:
            trackAdProgress(event.ad, quartile: 1)

        case .MIDPOINT:
            trackAdProgress(event.ad, quartile: 2)

        case .THIRD_QUARTILE:
            trackAdProgress(event.ad, quartile: 3)

        default:
            break
        }
    }

    private func trackAdStarted(_ ad: IMAAd?) {
        guard let ad = ad else { return }

        try? Permutive.shared.track(
            event: "VideoAdStarted",
            properties: try? EventProperties([
                "ad_id": ad.adId,
                "ad_title": ad.adTitle,
                "duration": ad.duration,
                "is_skippable": ad.isSkippable,
                "ad_system": ad.adSystem,
                "advertiser": ad.advertiserName
            ])
        )
    }

    private func trackAdCompleted(_ ad: IMAAd?) {
        guard let ad = ad else { return }

        try? Permutive.shared.track(
            event: "VideoAdComplete",
            properties: try? EventProperties([
                "ad_id": ad.adId,
                "ad_title": ad.adTitle,
                "duration": ad.duration
            ])
        )
    }

    private func trackAdSkipped(_ ad: IMAAd?) {
        guard let ad = ad else { return }

        try? Permutive.shared.track(
            event: "VideoAdSkipped",
            properties: try? EventProperties([
                "ad_id": ad.adId,
                "ad_title": ad.adTitle
            ])
        )
    }

    private func trackAdClicked(_ ad: IMAAd?) {
        guard let ad = ad else { return }

        try? Permutive.shared.track(
            event: "VideoAdClicked",
            properties: try? EventProperties([
                "ad_id": ad.adId
            ])
        )
    }

    private func trackAdProgress(_ ad: IMAAd?, quartile: Int) {
        guard let ad = ad else { return }

        try? Permutive.shared.track(
            event: "VideoAdProgress",
            properties: try? EventProperties([
                "ad_id": ad.adId,
                "quartile": quartile,
                "percentage": quartile * 25
            ])
        )
    }
}
```

## Ad Pod Tracking

Track ad pods (multiple ads in sequence):

```swift theme={"dark"}
class AdPodTracker {

    func trackAdPodStarted(podIndex: Int, adCount: Int) {
        try? Permutive.shared.track(
            event: "AdPodStarted",
            properties: try? EventProperties([
                "pod_index": podIndex,
                "ad_count": adCount,
                "position": podIndex == 0 ? "pre-roll" : "mid-roll"
            ])
        )
    }

    func trackAdPodComplete(podIndex: Int, adsWatched: Int, totalAds: Int) {
        try? Permutive.shared.track(
            event: "AdPodComplete",
            properties: try? EventProperties([
                "pod_index": podIndex,
                "ads_watched": adsWatched,
                "total_ads": totalAds,
                "completion_rate": Float(adsWatched) / Float(totalAds)
            ])
        )
    }
}
```

## Combining with Content Tracking

Track both content and ads in a video player:

```swift theme={"dark"}
class VideoPlayerController {
    private var mediaTracker: MediaTrackerProtocol?
    private var isPlayingAd = false

    // Content tracking
    func onContentPlay() {
        guard !isPlayingAd else { return }
        try? mediaTracker?.play()
    }

    func onContentPause() {
        guard !isPlayingAd else { return }
        mediaTracker?.pause()
    }

    // Ad tracking
    func onAdBreakStarted() {
        isPlayingAd = true
        mediaTracker?.pause()  // Pause content tracking during ads
    }

    func onAdBreakEnded() {
        isPlayingAd = false
        // Content will resume with onContentPlay()
    }

    func onAdStarted(_ ad: Ad) {
        trackAdImpression(ad: ad)
    }

    func onAdCompleted(_ ad: Ad) {
        trackAdComplete(ad: ad)
    }

    private func trackAdImpression(ad: Ad) {
        try? Permutive.shared.track(
            event: "VideoAdImpression",
            properties: try? EventProperties([
                "ad_id": ad.id,
                "ad_title": ad.title
            ])
        )
    }

    private func trackAdComplete(ad: Ad) {
        try? Permutive.shared.track(
            event: "VideoAdComplete",
            properties: try? EventProperties([
                "ad_id": ad.id
            ])
        )
    }
}
```

## Event Schema

Common video ad event properties:

| Property             | Type    | Description                         |
| -------------------- | ------- | ----------------------------------- |
| `ad_id`              | String  | Unique ad identifier                |
| `ad_title`           | String  | Ad title or description             |
| `duration`           | Number  | Ad duration in seconds              |
| `ad_position`        | String  | "pre-roll", "mid-roll", "post-roll" |
| `advertiser`         | String  | Advertiser name                     |
| `campaign_id`        | String  | Campaign identifier                 |
| `is_skippable`       | Boolean | Whether ad can be skipped           |
| `watched_percentage` | Number  | Percentage of ad watched (0-1)      |

<Warning>
  Ensure your event properties match your Permutive dashboard schema. Mismatched properties result in event rejection.
</Warning>

## tvOS Considerations

<Info>
  **tvOS Note:** Video ad tracking works the same on tvOS. Use the same event tracking APIs with your TVML or UIKit video player.
</Info>

## Best Practices

<Tabs>
  <Tab title="Do">
    * Track ad impressions when ads actually start playing
    * Include ad position (pre-roll, mid-roll, post-roll)
    * Track quartile progress for engagement analysis
    * Pause content tracking during ad breaks
    * Include meaningful ad metadata
  </Tab>

  <Tab title="Don't">
    * Don't track impression before ad is visible
    * Don't include PII in ad properties
    * Don't track duplicate events
    * Don't mix content and ad events incorrectly
  </Tab>
</Tabs>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Ad events not appearing">
    **Problem:** Video ad events not in dashboard.

    **Solutions:**

    * Enable debug logging
    * Check event names match schema
    * Verify SDK is initialized
    * Look for schema validation errors
  </Accordion>

  <Accordion title="Targeting not working for ads">
    **Problem:** Permutive targeting not applied to ad requests.

    **Solutions:**

    * Ensure `googleCustomTargeting` is called before ad request
    * Verify PageTracker is active when requesting ads
    * Check targeting dictionary is applied to GAMRequest
  </Accordion>
</AccordionGroup>

## Related Documentation

<CardGroup cols={2}>
  <Card title="Video Tracking" icon="video" href="/sdks/mobile/ios/features/video-tracking">
    Track video content
  </Card>

  <Card title="Google Ad Manager" icon="google" href="/sdks/mobile/ios/integrations/google-ad-manager">
    GAM integration
  </Card>

  <Card title="Event Tracking" icon="bolt" href="/sdks/mobile/ios/features/event-tracking">
    Custom event tracking
  </Card>

  <Card title="Cohorts" icon="users" href="/sdks/mobile/ios/core-concepts/cohorts-and-activations">
    Ad-based targeting
  </Card>
</CardGroup>
