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 asfalsy
). 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 to5
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 to8
seconds.adStart
. This timeout overrides the other timeouts and runs at the start of the ad request. Defaults to5
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:
-
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.
-
The player obtains the ad parameters the system sends to MediaTailor on the initial request.
The player leverages thewindow.PoWaSettings.advertising.adTag
function to obtain these parameters. TheadTag
function returns an ad tag request URL string (for example,"https://adserver.com/Ads?Key1=Val1&Key2=Val2"
). -
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"}
). -
The player provides the
adTag
function with a BooleanadInsertion
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. -
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.
-
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.
-
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. -
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.
-
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:
// defaultsPoWaSettings.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`; },};