Custom Ad UI

This guide shows how to implement your own custom UI using the IMA SDK for HTML5. To do so, you need to disable the default UI, set up a new custom UI, and then populate the new UI with ad information obtained from the SDK. This guide builds on the simple sample for HTML5.

Add the UI elements to the DOM

Before you write any JavaScript, modify the HTML and stylesheet to add your new UI elements for the Learn More button, Skip Ad button, and countdown timer:

index.html

<div id="mainContainer">
  <div id="content">
    <video id="contentElement">
      <source src="https://storage.googleapis.com/gvabox/media/samples/stock.mp4"></source>
    </video>
  </div>
  <div id="adContainer"></div>
  <div id="customUi">
    <div id="adClick" class="customUIButton">Click me!</div>
    <div id="skipButton" class="customUIButton"></div>
    <div id="adCountdown"></div>
  </div>
</div>

Style.css

...
#customUI {
  display: none;
  text-align: center;
  width: 100%;
  height: 100%;
}

.customUIButton {
  position: absolute;
  right: 0px;
  background-color: red;
}

#adClick {
  top: 0px;
  width: 100px;
  height: 50px;
  line-height: 3em;
  cursor: pointer;
}

#skipButton {
  top: 213px;
  width: 150px;
  height: 35px;
  line-height: 2em;
  display: none;
}

#adCountdown {
  position: absolute;
  left: 0px;
  bottom: 10px;
  width: 120px;
  height: 20px;
  background-color: red;
}
...

You can style your UI differently if you wish; the above UI is merely an example.

Disable the built-in UI

Start by telling the SDK that you want it to disable its built-in UI.

ads.js

function onAdsManagerLoaded(adsManagerLoadedEvent) {
  const adsRenderingSettings = new google.ima.AdsRenderingSettings();
  adsRenderingSettings.disableUi = true;
  // videoContent should be set to the content video element.
  adsManager = adsManagerLoadedEvent.getAdsManager(
      videoContent, adsRenderingSettings);
  ...
}

Show and hide your custom UI when allowed

Some Google ads, such as AdSense ads, do not allow for a custom UI, and always render their own UI instead. In the stylesheet above the custom UI div is hidden by default. Show it only when the currently playing ad is hiding its UI and hide the custom UI after each ad in case the ad that follows doesn't allow a custom UI:

ads.js

let mainContainerDiv, currentAd, customUiDiv;
...
function setUpIMA() {
  customUiDiv = document.getElementById('customUi');
  mainContainerDiv = document.getElementById('mainContainer');
  mainContainerDiv.addEventListener('click', () => {
    // Need this to resume ads after clickthrough.
    adsManager.resume();
  });
  ...
}

function onAdsManagerLoaded(adsManagerLoadedEvent) {
  ...
  adsManager.addEventListener(
      google.ima.AdEvent.Type.SKIPPED,
      onAdEvent);
}

function onAdEvent(adEvent) {
  switch(adEvent.type) {
    ...
    case google.ima.AdEvent.Type.STARTED:
      currentAd = adEvent.getAd();
      if (currentAd.isUiDisabled()) {
        showCustomUi();
      }
      break;
    case google.ima.AdEvent.Type.COMPLETE:
    case google.ima.AdEvent.Type.SKIPPED:
      hideCustomUi();
      break;
  }
}

function showCustomUi() {
  customUiDiv.style.display = 'block';
}

function hideCustomUi() {
  customUiDiv.style.display = 'none';
}

Add logic to the Learn More button

The first UI component you need to wire up is the Learn More button. This element notifies the SDK when it has been clicked:

ads.js

let clickDiv;
...
function setUpIma() {
  ...
  clickDiv = document.getElementById('adClick');
  clickDiv.addEventListener('click', (e) => {
    // Prevent this from propagating to the customUi div. That would cause the ad to
    // resume immediately after the user clicks it, and we want it to pause.
    e.stopPropagation();
    adsManager.clicked();
  });
  ...
}

Add logic to the countdown timer

Next, wire up the countdown timer that is used in polling the remaining time in ads.

ads.js

let countdownDiv, uiUpdateInterval;
...
function setUpIma() {
  ...
  countdownDiv = document.getElementById('adCountdown');
  ...
}

function showCustomUi() {
  uiUpdateInterval = setInterval(updateUi, 100);
  customUiDiv.style.display = 'block';
}

function hideCustomUi() {
  if (uiUpdateInterval) {
    clearInterval(uiUpdateInterval);
  }
  customUiDiv.style.display = 'none';
}

function updateUi() {
  updateCountdown();
}

function updateCountdown() {
  let countdownText = 'Ad ';
  const adPodInfo = currentAd.getAdPodInfo();
  const totalAds = adPodInfo.getTotalAds();
  if (totalAds > 1) {
    const position = adPodInfo.getAdPosition();
    countdownText += position + ' of ' + totalAds;
  }
  const remainingTime = Math.ceil(adsManager.getRemainingTime());
  countdownText +=  ' (' + remainingTime + 's)';
  countdownDiv.innerText = countdownText;
}

Add logic to the Skip Ad button

Lastly, wire up the Skip Ad button. This button is only displayed for skippable ads and its countdown timer must reach 0 before it activates to enable the user to skip an ad.

ads.js

let skipDiv;
// Set this infinitely high to fail early <=0 checks.
let timeTillSkip = Number.POSITIVE_INFINITY;
...
function setUpIma() {
  ...
  skipButton = document.getElementById('skipButton');
  skipButton.addEventListener('click', (e) => {
    // Prevent this from propagating to the customUi div. That would cause the ad to
    // resume immediately after the user clicks it, and we want it to pause.
    e.stopPropagation();
    if (timeTillSkip <= 0) {
      adsManager.skip();
    }
  });
  ...
}

function showCustomUi() {
  if (currentAd.isSkippable()) {
    skipButton.innerText = '';
    skipButton.style.display = 'block';
  } else {
    skipButton.style.display = 'none';
  }
  ...
}

function updateUi() {
  updateCountdown();
  if (currentAd.isSkippable()) {
    updateSkip();
  }
}

function updateSkip() {
  const currentTime = currentAd.getDuration() - adsManager.getRemainingTime();
  timeTillSkip = Math.ceil(currentAd.getSkipTimeOffset() - currentTime);
  if (timeTillSkip > 0) {
    skipButton.innerText = "Skip this ad in " + timeTillSkip + '...';
    skipButton.style.cursor = 'default';
   } else {
    skipButton.innerText = "Skip ad";
    skipButton.style.cursor = 'pointer';
  }
}

Troubleshooting

Do you have a sample tag that is enabled for disabling ad UI?
You can copy the URL of this sample tag and paste it into your IMA implementation.
I can't disable the default UI.
Check to make sure that you set adsRenderingSettings.disableUi to true and pass it to the getAdsManager. Check to see that ad.isUiDisabled() returns true. In addition, your network must be enabled in Ad Manager to disable ad UI. If you are enabled, your VAST contains an Extension that looks like:
<Extension type="uiSettings">
<UiHideable>1</UiHideable>
</Extension>
If you are still having trouble, check with your account manager to confirm that you are enabled. Some ad types require a specific UI; these ads return with a <UiHideable> value of 0. If you encounter this, your trafficking team must make changes to ensure these ad types do not serve.