Appearance
VPAID Examples
A simple example that plays a TrueX ad through Google IMA (HTML5 SDK) with VPAID enabled, using the VPAID tag.
Live ads
The example requests a real ad when you select "Play ad". Choosing to interact, and staying with the ad, behaves like a real TrueX ad.
Live Example
Select "Play ad", choose "Yes" on the choice card, interact with the ad for about 30 seconds, and then select "Return to content". The log shows the events that Google IMA passes to your app.
What the Example Shows
- The choice card and the interactive ad are rendered by the VPAID unit, inside the ad container that IMA provides.
- Google IMA does not pass custom events such as
AdFreePodto your app. It passes the unit'sAdInteractionevents as anINTERACTIONevent, and the event'sidis theId- see When Custom Events Are Blocked. - The event you need is
TrueXClosedAfterCredit, shown in bold in the log. It fires when the user selects "Return to content", which appears after about 30 seconds and one interaction. That is the point to skip the rest of the ad pod. CONTENT_RESUME_REQUESTEDarrives when the whole ad break ends. That is the point to resume the content.
| VPAID event | Google IMA event |
|---|---|
AdLoaded | LOADED |
AdStarted, AdImpression | STARTED, IMPRESSION |
AdInteraction (with an Id) | INTERACTION (getAdData().id) |
AdStopped | COMPLETE (the ad ends), then CONTENT_RESUME_REQUESTED (the ad break ends) |
AdSkipped | SKIPPED |
AdError | AD_ERROR |
Setup
Enable VPAID in the IMA settings, and request the tag. IMA runs the VPAID unit for you:
js
google.ima.settings.setVpaidMode(
google.ima.ImaSdkSettings.VpaidMode.ENABLED
);
const displayContainer =
new google.ima.AdDisplayContainer(adContainer, videoElement);
displayContainer.initialize();
const adsLoader = new google.ima.AdsLoader(displayContainer);
const request = new google.ima.AdsRequest();
request.adTagUrl = 'https://get.truex.com/{placement_hash}/vast';
adsLoader.requestAds(request);Skipping the Ad Break
Skip the ad break when the user returns to the content after earning the credit, and resume the content when the ad break ends:
js
adsManager.addEventListener(
google.ima.AdEvent.Type.INTERACTION,
(event) => {
if (event.getAdData().id === 'TrueXClosedAfterCredit') {
// Skip the rest of the ad pod
adsManager.discardAdBreak();
}
}
);
adsManager.addEventListener(
google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED,
() => {
// The ad break is over
videoElement.play();
}
);discardAdBreak
adsManager.discardAdBreak() discards only the current ad break, and keeps the later ones. It does nothing unless the ad request returned a VMAP or playlist response, such as an ad pod. With a single ad, as in this example, the content resumes when the ad ends.
Full Listing
The page that runs in the live example above:
html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>VPAID demo player</title>
<style>
html, body { margin: 0; height: 100%; background: #000; }
#stage { position: relative; width: 100%; height: 100%; }
#content, #adContainer {
position: absolute; top: 0; left: 0;
width: 100%; height: 100%;
}
</style>
</head>
<body>
<div id="stage">
<video id="content" playsinline controls></video>
<div id="adContainer"></div>
</div>
<script
src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"
></script>
<script>
const CONTENT_URL =
'https://storage.googleapis.com/gvabox/media/samples/stock.mp4';
const video = document.getElementById('content');
video.src = CONTENT_URL;
const container = document.getElementById('adContainer');
let displayContainer;
let adsLoader;
let adsManager;
// Sends an event to the docs page, which shows it in the log
function sendMessageToParentFrame(name, data) {
parent.postMessage(
{ source: 'vpaid-demo', name: name, data: data },
location.origin
);
}
// Hide the ad container, so that it does not cover the video
function resumeContent() {
container.style.display = 'none';
video.play();
}
function destroyAds() {
if (adsManager) {
adsManager.destroy();
adsManager = undefined;
}
if (adsLoader) {
adsLoader.destroy();
adsLoader = undefined;
}
if (displayContainer) {
displayContainer.destroy();
displayContainer = undefined;
}
}
function onAdEvent(name, adEvent) {
const adData = adEvent.getAdData();
const isInteraction = name === 'INTERACTION' && adData;
const id = isInteraction ? adData.id : undefined;
sendMessageToParentFrame(name, id ? { id: id } : undefined);
// The user was credited and selected "Return to content":
// skip the rest of the ad break
if (id === 'TrueXClosedAfterCredit') {
sendMessageToParentFrame('app', {
message: 'credited: discard the ad break'
});
adsManager.discardAdBreak();
}
// CONTENT_RESUME_REQUESTED is the end of the whole ad break
if (name === 'CONTENT_RESUME_REQUESTED') {
sendMessageToParentFrame('app', {
message: 'break done: resume content'
});
resumeContent();
}
}
function onAdsManagerLoaded(event) {
adsManager = event.getAdsManager(video);
const types = Object.keys(google.ima.AdEvent.Type);
types.forEach(function (name) {
if (name === 'AD_PROGRESS' || name === 'DURATION_CHANGE') {
return;
}
adsManager.addEventListener(
google.ima.AdEvent.Type[name],
function (adEvent) {
onAdEvent(name, adEvent);
}
);
});
adsManager.addEventListener(
google.ima.AdErrorEvent.Type.AD_ERROR,
onAdError
);
adsManager.init(
video.clientWidth,
video.clientHeight,
google.ima.ViewMode.NORMAL
);
adsManager.start();
}
function onAdError(errorEvent) {
const message = errorEvent.getError().getMessage();
sendMessageToParentFrame('AD_ERROR', { message: message });
destroyAds();
resumeContent();
}
function playAd(tag) {
destroyAds();
video.pause();
video.currentTime = 0;
container.style.display = 'block';
// Let IMA run the VPAID unit
google.ima.settings.setVpaidMode(
google.ima.ImaSdkSettings.VpaidMode.ENABLED
);
displayContainer =
new google.ima.AdDisplayContainer(container, video);
displayContainer.initialize();
adsLoader = new google.ima.AdsLoader(displayContainer);
adsLoader.addEventListener(
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
onAdsManagerLoaded
);
adsLoader.addEventListener(
google.ima.AdErrorEvent.Type.AD_ERROR,
onAdError
);
const request = new google.ima.AdsRequest();
request.adTagUrl = tag;
request.linearAdSlotWidth = video.clientWidth;
request.linearAdSlotHeight = video.clientHeight;
sendMessageToParentFrame('app', {
message: 'ad request: ' + tag
});
adsLoader.requestAds(request);
}
function stop() {
destroyAds();
video.pause();
video.currentTime = 0;
container.style.display = 'none';
}
// The docs page sends { type: 'play', tag } or { type: 'stop' }
window.addEventListener('message', function (event) {
if (event.origin !== location.origin || !event.data) {
return;
}
if (event.data.type === 'play') {
playAd(event.data.tag);
} else if (event.data.type === 'stop') {
stop();
}
});
sendMessageToParentFrame('ready');
</script>
</body>
</html>
