Overview
IMA DAI SDK stitches your video content and ads into a single stream, independent of a web page or app, and removes the ad request and ad response process from the SDK. This reduces the likelihood of client-side errors and produces a seamless TV-like experience without latency or buffering between content and ads.
With IMA DAI SDK, you can target individual ads for live linear and video on demand programming, obtain multi-screen reach with broad device support, and take advantage of programmatic monetization across all devices with Ad Exchange for Video.
Regardless of the original format of your content, once it becomes digital, DAI can stitch custom targeted video ads into the stream, based on the individual user viewing the content.
It minimizes buffering and latency, and it ensures ads are rendered in the appropriate format, so that viewers have the broadcast-quality experience they expect.
Requirements
- Have an Ad Manager 360 Advanced account.
Features
- Provides a seamless, broadcast-like viewing experience.
- Streams are combined on the Ad Manager servers, regardless of which network an ad is hosted on.
Implement using Players module - Plugins section
Add the DAI plugin
- Open the PLAYERS module and either create a new player or locate the player to which you wish to add the plugin.
- Click the player's name to open the player's properties.
- Click Plugins in the left navigation menu.
-
From the Add a Plugin dropdown, select Custom Plugin.
- For the Plugin Name enter
imaDai
. - For the JavaScript URL, enter:
https://players.brightcove.net/videojs-ima-dai/1/videojs-ima-dai.min.js
- For the CSS enter:
https://players.brightcove.net/videojs-ima-dai/1/videojs-ima-dai.css
- Click Save.
- To publish the player, click Publish & Embed > Publish Changes.
- To close the open dialog, click Close.
Implement using code
To Initialize the IMA DAI Plugin, follow these steps:
Get the IMA DAI Plugin class:
const ImaDaiPlugin = videojs.getPlugin('imaDai');
Initialize the bc player:
const videoId = 'ima-dai-player'; const player = bc(videoId);
Initialize the IMA DAI Plugin:
const imaDai = player.imaDai();
Listen to the
IMA_DAI_SDK_LOADED
event:imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => { // The IMA DAI SDK is now ready, and you can send a stream request. });
Create a StreamRequest instance:
streamRequest
should be one of the following classes:LiveStreamRequest
,VODStreamRequest
,PodStreamRequest
.const streamRequest = new VODStreamRequest();
Provide a fallback stream: A fallback is required for any IMA DAI stream request. If the IMA DAI SDK fails to get a stream, the player will use this fallback stream.
const fallback = { type: 'your-fallback-type', src: 'your-fallback-src' };
Set the player source:
player.src({ type: fallback.type, src: fallback.src, imaDai: { streamRequest } });
VOD Stream Request:
// ... imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => { const { VODStreamRequest } = imaDaiSdk; const streamRequest = new VODStreamRequest(); streamRequest.videoId = 'tears-of-steel'; streamRequest.contentSourceId = '2528370'; const fallback = { type: 'application/x-mpegURL', src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8' }; player.src({ type: fallback.type, src: fallback.src, imaDai: { streamRequest } }); }); // ...
Live Stream Request:
// ... imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => { const { LiveStreamRequest } = imaDaiSdk; const streamRequest = new LiveStreamRequest(); streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ'; const fallback = { type: 'application/x-mpegURL', src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8' }; player.src({ type: fallback.type, src: fallback.src, imaDai: { streamRequest } }); }); // ...
Pod Serving Stream Request:
// ... imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => { const { PodStreamRequest } = imaDaiSdk; const streamRequest = new PodStreamRequest(); streamRequest.networkCode = '51636543'; streamRequest.customAssetKey = 'google-sample'; streamRequest.apiKey = ''; // Pod stream request requires podSourceResolver const podStreamUrl = 'https://encodersim.sandbox.google.com/masterPlaylist/9c654d63-5373-4673-8c8d-6d92b66b9d46/master.m3u8?gen-seg-redirect=true&network=51636543&event=google-sample&pids=devrel4628000,devrel896000,devrel3528000,devrel1428000,devrel2628000,devrel1928000&seg-host=dai.google.com&stream_id=[[STREAMID]]'; const podSourceResolver = (streamId) => { const src = podStreamUrl.replace('[[STREAMID]]', streamId); const type = 'application/x-mpegURL'; return { src, type }; }; const fallback = { type: 'application/x-mpegURL', src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8' }; player.src({ type: fallback.type, src: fallback.src, imaDai: { streamRequest, podSourceResolver } }); }); // ...
Final Code
const ImaDaiPlugin = videojs.getPlugin('imaDai');
const videoId = 'ima-dai-player';
const player = bc(videoId);
const imaDai = player.imaDai();
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const streamRequest = new VODStreamRequest();
const fallback = { type: 'your-fallback-type', src: 'your-fallback-src' };
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
Stream Request Examples:
Open Measurement
The IMA SDK for HTML5 includes the Open Measurement (OM) SDK, an industry standard developed by the Interactive Advertising Bureau (IAB) to enable third-party viewability and verification measurement. When using the IMA SDK for HTML5, the included OM SDK automatically parses the tag within VAST ad tags and sends viewability data to the specified measurement vendors via the OMID API. You can optionally set access mode rules for each request to control what content the verification script can access. Learn more
Access modes The Open Measurement SDK supports running verification scripts in different access modes, which control how much the verification script can access. The four access modes are:
FULL
: The verification script has direct access to the creative and the publisher page.CREATIVE
: The verification script and creative are sandboxed from the publisher page. However, the script has direct access to the creative.DOMAIN
: The verification script is sandboxed and cannot access the creative or publisher page. However, the script is loaded in such a way that it can directly confirm what publisher domain it is on.LIMITED
: The verification script is sandboxed and cannot access the creative or publisher page and cannot directly confirm what publisher domain it is on.
Here is an example of how you can set access mode rules for a request for different verification script providers:
// ...
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const { LiveStreamRequest } = imaDaiSdk;
const streamRequest = new LiveStreamRequest();
streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ';
streamRequest.omidAccessModeRules = {};
// set full access mode for goole:
streamRequest.omidAccessModeRules[google.ima.OmidVerificationVendor.GOOGLE] = google.ima.OmidAccessMode.FULL;
// set domain acess mode for other verfication script provider:
streamRequest.omidAccessModeRules[google.ima.OmidVerificationVendor.OTHER] = google.ima.OmidAccessMode.DOMAIN;
const fallback = {
type: 'application/x-mpegURL',
src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
};
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
// ...
Privacy
CCPA
To help publishers toward compliance with the California Consumer Privacy Act (CCPA), the Google Interactive Media Ads SDK allows publishers to use two different parameters to indicate whether Google should enable restricted data processing (RDP). The SDK provides publishers with the ability to set RDP at an ad request level utilizing the following parameters:
- RDP signal
- IAB signal
RDP signal
To notify Google that RDP should be enabled using Google's signal, append rdp=1
to your ad tag parameters, as shown in the following example:
// ...
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const { LiveStreamRequest } = imaDaiSdk;
const streamRequest = new LiveStreamRequest();
streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ';
// RDP signal:
streamRequest.adTagParameters = {"rdp": 1};
const fallback = {
type: 'application/x-mpegURL',
src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
};
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
// ...
IAB signal
To notify Google that RDP should be enabled using IAB's signal, use the ad tag parameter us_privacy
. The snippet below demonstrates how to create an ad request with the IAB parameter "1YNN"
:
// ...
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const { LiveStreamRequest } = imaDaiSdk;
const streamRequest = new LiveStreamRequest();
streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ';
// IAB signal:
streamRequest.adTagParameters = {"us_privacy": "1YNN"};
const fallback = {
type: 'application/x-mpegURL',
src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
};
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
// ...
GDPR
Under Google's updated EU User Consent Policy, you must make certain disclosures to your users in the European Economic Area (EEA) and obtain their consent for the use of cookies or other local storage where legally required and for the collection, sharing, and use of personal data for ads personalization. This policy reflects the requirements of the EU ePrivacy Directive and the General Data Protection Regulation (GDPR). Learn more.
Force non-personalized ads
Append npa=1
to your ad tag to specify that only non-personalized ad content.
// ...
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const { LiveStreamRequest } = imaDaiSdk;
const streamRequest = new LiveStreamRequest();
streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ';
// Force non-personalized ads:
streamRequest.adTagParameters = {"npa": 1};
const fallback = {
type: 'application/x-mpegURL',
src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
};
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
// ...
Tagging users as under the age of consent
This parameter disables personalized advertising, including remarketing, for that specific ad request. It also disables requests to third-party ad vendors, such as ad measurement pixels and third-party ad servers. To include this tag on all ad requests made from your implementation, append tfua=1
to your ad tag.
// ...
imaDai.one(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => {
const { LiveStreamRequest } = imaDaiSdk;
const streamRequest = new LiveStreamRequest();
streamRequest.assetKey = 'c-rArva4ShKVIAkNfy6HUQ';
// Tagging users as under the age of consent:
streamRequest.adTagParameters = {"tfua": 1};
const fallback = {
type: 'application/x-mpegURL',
src: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8'
};
player.src({
type: fallback.type,
src: fallback.src,
imaDai: { streamRequest }
});
});
// ...
Main Concepts
Stream Time vs. Relative Time
When we use server-side ad insertion (SSAI), ads and content are stitched together into a single stream.
Since there's only one stream, we need to create a way to understand time:
- Stream Time (or Absolute Time): This is the time in the whole stream.
- Relative Time: This depends on what's playing right now (ads or content).
- If we're playing an ad, the relative time will be the time within that specific ad.
- If we're playing content, the relative time will be the time within the content.
Example:
In this 70-second stream, ads take up to 30 seconds, and content takes up to 40 seconds.
- Absolute Time Duration = 70 seconds
- Relative Time Duration (Content) = 40 seconds
- Relative Time Duration (each Ad) = each individual ad's length (10s, 5s, ...)
Snapback
Snapback is the ability to take the user back to the start of the ad break they seeked past and then return them to their seek location after that ad break is over. Learn more.
Options
Option | Description | Default Value |
---|---|---|
debug |
If true, it enables debug messages and logs extra information. | false |
sdkUrl |
The URL of your self-hosted IMA DAI SDK. | //imasdk.googleapis.com/js/sdkloader/ima3_dai.js |
hideOverlays |
If true, it hides overlays while ads are playing. | false |
Static Members
Member | Description | Type | Usage example |
---|---|---|---|
DEFAULTS |
Object with possible plugin options and their default values. | Record<string, any> |
console.log(ImaDaiPlugin.DEFAULTS); |
VERSION |
Current plugin's version. | string |
console.log(ImaDaiPlugin.VERSION); |
EVENTS |
Object with possible plugin events. | Record<string, string> |
console.log(ImaDaiPlugin.EVENTS); |
SOURCE_TYPES |
Object with possible plugin source types. | Record<string, string> |
console.log(ImaDaiPlugin.SOURCE_TYPES); |
Instance getters
Getter | Description | Type | Usage Example |
---|---|---|---|
options |
Getter for the current options of the IMA DAI plugin instance. | Options |
console.log(imaDai.options); |
isImaDaiStream |
Check if the IMA DAI stream is playing. Returns true if it is, false otherwise. | boolean |
console.log(imaDai.isImaDaiStream); |
contentDuration |
Getter for the content duration (without ads). | number |
console.log(imaDai.contentDuration); |
relativeDuration |
Get the current ad duration if in ad mode or content duration without ads otherwise. | number |
console.log(imaDai.relativeDuration); |
canSeekNow |
Check if it is possible to perform a seek now. | boolean |
console.log(imaDai.canSeekNow); |
relativeCurrentTime |
Get the current time for the current ad if in ad mode or current content time (without ads) otherwise. | number |
console.log(imaDai.relativeCurrentTime); |
totalAdsDuration |
Get the total duration of all known ads (applicable for VOD only). | number |
console.log(imaDai.totalAdsDuration); |
Instance methods
Method | Description | Type | Usage Example |
---|---|---|---|
updateOptions |
Update the plugin's options. | (receivedOptions: Record<string, any>) => void |
imaDai.updateOptions({}); |
streamTimeForContentTime |
Convert a given content time to stream time with ads. | (contentTime: number) => number |
console.log(imaDai.streamTimeForContentTime(contentTime)); |
contentTimeForStreamTime |
Convert a given stream time to content time without ads. | (streamTime: number) => number |
console.log(imaDai.contentTimeForStreamTime(streamTime)); |
replaceAdTagParameters |
Replaces all of the ad tag parameters used for upcoming ad requests for a live stream. | (adTagParameters: Object|null) => void/code> |
imaDai.replaceAdTagParameters(new_adTagParameters) |
Events
Event | Description | Value | Usage Example |
---|---|---|---|
IMA_DAI_SDK_LOADED |
The event is triggered when the IMA DAI SDK has finished loading. | 'imaDai:imaDaiSdkLoaded' |
imaDai.on(ImaDaiPlugin.EVENTS.IMA_DAI_SDK_LOADED, ({ imaDaiSdk }) => { ... }); |