> For the complete documentation index, see [llms.txt](https://docs.relevant-digital.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.relevant-digital.com/hb-analytics/setup/hba-instream-reporting-with-google-ima-sdk.md).

# HBA instream reporting with Google IMA SDK

## Learn how to enable HBA to pick up revenue and impressions when using Google's IMA SDK for instream video - either directly or via a 3rd party video player.

When using Google's [IMA SDK](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side) the [instreamTracking](https://docs.prebid.org/dev-docs/modules/instreamTracking.html) module for Prebid.js is not working. Instead it is necessary to "manually" register instream impressions using the **relevantDigital.Auction.registerImpressionByAdId()** function.

{% hint style="info" %}
This method is comparing ids in **VAST** XML for so called *Wrapper* ads - with the ids in Prebid bid responses. Potentially it might happen that the *same* instream ad (with the same id) is delivered e.g. via **Open Bidding** in **Google Ad Manager** instead. In this case the impression + revenue will incorrectly be attributed to Prebid in the headerbid reports.
{% endhint %}

#### When using the IMA SDK directly

We need to listen for the [**google.ima.AdEvent.Type.IMPRESSION**](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent) event and then extract the ad id(s) via the [Ad.getWrapperAdIds()](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.Ad#getWrapperAdIds) and [Ad.getAdId()](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.Ad#getAdId) functions that we'll then supply to **relevantDigital.Auction.registerImpressionByAdId()** .

First we create the event handler:

```javascript
// Our impression event handler
const onImp = (ev) => {
    window.relevantDigital = window.relevantDigital || {};
    relevantDigital.cmd = relevantDigital.cmd || [];
    relevantDigital.cmd.push(() => {
        // Loop through all ad ids starting from the innermost ad.
        // registerImpressionByAdId() will return true if it registered an impression
        const adIds = [
            ev.getAd().getAdId(),
            ...ev.getAd().getWrapperAdIds(),
        ];
        for (const id of adIds) {
            if (relevantDigital.Auction.registerImpressionByAdId(id)) {
                return;
            }
        }
    });
};
```

We can then use this **onImp** handler from the *existing* site code similar to this:

```javascript
const onAdsManagerLoaded = (ev) => {
  ...
  adsManager = ev.getAdsManager(...);

  // THE NEW LINE!
  adsManager.addEventListener(google.ima.AdEvent.Type.IMPRESSION, onImp);
};

...

// Create ads loader.
const adsLoader = new google.ima.AdsLoader(...);
// Listen and respond to ads loaded and error events.
adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
onAdsManagerLoaded, false);
```

#### When using the IMA SDK *indirectly* via 3'rd party video players

Unfortunately it's currently not possible to listen for the impression-events in a supported way from "outside" using the IMA SDK as there is no reliable way to get access to the **google.ima.AdsManager** instances.

It is *highly* recommended that you check the documentation for your existing video player to see if there is a way to to listen to impression events and get ad ids in the same manner as via [Ad.getWrapperAdIds()](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.Ad#getWrapperAdIds) and [Ad.getAdId()](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.Ad#getAdId). If so it should be possible create a listener very similar to the **onImp** listener above.

#### Quick workarounds

As a *last resort* it's possible to "inject" some JavaScript-functionality into the IMA SDK instead - in order to capture the impression events.

{% hint style="warning" %}
The solution below overwrites **google.ima.AdsLoader** etc. In worst case a subsequent update of the IMA SDK might interfere with this solution in such a way so that instream ads breaks completely!
{% endhint %}

The setting below requires that the first call to [relevantDigital.loadPrebid()](broken://spaces/thyujPhgXh1WtJZy8bjr/pages/28d0e242e33c72426e17b4dc7700f6629be560ea) is executed *before* the video player code creates the **google.ima.AdsLoader** object, in order to work.

![1-3](/files/85cbd2431dc6a9c5212eb72dd1b760c84b6fab4c)

If that timing requirement is not possible, or in case of uncertainty - the code below will do the same thing:

```javascript
// Helper-function that triggers a callback when a variable is set
// in an object. Our use-case will be to react when
// google.ima.AdsLoader is set, and replace it with an own version.
const inject = (obj, [name, ...rest], cb) => {
    let val = obj[name];
    const update = (newVal) => {
        if (rest.length) {
            inject(newVal, rest, cb);
        } else {
            newVal = cb(newVal)
        }
        val = newVal;
    }
    if (val) {
        update(val)
    } else {
        Object.defineProperty(obj, name, {
            get() {
                return val;
            },
            set: update,
        });
    }
}

inject(window, ['google', 'ima', 'AdsLoader'], (org) => {
    // Our impression event handler
    const onImp = (ev) => {
        window.relevantDigital = window.relevantDigital || {};
        relevantDigital.cmd = relevantDigital.cmd || [];
        relevantDigital.cmd.push(() => {
            // Loop through all ad ids starting from the innermost ad.
            // registerImpressionByAdId() will return
            // true if it registered an impression
            const adIds = [
                ev.getAd().getAdId(),
                ...ev.getAd().getWrapperAdIds(),
            ];
            for (const id of adIds) {
                if (relevantDigital.Auction
                    .registerImpressionByAdId(id))
                {
                    return;
                }
            }
        });
    };

    const onAdsManagerLoaded = (ev) => {
        const orgGet = ev.getAdsManager;
        ev.getAdsManager = function () {
            const mgr = orgGet.apply(this, arguments);
            if (mgr) {
                mgr.addEventListener(
                    google.ima.AdEvent.Type.IMPRESSION,
                    onImp,
                    false
                );
            }
            return mgr;
        }
    };

    // Create our own version of google.ima.AdsLoader
    const loader = function () {
        const res = org.apply(this, arguments);
        this.addEventListener(
           google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
           onAdsManagerLoaded,
           false
        );
        return res;
    };
    // Make our AdLoader "inherit" from the orignal AdLoader
    Object.assign(loader, org);
    loader.prototype = org.prototype;
    return loader;
});
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.relevant-digital.com/hb-analytics/setup/hba-instream-reporting-with-google-ima-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
