Skip to content

Advertising in the Video Center player

The Video Center player supports pre-roll ads through Google Ad Manager. You can tailor ad logic for each video using a JavaScript function. The system makes an ad request per video right before the video begins playing.

The ad tag URL

By default, the video player looks for a value located at window.PoWaSettings.advertising.adTag. The value can be either a string or a function. If the value is a string and it begins with window, the player then looks at that location and restarts the same process (for example, is window.other.location.adTag a string or a function?). If the ultimate value is a string, the system assumes that string is an ad tag URL. If the ultimate value is a function, the player provides an object ({powa, videoData}) containing the powa object (for example, the player) and the JSON object of the current video (videoData).

The value returned by adTag must be either of the following:

  • An ad tag URL (string).
  • A falsey value (also written as falsy). For example, an empty string or null.
  • A Promise that resolves to either of those values or rejects.

If the value returned by adTag is falsey, then the system doesn’t make an ad request for the current video. If the system returns a string, it passes the string to the Google IMA plugin to make the actual ad request.

Ad timeouts

The player also sets ad timeouts, which you can customize. You can choose from three standard timeouts:

  • vastLoad. This timeout runs for each ad wrapper and defaults to 5 seconds. For example, if an ad has three wrappers, the maximum allowed load time is 15 seconds.
  • videoLoad. This timeout runs on the fetch for the ad video and defaults to 8 seconds.
  • adStart. This timeout overrides the other timeouts and runs at the start of the ad request. Defaults to 5 seconds.

Additional settings

You can configure the location with the locale setting (for example, es, fr, it). You can set the maximum number of ad wrappers with the maxAdWrappers setting (default: 4). By default, the player supports VPAID ads, but you can disable this setting with the vpaidEnabled property.

The following is an example of additional settings for advertising with the Video Center player:

window.PoWaSettings.advertising = {
vpaidEnabled: true, // default
maxWrappers: 4, // default
locale: '', // default, '' defaults to 'en', e.g. 'es', 'fr', etc.
};

Examples

This section provides examples of values for window.PoWaSettings.advertising.adTag.

Simple static string

window.PoWaSettings = window.PoWaSettings || {};
window.PoWaSettings.advertising = window.PoWaSettings.advertising || {}
window.PoWaSettings.advertising.adTag = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=';

Simple string function

window.PoWaSettings = window.PoWaSettings || {};
window.PoWaSettings.advertising = window.PoWaSettings.advertising || {}
window.PoWaSettings.advertising.adTag = () => 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=';

Function with Logic

window.PoWaSettings = window.PoWaSettings || {};
window.PoWaSettings.advertising = window.PoWaSettings.advertising || {};
window.PoWaSettings.advertising.adTag = () => {
let everyOtherVideo = 0;
return ({powa, videoData}) => {
const videoAdZone = videoData.additional_properties.advertising.videoAdZone;
const commercialAdNode = videoData.additional_properties.advertising.commercialAdNode;
const adTag = `https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/${ commercialAdNode }${ videoAdZone }&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=`;
return everyOtherVideo++ % 2 === 0 ? adTag : null;
}
}();

Asynchronous function

window.PoWaSettings.advertising.adTag = () => {
return new Promise((resolve, reject) => {
const adTagURL = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=';
setTimeout(() => {
resolve(adTagURL);
}, 100);
});
};

Changing location

window.PoWaSettings.advertising.adTag = 'window.other.location.adTag';
window.other.location.adTag = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=';

Ad timeouts

window.PoWaSettings.advertising.timeouts = {
standard: {
vastLoad: 5, // default
videoLoad: 8, // default
adStart: 5, // default
}
};

Custom ad timeouts

window.PoWaSettings.advertising.timeouts = {
standard: {
// give the first player on a page short ad timeouts
vastLoad: powa => powa.getDataset().powaIndex === 0 ? 3 : 5,
videoLoad: powa => powa.getDataset().powaIndex === 0 ? 3 : 8,
adStart: powa => powa.getDataset().powaIndex === 0 ? 5 : 25,
}
};

Inserting ads server-side

