Skip to main content

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​

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.

NameRequiredTypeDescription
autoAlignfalsebooleanSet 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.
bitratefalsenumberMaximum recommended bitrate in kbit/s.
enablePreloadingfalsebooleanEnables preloading of video assets
loadVideoTimeoutfalsenumberTimeout (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.
mimeTypesfalsestring[]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.
playAdsAfterTimefalsenumberFor VMAP and ad rules playlists, only play ad breaks scheduled after this time (in seconds).
enableUiElementsfalsebooleanSpecifies whether to display the UI elements.
useStyledLinearAdsfalsebooleanRender linear ads with full UI styling
useStyledNonLinearAdsfalsebooleanRender 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();

The ad player works like a conventional player from the @quickplay/player library, so you can use it for playback.

note

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.
});
note

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 NameDescription
adbreakstartCalled when an ad break starts
adbreakendCalled when an ad break ends
adstartCalled when playback of an advert starts
adendCalled when playback of an advert ends
adprogressupdateCalled when an advert is playing
adcuepointsCalled when cue points are available
adverttrackingeventCalled 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.

PropertyTypeDescription
adBreakIDstringUnique id of the ab break
contentTimePositionAdContentTimePositionThe position of the ad break, can be on of preroll, midroll or postroll
adBreakStartTimeOffsetMsnumberThe start position in milliseconds
remainingTimeMsnumberThe time remaining in the ad break from the playhead provided, in milliseconds
durationMsnumberThe duration of the ad break, in milliseconds
totalAdsnumberTotal number of adverts in the ad break
adBreakIndexnumberThe index of the current ad break
note

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.

PropertyTypeDescription
adIDstringThe identifier of the advert
sequencenumberThe sequence of the advert
adStartTimeOffsetMsnumberThe start playhead position of the advert in milliseconds
durationMsnumberThe duration of the advert in milliseconds
remainingTimeMsnumberReturns the natural playback time remaining for the advert in milliseconds
isSkippablebooleanIndicates if the ad is skippable
skipOffsetMsnumberThe 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.
isFillerbooleanWhether this advert represents filler content
adBreakInfoAdBreakInfoThe ad break in which the advert belongs in
vastPropertiesVastPropertiesRepresents a VAST properties of advert.

VASTProperties​

Represents the VAST properties of an advert.

PropertyTypeDescription
adSystemstringThe source ad server of the advert
AdTitlestringThe common name of the advert
adServingIdstringAn identifier used to compare impression-level data across systems
creativeIdstringCreativeId of the advert
categorystringCategory of the advert content
descriptionstringThe longer description of the advert
advertiserstringAdvertiser name
pricingstringPricing element of the advert
surveystringAn URI to any resource file having to do with collecting survey data
expiresstringNumber of seconds in which the ad is valid for execution
adChoicesIconsArray of AdChoicesIconThe 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.

PropertyTypeDescription
programstringThe program represented in the icon (for example, AdChoices).
widthstringThe pixel width of the icon asset.
heightstringThe pixel height of the icon asset.
xPositionstringThe 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.
yPositionstringThe y-coordinate of the top left corner of the icon asset relative to the ad display area; values of"top" or "bottom" also accepted.
offsetstringThe 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).
durationstringThe 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).
apiFrameworkstringIdentifies the API needed to execute the icon resource file if applicable.
altTextstringThe 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.
imageURLstringThe URL of the image file for the icon (PNG is preferred).
clickThroughURLstringThe 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.
fallbackImagesArray of IconClickFallbackImageThe 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.

PropertyTypeDescription
widthstringThe pixel width of the image asset.
heightstringThe pixel height of the image asset.
altTextstringThe alternative text for the fallback image.
imageURLstringThe URL of the image file for the fallback image (PNG is preferred).

Ad tracking events​

The adverttrackingevent event reports the following AdTrackingEvent values.

EventDescription
AD_BREAK_STARTED_EVENTFired when an ad break in a stream starts.
AD_STARTED_EVENTFired when an ad starts playing.
AD_FIRST_QUARTILE_EVENTFired when the ad playhead crosses first quartile.
AD_MIDPOINT_EVENTFired when the ad playhead crosses midpoint.
AD_THIRD_QUARTILE_EVENTFired when the ad playhead crosses third quartile.
AD_PAUSED_EVENTFired when an ad is paused.
AD_RESUMED_EVENTFired when an ad is resumed.
AD_MUTED_EVENTFired when an ad is muted.
AD_UNMUTED_EVENTFired when an ad is unmuted.
AD_ENDED_EVENTFired when an ad completes playing.
AD_BREAK_ENDED_EVENTFired when an ad break in a stream ends.
AD_CLICKFired when an ad is clicked.
AD_VIDEO_CLICKEDFired when a non-clickthrough portion of a video ad is clicked.
AD_IMPRESSIONFires when the impression URL has been pinged.
AD_USER_CLOSEFires when the ad is closed by the user.
AD_SKIPPED_EVENTFired when an ad was skipped.
AD_INTERACTIONFires when an ad triggers the interaction callback. Ad interactions contain an interaction ID string in the ad data.
AD_SKIPPABLE_STATE_CHANGEDFires when the displayed ads skippable state is changed.
AD_VIDEO_ICON_CLICKEDFires 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​

Note: Pre-roll ad prefetch is supported on Web only. It is 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:

  1. Maintain persistent DOM elements for the video and ad container.
  2. Initialize QPAdsLoader with your prefetch configuration.
  3. Enable prefetch on the IMA player builder using .enablePrefetch(true).
  4. 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:

PropertyTypeRequiredDescription
imaSDKanyYesThe Google IMA SDK instance (window.google.ima).
adRequestIMAAdRequestYesAd request containing the pre-roll VAST or VMAP ad tag URL.
containerElementElementYesPersistent DOM container element for ad UI rendering.
videoElementHTMLVideoElementYesPersistent HTML video element for playback.
adsRenderingSettingsAdsRenderingSettingsNoOptional rendering settings such as enableUiElements or useStyledLinearAds.
imaSdkSettingsImaSdkSettingsNoOptional 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();
Prefetched pre-roll ad consumption

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 enablePrefetch setting.
  • Consumption is controlled by enablePrefetch. It decides whether playback uses an already-prefetched pre-roll ad.
enablePrefetchPrefetched ad availableBehavior
trueYesPlayback consumes the prefetched pre-roll ad.
trueNoPlayback follows the normal ad request flow.
falseYesThe prefetched ad is not consumed, even though it was already prefetched.
falseNoPlayback 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.
note

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 call QPAdsLoader.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.