Client Side Ad Insertion
The @quickplay/ads-ima library integrates with Google IMA to provide client-side ad insertion (CSAI) for both VOD and live content. This page shows how to load the SDK, create the ad player, handle ad events, and prefetch pre-roll ads.
Google IMA
Google IMA serves ads to the player based on the ad response for your ad tag.
Set up the SDK
You must load the Google IMA SDK before you create the ad player.
<!-- Add the script tag for the Google IMA SDK -->
<script
type="text/javascript"
src="//imasdk.googleapis.com/js/sdkloader/ima3.js"
></script>
Create the ad composable player
- Web
- Smart TV
AdComposablePlayer manages both the main content player and the ad player. It provides seamless content playback with Google IMA ads served according to the ad response.
Create the content player
Create a content player using the PlayerBuilder for Player or WebMAF Player.
const contentPlayer = playerBuilder
.mediaElement(videoElement)
.mediaUrl(contentUrl)
.drmLicenseUrl(playbackAsset.licenseUrl)
.drmScheme(playbackAsset.drmScheme)
.build();
Create the ad player
Create the ad player from the main content Player and a GoogleIMAAdRequest. The ad player manages only Google IMA ad playback, so you can't use it standalone. It doesn't manage main content playback.
AdsRenderingSettings
The following parameters control how the player renders ads.
| Name | Required | Type | Description |
|---|---|---|---|
| autoAlign | false | boolean | Set to false if you wish to have fine grained control over the positioning of all non-linear ads. If this value is true, the ad is positioned in the bottom center. If this value is false, the ad is positioned in the top left corner. The default value is true. |
| bitrate | false | number | Maximum recommended bitrate in kbit/s. |
| enablePreloading | false | boolean | Enables preloading of video assets |
| loadVideoTimeout | false | number | Timeout (in milliseconds) when loading a video ad media file. If loading takes longer than this timeout, the ad playback is canceled and the next ad in the pod plays, if available. |
| mimeTypes | false | string[] | Only supported for linear video MIME types. If specified, the player includes only media that matches the listed MIME types, for example ['video/mp4', 'video/webm']. If not specified, the SDK picks media based on player capabilities. |
| playAdsAfterTime | false | number | For VMAP and ad rules playlists, only play ad breaks scheduled after this time (in seconds). |
| enableUiElements | false | boolean | Specifies whether to display the UI elements. |
| useStyledLinearAds | false | boolean | Render linear ads with full UI styling |
| useStyledNonLinearAds | false | boolean | Render non-linear ads with a close and recall button. |
const adTagUrl =
'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&' +
'iu=/124319096/external/ad_rule_samples&ciu_szs=300x250' +
'&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vast&' +
'cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&' +
'vid=short_onecue&correlator=&unviewed_position_start=1';
const adPlayer = flAdsIma
.createPlayerBuilder()
.ima(google.ima)
.adRequest({ adTagUrl: adTagUrl, slotWidth: 628, slotHeight: 300 })
.contentPlayer(contentPlayer)
.contentVideoElement(videoElement) // videoElement on which ad is played.
.contentContainerElement(videoWrapper) // adContainer on which ad UI and settings are rendered.
.adsRenderingSettings({
enableUiElements: true,
useStyledLinearAds: true,
})
.build();
AdComposablePlayer manages both the main content player and the ad player. It provides seamless content playback with Google IMA ads served according to the ad response.
Create the content player
Create a content player using the PlayerBuilder for Player or WebMAF Player.
const playbackOptions = {
enablePreload: true,
segmentPrefetchLimit: 1,
};
const contentPlayer = playerBuilder
.mediaElement(videoElement)
.mediaUrl(contentUrl)
.drmLicenseUrl(playbackAsset.licenseUrl)
.playabackOptions(playbackOptions)
.drmScheme(playbackAsset.drmScheme)
.build();
Create the ad player
Create the ad player from the main content Player and a GoogleIMAAdRequest. The ad player manages only Google IMA ad playback, so you can't use it standalone. It doesn't manage main content playback.
AdsRenderingSettings
The following parameters control how the player renders ads.
| Name | Required | Type | Description |
|---|---|---|---|
| autoAlign | false | boolean | Set to false if you wish to have fine grained control over the positioning of all non-linear ads. If this value is true, the ad is positioned in the bottom center. If this value is false, the ad is positioned in the top left corner. The default value is true. |
| bitrate | false | number | Maximum recommended bitrate in kbit/s. |
| enablePreloading | false | boolean | Enables preloading of video assets |
| loadVideoTimeout | false | number | Timeout (in milliseconds) when loading a video ad media file. If loading takes longer than this timeout, the ad playback is canceled and the next ad in the pod plays, if available. |
| mimeTypes | false | string[] | Only supported for linear video MIME types. If specified, the player includes only media that matches the listed MIME types, for example ['video/mp4', 'video/webm']. If not specified, the SDK picks media based on player capabilities. |
| playAdsAfterTime | false | number | For VMAP and ad rules playlists, only play ad breaks scheduled after this time (in seconds). |
| enableUiElements | false | boolean | Specifies whether the UI elements should be displayed or not. |
| useStyledLinearAds | false | boolean | Render linear ads with full UI styling |
| useStyledNonLinearAds | false | boolean | Render non-linear ads with a close and recall button. |
const adTagUrl =
'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&' +
'iu=/124319096/external/ad_rule_samples&ciu_szs=300x250' +
'&ad_rule=1&impl=s&gdfp_req=1&env=vp&output=vast&' +
'cust_params=deployment%3Ddevsite%26sample_ar%3Dpremidpost&cmsid=496&' +
'vid=short_onecue&correlator=&unviewed_position_start=1';
const adPlayer = flAdsIma
.createPlayerBuilder()
.ima(google.ima)
.adRequest({ adTagUrl: adTagUrl, slotWidth: 1080, slotHeight: 720 })
.contentPlayer(contentPlayer)
.contentVideoElement(videoElement) // videoElement on which ad is played.
.contentContainerElement(videoWrapper) // adContainer on which ad UI and settings are rendered.
.deferContentUntilAdLoad(true)
.imaSmartTvAdPlaybackConfig({
contentPlaybackDelayMs: 500,
adToContentTransitionFactor: 1,
adCueTransitionDelayMs: 1000,
})
.adsRenderingSettings({
enableUiElements: true,
useStyledLinearAds: true,
enablePreloading: true,
bitrate: 3000, //kbits
})
.build();
The ad player works like a conventional player from the @quickplay/player library, so you can use it for playback.
The Google IMA SDK provides the Skip ad button when the ad is skippable.
Skip preroll ads during audio switching
You can skip preroll ads when you resume content or switch audio tracks. Set both of the following values:
initialPlaybackTime: The playback position, in seconds, where content resumes.playAdsAfterTime: The time, in seconds, after which the player plays scheduled ad breaks.
adPlayer.adsRenderingSettings({
playAdsAfterTime: 5, // Set equal to initialPlaybackTime.
});
You must set both values to skip preroll ads. If playAdsAfterTime is 0 or undefined, preroll ads play normally.
Listen to ad events
Subscribe to ad events to track ad playback state and build custom UIs. The AdPlayer emits the following events:
| Event Name | Description |
|---|---|
| adbreakstart | Called when an ad break starts |
| adbreakend | Called when an ad break ends |
| adstart | Called when playback of an advert starts |
| adend | Called when playback of an advert ends |
| adprogressupdate | Called when an advert is playing |
| adcuepoints | Called when cue points are available |
| adverttrackingevent | Called when an ad tracking event is signaled |
player.subscribe('adstart', function (adInfo) {
// Update the player controls if needed.
});
player.subscribe('adend', function (adInfo) {
// Update the player controls if needed.
});
player.subscribe('adprogressupdate', function (adInfo, progress) {
// Update the ad countdown timer if needed.
});
player.subscribe('adverttrackingevent', function (adTrackingEvent) {
// Signal ad and media events.
});
Handle ad blockers
Ad blockers can prevent the Google IMA SDK from loading. Before you create the ad player, check that google.ima is available. If it isn't, fall back to the content player.
if (typeof google === 'undefined' || typeof google.ima === 'undefined') {
const contentPlayer = playerBuilder
.mediaElement(videoElement)
.mediaUrl(contentUrl)
.drmLicenseUrl(playbackAsset.licenseUrl)
.drmScheme(playbackAsset.drmScheme)
.build();
} else {
const adPlayer = flAdsIma
.createPlayerBuilder()
.ima(google.ima)
.adRequest({ adTagUrl: adTagUrl, slotWidth: 1080, slotHeight: 720 })
.contentPlayer(contentPlayer)
.contentVideoElement(videoElement)
.contentContainerElement(videoWrapper)
.contentPlaybackDelayMs(500)
.deferContentUntilAdLoad(true)
.adsRenderingSettings({
enableUiElements: true,
useStyledLinearAds: true,
})
.build();
// The above values are for reference only. Use environment-specific values.
}
Ad metadata
The following objects describe ads and ad breaks in ad events.
AdBreakInfo
Represents an ad break object.
| Property | Type | Description |
|---|---|---|
| adBreakID | string | Unique id of the ab break |
| contentTimePosition | AdContentTimePosition | The position of the ad break, can be on of preroll, midroll or postroll |
| adBreakStartTimeOffsetMs | number | The start position in milliseconds |
| remainingTimeMs | number | The time remaining in the ad break from the playhead provided, in milliseconds |
| durationMs | number | The duration of the ad break, in milliseconds |
| totalAds | number | Total number of adverts in the ad break |
| adBreakIndex | number | The index of the current ad break |
The totalAds read from AdPlayer may not be accurate when it comes from adstart event. This may change once ad playback starts. GoogleIMA advises to read totalAds on or after FIRST_QUARTILE ad tracking event, to get a reliable data.
AdInfo
Represents an advert object.
| Property | Type | Description |
|---|---|---|
| adID | string | The identifier of the advert |
| sequence | number | The sequence of the advert |
| adStartTimeOffsetMs | number | The start playhead position of the advert in milliseconds |
| durationMs | number | The duration of the advert in milliseconds |
| remainingTimeMs | number | Returns the natural playback time remaining for the advert in milliseconds |
| isSkippable | boolean | Indicates if the ad is skippable |
| skipOffsetMs | number | The value of skip offset for the advert, in milliseconds. If the VAST skip offset is not defined then this method returns -1, signifying that the advert cannot be skipped. |
| isFiller | boolean | Whether this advert represents filler content |
| adBreakInfo | AdBreakInfo | The ad break in which the advert belongs in |
| vastProperties | VastProperties | Represents a VAST properties of advert. |
VASTProperties
Represents the VAST properties of an advert.
| Property | Type | Description |
|---|---|---|
| adSystem | string | The source ad server of the advert |
| AdTitle | string | The common name of the advert |
| adServingId | string | An identifier used to compare impression-level data across systems |
| creativeId | string | CreativeId of the advert |
| category | string | Category of the advert content |
| description | string | The longer description of the advert |
| advertiser | string | Advertiser name |
| pricing | string | Pricing element of the advert |
| survey | string | An URI to any resource file having to do with collecting survey data |
| expires | string | Number of seconds in which the ad is valid for execution |
| adChoicesIcons | Array of AdChoicesIcon | The List of AdChoicesIcon instances |
AdChoicesIcon
Represents VAST response metadata for Why This Ad? (WTA) privacy disclosures.
The VAST response returns these disclosures inside the AdChoices element.
The WTA attributes are part of the relevant Icon tag and render the AdChoices icon.
| Property | Type | Description |
|---|---|---|
| program | string | The program represented in the icon (for example, AdChoices). |
| width | string | The pixel width of the icon asset. |
| height | string | The pixel height of the icon asset. |
| xPosition | string | The x-coordinate of the top, left corner of the icon asset relative to the ad display area. Values of "left" or "right" also accepted and indicate the leftmost or rightmost available position. |
| yPosition | string | The y-coordinate of the top left corner of the icon asset relative to the ad display area; values of"top" or "bottom" also accepted. |
| offset | string | The time of delay from when the associated linear creative begins playing to when the icon should be displayed; provided in the format HH:MM:SS.mmm or HH:MM:SS where .mmm is milliseconds (optional). |
| duration | string | The duration icon should be displayed unless clicked or ad is finished playing; provided in the format HH:MM:SS.mmm or HH:MM:SS where .mmm is milliseconds (optional). |
| apiFramework | string | Identifies the API needed to execute the icon resource file if applicable. |
| altText | string | The alternative text for the image. In an html5 image tag this should be the text for the alt attribute. This should enable screen readers to properly read back a description of the icon for visually impaired users. |
| imageURL | string | The URL of the image file for the icon (PNG is preferred). |
| clickThroughURL | string | The URL of the action that occurs when a user clicks the AdChoices icon. In most cases,the user sees the Ad Settings page that the media player opens when the icon is clicked. |
| fallbackImages | Array of IconClickFallbackImage | The List of IconClickFallbackImage instances. |
IconClickFallbackImage
When the WTA icon can't display the Ad Settings page, such as when the platform doesn't support a browser,
WTA shows a fallback image with the same disclosure information as the Ad Settings page.
When the user clicks the icon, the ad must pause and the player must render the image above the video.
The player must let the user close the dialog, for example by pressing the back button.
Nothing can obstruct the image, and the player must not download it unless the user clicks the icon.
| Property | Type | Description |
|---|---|---|
| width | string | The pixel width of the image asset. |
| height | string | The pixel height of the image asset. |
| altText | string | The alternative text for the fallback image. |
| imageURL | string | The URL of the image file for the fallback image (PNG is preferred). |
Ad tracking events
The adverttrackingevent event reports the following AdTrackingEvent values.
| Event | Description |
|---|---|
| AD_BREAK_STARTED_EVENT | Fired when an ad break in a stream starts. |
| AD_STARTED_EVENT | Fired when an ad starts playing. |
| AD_FIRST_QUARTILE_EVENT | Fired when the ad playhead crosses first quartile. |
| AD_MIDPOINT_EVENT | Fired when the ad playhead crosses midpoint. |
| AD_THIRD_QUARTILE_EVENT | Fired when the ad playhead crosses third quartile. |
| AD_PAUSED_EVENT | Fired when an ad is paused. |
| AD_RESUMED_EVENT | Fired when an ad is resumed. |
| AD_MUTED_EVENT | Fired when an ad is muted. |
| AD_UNMUTED_EVENT | Fired when an ad is unmuted. |
| AD_ENDED_EVENT | Fired when an ad completes playing. |
| AD_BREAK_ENDED_EVENT | Fired when an ad break in a stream ends. |
| AD_CLICK | Fired when an ad is clicked. |
| AD_VIDEO_CLICKED | Fired when a non-clickthrough portion of a video ad is clicked. |
| AD_IMPRESSION | Fires when the impression URL has been pinged. |
| AD_USER_CLOSE | Fires when the ad is closed by the user. |
| AD_SKIPPED_EVENT | Fired when an ad was skipped. |
| AD_INTERACTION | Fires when an ad triggers the interaction callback. Ad interactions contain an interaction ID string in the ad data. |
| AD_SKIPPABLE_STATE_CHANGED | Fires when the displayed ads skippable state is changed. |
| AD_VIDEO_ICON_CLICKED | Fires when a user clicks a video icon. |
CCPA compliance
Send the CCPA consent string in the us_privacy query parameter of the ad request URL. For details, see the Google IMA SDK CCPA documentation.
The following example shows an ad request URL with the IAB parameter 1YNN.
let adTagUrl =
'https://pubads.g.doubleclick.net/gampad/ads?' +
'iu=/124319096/external/single_ad_samples&output=vast&us_privacy=1YNN';
Ad frequency control
To limit how often viewers see ads, see Ad frequency control.
Pre-roll ad prefetch
not applicable to,
and not supported on, WebTV. Confirm your target platform before enabling this feature.Pre-roll ad prefetch lets you request and warm up a Google IMA pre-roll ad break before the user starts playback. When the user selects a video, the player immediately uses the prefetched pre-roll ad, which eliminates initial ad buffering and network latency.
To integrate pre-roll prefetch into your web app, complete the following steps:
- Maintain persistent DOM elements for the video and ad container.
- Initialize
QPAdsLoaderwith your prefetch configuration. - Enable prefetch on the IMA player builder using
.enablePrefetch(true). - Clean up when exiting playback.
Step 1: Maintain persistent DOM elements
Google IMA binds directly to the DOM elements you pass to its container. To reuse the warmed ad instance across page navigations, keep the video element and ad container mounted in the DOM across your catalog and player screens. Don't destroy or recreate these DOM nodes between playback sessions.
In React applications, define the video element and ad container at the root
level of your application (such as App.tsx) using useRef. You can then pass
these element references (videoRef and adContainerRef) to your player
screen:
// App.tsx - Define persistent media elements at the root level
function App() {
const videoRef = useRef<HTMLVideoElement>(null);
const adContainerRef = useRef<HTMLDivElement>(null);
const [selectedAsset, setSelectedAsset] = useState<Asset | null>(null);
return (
<div className="app-container">
{/* Persistent media elements defined at root level */}
<div ref={adContainerRef} className="ad-container" />
<video ref={videoRef} playsInline />
{selectedAsset ? (
<PlayerScreen
asset={selectedAsset}
videoRef={videoRef}
adContainerRef={adContainerRef}
onBack={() => setSelectedAsset(null)}
/>
) : (
<CatalogScreen onSelectAsset={setSelectedAsset} />
)}
</div>
);
}
Step 2: Initialize QPAdsLoader
Call QPAdsLoader.initAdsLoader() early in your application lifecycle, such as
when your dashboard or catalog page mounts. This triggers Google IMA to fetch
the pre-roll ad tag in the background:
QPPrefetchConfig options
Configure the prefetch request using the following properties:
| Property | Type | Required | Description |
|---|---|---|---|
imaSDK | any | Yes | The Google IMA SDK instance (window.google.ima). |
adRequest | IMAAdRequest | Yes | Ad request containing the pre-roll VAST or VMAP ad tag URL. |
containerElement | Element | Yes | Persistent DOM container element for ad UI rendering. |
videoElement | HTMLVideoElement | Yes | Persistent HTML video element for playback. |
adsRenderingSettings | AdsRenderingSettings | No | Optional rendering settings such as enableUiElements or useStyledLinearAds. |
imaSdkSettings | ImaSdkSettings | No | Optional Google IMA SDK settings instance used by the prefetch request. |
import { QPAdsLoader } from '@quickplay/ads-ima';
import type { QPPrefetchConfig } from '@quickplay/ads-ima';
const prefetchConfig: QPPrefetchConfig = {
imaSDK: window.google.ima,
imaSdkSettings: new window.google.ima.ImaSdkSettings(),
adRequest: {
// Pre-roll-only ad tag URL used for background prefetching.
adTagUrl: '<PRE_ROLL_ONLY_AD_TAG_URL>',
slotWidth: window.innerWidth || 1920,
slotHeight: window.innerHeight || 1080,
},
adsRenderingSettings: {
enableUiElements: true,
useStyledLinearAds: true,
enablePreloading: true,
},
containerElement: adContainerRef.current, // Persistent ad container DOM element
videoElement: videoRef.current, // Persistent video DOM element
};
QPAdsLoader.initAdsLoader(prefetchConfig);
Step 3: Enable prefetch in the player builder
When the user selects an asset to play, construct your content player and ad
player. Call .enablePrefetch(true) on the IMA player builder so the player
reuses the prefetched pre-roll ad break:
import { createPlayerBuilder as createContentPlayerBuilder } from '@quickplay/player';
import { createPlayerBuilder as createImaPlayerBuilder } from '@quickplay/ads-ima';
import { MediaType } from '@quickplay/player-interface';
// 1. Build content player
const contentPlayer = createContentPlayerBuilder()
.mediaElement(videoRef.current)
.mediaUrl(asset.streamUrl)
.mediaType(MediaType.HLS)
.build();
// 2. Build ad player with enablePrefetch
const adPlayer = createImaPlayerBuilder()
.ima(window.google.ima)
.adRequest({
// Main playback ad tag URL returned by playback authorization.
adTagUrl: '<AD_TAG_URL>',
slotWidth: window.innerWidth || 1920,
slotHeight: window.innerHeight || 1080,
})
.contentPlayer(contentPlayer)
.contentVideoElement(videoRef.current)
.contentContainerElement(adContainerRef.current)
.enablePrefetch(true) // Set to false to prevent consuming the app-level prefetched pre-roll ad.
.build();
// 3. Start playback
adPlayer.load();
Prefetching and consumption are two separate steps, and enablePrefetch only
controls the second one.
- Prefetching is handled at the app level. It can happen regardless of the
enablePrefetchsetting. - Consumption is controlled by
enablePrefetch. It decides whether playback uses an already-prefetched pre-roll ad.
enablePrefetch | Prefetched ad available | Behavior |
|---|---|---|
true | Yes | Playback consumes the prefetched pre-roll ad. |
true | No | Playback follows the normal ad request flow. |
false | Yes | The prefetched ad is not consumed, even though it was already prefetched. |
false | No | Playback follows the normal ad request flow. |
Setting enablePrefetch to false does not stop the app from prefetching ads.
It only prevents playback from using them.
If the prefetched pre-roll is user-specific or profile-specific, see Step 4.
Step 4: Clean up when exiting playback
When the user exits the player screen (for example, by selecting Back to
return to the catalog), stop the player instances. Don't call
deInitAdsLoader(), so the shared loader stays ready to prefetch ads for later
videos:
// Stop active player instances
adPlayer.stop();
contentPlayer.stop();
// QPAdsLoader automatically prefetches a fresh pre-roll ad for the next asset.
Avoid calling QPAdsLoader.deInitAdsLoader() unnecessarily. Call it only in these cases:
- The user logs out, the application session ends, or you tear down a test.
- Your prefetched pre-roll is user-specific or profile-specific, for example when the user switches profiles. Call
deInitAdsLoader()before the switch. Then callQPAdsLoader.initAdsLoader()again with the newly prefetched ad tag URL so the player doesn't reuse the previous user's or profile's ad.
Next steps
- Learn how to configure Incoming ad notification to display countdown notifications before upcoming mid-roll ad breaks.