Instead of running an ad before a video plays, you can stitch ads into streams server-side. This technology has many names: Server-Side Ad Insertion (SSAI), Dynamic Ad Insertion (DAI), and ad stitching. The benefit to ad stitching is that this process inserts ads into a live stream similar to a commercial break on broadcast television.

Ad stitching tailors ads to the individual watching the stream by setting the ad tag request parameters on the client side.

Arc XP leverages AWS MediaTailor for ad stitching with client-side reporting of ad events. You can insert ads into live streams as long as that live stream contains cue points to indicate a window when ads can be inserted. You can also insert ads into video-on-demand (VOD) streams as pre-roll. VOD does not require cue points. If the initial request to MediaTailor fails, the player resolves to run client-side ads.

The client-side ad insertion process starts very early in the player lifecycle and consists of the following steps:

  1. The player checks if ad insertion is enabled for the video in question. If ad insertion is enabled, the system then obtains a unique video steam for the current end user.

  2. The player obtains the ad parameters the system sends to MediaTailor on the initial request.
    The player leverages the window.PoWaSettings.advertising.adTag function to obtain these parameters. The adTag function returns an ad tag request URL string (for example, "https://adserver.com/Ads?Key1=Val1&Key2=Val2").

  3. The player takes the query string parameters off of the ad tag URL (for example, "key1=val1&key2=val2") and convert them to a JSON object (for example, {"key1″: "val1", "key2": "val2"}).

  4. The player provides the adTag function with a Boolean adInsertion property on the object that is passed in to it (for example, adTag({adInsertion, powa, videoData})) to facilitate the customization of the ad tag request URL for ad insertion.

  5. The player makes a request to MediaTailor.

    On the server, MediaTailor takes the ad parameters that we send and parameters that are available server-side (like client IP) and constructs a new ad tag request URL. The template the system uses to create this server-side ad request URL is the Ad Decision Server URL field in Video Center. This new server-side ad tag request URL is what the system uses to request all of the ads that are inserted into the stream.

  6. MediaTailor responds with a unique video stream URL and a separate tracking URL from which we obtain information about the ads that have been inserted into this stream.

  7. After the user starts the stream and is receiving video, the player makes a call to the tracking URL to obtain information about any available ads.

    VOD streams require just one call to the tracking URL for any potential pre-roll ads. Live streams require additional calls as the stream progresses. The hls.js file provides visibility to the cue points that were added to the stream and the player sends additional requests to the tracking URL when it encounters a cue point. Running HLS natively (like mobile Safari), the player does not have visibility to the stream’s cue points, so the player sends additional requests to the tracking URL on an interval.

  8. The player receives information from the tracking URL. The response details when the ad starts, the ad’s duration, and any tracking events that the player is responsible for.

  9. The player waits for any stream events (like ad start, 25% complete, and more) or user events (like click through, mute, and pause) and sends the related tracking beacons.

The player supports two request timeouts for our MediaTailor implementation: a two-second timeout for the initial session request and a five-second timeout for the tracking requests. You can customize these timeout requests with window.PoWaSettings.advertising.mediaTailor.session and window.PoWaSettings.advertising.mediaTailor.tracking.

VPAID ads

The player supports Video Player-Ad Interface Definition (VPAID) ads through MediaTailor. MediaTailor can stitch in some VPAID ads, in which case the player treats the ad the same as any other stitched ad. When a VPAID ad is stitched in, the player flags the adMeta object with stitchedVPAID: true. If MediaTailor cannot stitch the ad into the stream, the player runs VPAID ad client-side. A VPAID is denoted by the VPAID property in the ad’s adMeta object.

Example

window.PoWaSettings = window.PoWaSettings || {};
window.PoWaSettings.advertising = window.PoWaSettings.advertising || {};
window.PoWaSettings.advertising.adTag = ({adInsertion, powa, videoData}) => {
if (adInsertion) {
return 'https://example.com/ad?key1=val1&key2=val2&ad_insertion=true';
}
else {
return 'https://example.com/ad?key1=val1&key2=val2&ad_insertion=false';
}
};
window.PoWaSettings.advertising.timeouts = window.PoWaSettings.advertising.timeouts || {};
window.PoWaSettings.advertising.timeouts.mediaTailor = {
session: 3 * 1000, // three seconds
tracking: 10 * 1000, // ten seconds
};
window.addEventListener('powaReady' event => {
new MediaTailor({
powa: event.detail.powa,
// how long to store ad data locally
// e.g. for DVR functionality during a live stream
adMemoryDuration: 60 * 60, // in seconds, default: one hour
// how often to request ad data when using native HLS
// our live streams are usually 6-second chunks
// and we usually buffer three chunks
// 6 * 3 = 18
trackingInterval: 18, // in seconds, default: 18 seconds
});
})

Ad bar

If enabled, the ad bar appears during ads and offers countdowns and controls. You can enable the ad bar with the default configuration by setting window.PoWaSettings.advertising.adBar = true or with a configuration through window.PoWaSettings.advertising.adBar = {...}.

By default, the ad bar provides controls to play or pause, mute or unmute, and skip the ad. The ad bar also displays an ad countdown for the duration of the ad. The ad bar defaults to a 15-second skip offset to enable the skip control. The ad bar also displays a skip countdown to count down until the skip option is available. A two-second threshold is factored into the skip calculation so that ads slightly longer than the skip offset do not trigger the skip control.

Example

window.PoWaSettings = window.PoWaSettings || {};
PoWaSettings.advertising = PoWaSettings.advertising || {};
PoWaSettings.advertising.adBar = true;

Customization

You can customize the ad bar by defining style and template properties in the PoWaSettings.advertising.adBar object. This object also accepts Boolean values to enable or disable play or pause controls, mute or unmute controls, the ad countdown, and the skip control. This object is also where you can adjust the length of your skipOffset and skipThreshold. You can customize the language that the ad bar displays with the adSkipText, adCountdownTemplate, and adSkipCountdownTemplate properties.

The checkSizing function is run on every PoWa.EVENTS.TIME update to the ad bar and is employed to hide the ad countdown and skip countdown elements if those elements overlap the controls on the ad bar. In other words, this function checks if the player is too small to display all of the ad bar’s elements and conditionally hides one or both countdowns to ensure that the more important elements are visible.

The ad bar resizes the ad so that the ad bar does not overlay the ad. You can disable this function, and the default style of the ad bar has a level of transparency such that the ad is not completely obscured. Some advertisers take exception to the ad being obscured at all, so the default is to resize. To disable the setting, set window.PoWaSettings.advertising.adBar.shrinkAd = false. Otherwise, shrinkAd must be a function that returns an object with values needed to resize the ad. The shrinkAdCSS function accepts the object created by shrinkAd and returns a JavaScript CSS object to be applied to the ad to resize it.

The following is an example of ad bar customization using several properties:

// defaults
PoWaSettings.advertising.adBar = {
// enable play/pause control
playControl: true,
// enable mute/unmute control
muteControl: true,
// enable ad countdown
adCountdown: true,
// enable skip control
skipControl: true,
// allow user to skip after N seconds
skipOffset: 15,
// fudge factor to prevent showing 'skip' for ads slightly longer than skipOffset
skipThreshold: 2,
// text displayed on 'skip control'
adSkipText: 'Skip',
// receives {duration, elapsed, remaining, skipOffset, skipThreshold}
adCountdownTemplate: timing => `This ad will end in ${ Math.ceil(timing.remaining) } seconds`,
// receives {duration, elapsed, remaining, skipOffset, skipThreshold}
adSkipCountdownTemplate: timing => `You can skip this ad in ${ Math.ceil(timing.skipOffset - (timing.duration - timing.remaining)) } seconds`,
// ensure countdowns aren't too long, else, hide them
// receives object of all ad bar elements wrapped in PoWaPack objects
checkSizing: adBarElements => {
const $controls = adBarElements.$controls;
const $countdown = adBarElements.$countdown;
const $skipContainer = adBarElements.$skipContainer;
const $skipCountdown = adBarElements.$skipCountdown;
const adControlsRight = $controls.position().left + $controls.width();
const adCountdownRight = $countdown.position().left + $countdown.width();
const adSkipContainerLeft = $skipContainer.position().left;
if (adCountdownRight > adSkipContainerLeft) {
$countdown.addClass(classes.hidden);
}
if (adControlsRight > adSkipContainerLeft) {
$skipCountdown.addClass(classes.hidden);
}
},
// receives adBar = {height, width}, player = {fullscreen, height, width}
shrinkAd: (adBar, player) => {
const sides = (adBar.height * (player.width/player.height)) / 2;
return {
top: adBar.height,
bottom: 0,
left: sides,
right: sides,
height: player.height - adBar.height,
width: player.width - (2 * sides),
};
},
// receives {top, bottom, left, right, height, width} (from shrinkAd)
shrinkAdCSS: shrinkBy => {
return {
top: `${ shrinkBy.top }px`,
left: `${ shrinkBy.left }px`,
width: `${ shrinkBy.width }px`,
height: `${ shrinkBy.height }px`
};
},
style: config => `
.powa-sell-bar {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 22px;
display: flex;
align-items: center;
justify-content: flex-start;
pointer-events: auto;
font-family: Helvetica;
color: rgb(240, 248, 255);
background-color: rgba(0, 0, 0, 0.7);
z-index: 2;
}
.powa-sell-bar-controls {
display: flex;
align-items: center;
justify-content: flex-start;
margin: 0;
padding: 0;
}
.powa-sell-bar-control {
display: flex;
align-items: center;
justify-content: center;
width: 20px;
}
.powa-sell-bar-control:active {
color: rgb(153, 50, 204);
}
.powa-sell-bar-countdown {
font-size: 14px;
font-weight: 400;
line-height: normal;
margin: 0 3px 0 3px;
padding: 0;
}
.powa-sell-bar-skip-container {
position: absolute;
right: 0px;
display: flex;
justify-content: flex-end;
padding: 0 3px 0 3px;
}
.powa-sell-bar-skip-countdown {
font-size: 14px;
font-weight: 400;
line-height: normal;
margin: 0;
padding: 0;
}
.powa-sell-bar-skip {
font-size: 14px;
font-weight: 400;
cursor: pointer;
line-height: normal;
margin: 0;
padding: 0;
}
.powa-sell-bar-skip:hover {
text-decoration: underline;
}
.powa-sell-bar-skip:active {
color: rgb(153, 50, 204);
}
.powa-sell-bar-hidden {
display: none;
}
`,
template: config => `
<div class="powa-sell-bar">
<span class="powa-sell-bar-controls">
<span class="powa-sell-bar-control powa-sell-bar-play-pause powa-click-play-pause-click">
<span class="powa-sell-bar-play powa-sell-bar-hidden" aria-label="Play"><i class="fa fa-play" aria-hidden="true"></i></span>
<span class="powa-sell-bar-pause" aria-label="Pause"><i class="fa fa-pause" aria-hidden="true"></i></span>
</span>
<span class="powa-sell-bar-control powa-sell-bar-mute-unmute powa-click-mute-unmute-click">
<span class="powa-sell-bar-mute" aria-label="Mute"><i class="fa fa-volume-up" aria-hidden="true"></i></span>
<span class="powa-sell-bar-unmute powa-sell-bar-hidden" aria-label="Unmute"><i class="fa fa-volume-off" aria-hidden="true"></i></span>
</span>
</span>
<span class="powa-sell-bar-countdown powa-sell-bar-hidden"></span>
<span class="powa-sell-bar-skip-container">
<span class="powa-sell-bar-skip-countdown powa-sell-bar-hidden"></span>
<span class="powa-sell-bar-skip powa-click-skip-click powa-sell-bar-hidden">Skip</span>
</span>
</div>
`,
};

The following is an example of an Ad bar in Spanish without the play or pause control:

window.PoWaSettings.advertising.adBar = {
playControl: false,
adSkipText: 'Omitir anuncio',
adCountdownTemplate: timing => {
return `Anuncio: ${ Math.ceil(timing.remaining) } segundos`;
},
adSkipCountdownTemplate: timing => {
return `Podrá saltar el anuncio en ${ Math.ceil(timing.skipOffset - (timing.duration - timing.remaining)) } segundos`;
},
};