Appearance
Examples
Three HTML5 reference repositories show four ways to integrate TrueX and IDVx ads into a CTV web app. The first repository contains two examples, one for each way ads are inserted:
| Example | Repository | Ad source | Ad break behavior |
|---|---|---|---|
| Manual CSAI | truex-ctv-web-reference-app | Ad breaks defined in video-streams-csai.json | The app pauses the content, plays the ad pod itself, and resumes the content |
| Manual SSAI | truex-ctv-web-reference-app | Ad breaks defined in video-streams-ssai.json | The ads are stitched into one video stream, so the app calculates the ad break times |
| Google IMA CSAI | truex-ctv-google-ima-csai-ref-app | A VAST ad playlist (sample-ad-playlist.xml) | Google IMA requests and sequences client-side ads |
| Google IMA SSAI | truex-ctv-google-ima-ssai-ref-app | Google Ad Manager VAST tags stitched into the stream | One stream with stitched ad breaks, defined in video-streams.json |
Each example has its own player, ad, and TruexAdRenderer code on purpose, so you can pick the one closest to your setup and read it from top to bottom. All of them are webpack apps that load the renderer from the @truex/ad-renderer package - see SDK Integration.
NOTE
The Google IMA apps may still construct the renderer from the VAST config URL as a legacy fallback. For new integrations, construct it from adParameters as described in Integration Flow. The Manual examples already accept an adParameters JSON object for IDVx ads.
Running the Apps
Requirements:
- The Node version in the repository's
.nvmrc(14.16 at the time of writing)
Run an app locally:
bash
npm install
npm startThe app is served at http://localhost:8080. To build a deployable version in the dist folder, run npm run build and host its contents. To test on a device, open your computer's local network address (for example http://192.168.1.72:8080) in the device's browser, or use it as the launcher URL of the device's app.
Each repository has platform-specific instructions under its platforms folder for Fire TV / Android TV, Vizio, LG, Tizen, PS4, PS5, and Xbox One.
While the app is running:
- Select "4" or Menu on the remote, or click the left stick on the controller, to show the in-app debug console. The back action closes it.
- Select "2" on the remote, or click the right stick on the controller, to skip the current ad break (Manual examples).
Shared Rules
All the examples follow the same rules, described in Integration Flow:
- An ad with
<AdSystem>trueXis a TrueX ad only when it is the first ad in the pod. An ad with<AdSystem>IDVxcan be in any position. - The content and ad playback are paused before the renderer is created.
- Each example has an
InteractiveAdcomponent (interactive-ad.js) that creates the renderer, subscribes to its events, callsinitandstart, and removes the ad overlay when a terminal event arrives. adFreePodonly sets a flag. The playback timeline moves when the terminal event arrives: with the flag set, the app skips the rest of the ad break; without it, the app plays the next ad in the pod.- The renderer is created with
supportsUserCancelStream: true, so a user who backs out of the choice card closes the video. - The back action is handled with a
popstatehandler that ignores the renderer's own history state (onBackAction,pushBackActionBlock, andpushBackActionStubinmain-csai.js,main-ssai.js, ormain.js).
Manual CSAI
Repository: truex-ctv-web-reference-app. Open index-csai.html (main-csai.js, src/components/csai/), hosted at ctv.truex.com/web/ref-app/master/index-csai.html.
The ad breaks are defined in src/data/video-streams-csai.json:
timeOffset: the content time when the ad break startsdescription: the VAST config URL of a TrueX adadParameters: the JSON configuration of an IDVx admediaFile: the fallback video ad
Flow:
- The
VideoControllerreceives the video stream instartVideo, andsetAdPlaylistcreates anAdBreakfor each ad break. - When the content reaches a
timeOffset, the content pauses and the ads play separately. No time adjustments are needed, because the ads are not part of the content timeline. - For a TrueX or IDVx ad, an
InteractiveAdcreates the renderer and starts it. - On a terminal event,
skipAdBreakskips the rest of the ad break if the user earnedadFreePod, orplayNextAdInBreakplays the next ad. The content then resumes from the pause point.
Manual SSAI
Repository: truex-ctv-web-reference-app. Open index.html (main-ssai.js, src/components/ssai/), hosted at ctv.truex.com/web/ref-app/master/index.html.
The ad breaks are defined under the vmap key of src/data/video-streams-ssai.json:
timeOffset: the content time of the ad breakvideoAdDuration: the total length of the stitched ads (placeholders and fallback ads) in secondsads: the ads of the break, each withadSystem(trueX,IDVx, orGDFP),duration, anddescription(VAST config URL) oradParameters(JSON)
Flow:
- The SSAI
VideoControllercalculates thestartTimeandendTimeof each ad break from itstimeOffsetand the durations of all the earlier ads, because the ads are stitched into the timeline. It subtracts the ad durations from the raw video position to get the content time. - When playback reaches the start of an Infillion ad's placeholder, the app pauses and an
InteractiveAdcreates and starts the renderer. - On a terminal event,
skipAdBreakjumps past the end of the ad break if the user earnedadFreePod; otherwiseresumeAdBreakcontinues with the next stitched ad.
Google IMA CSAI
Repository: truex-ctv-google-ima-csai-ref-app. It uses the HTML5 Google IMA SDK for client-side ad insertion, with two versions of the same app:
| Version | Entry point | Hosted copy |
|---|---|---|
| Plain IMA SDK with your own HTML5 video element | src/simple/simple.js, simple-video-controller.js | index.html |
| IMA with video.js | src/videojs/videojs-demo.js, videojs-controller.js | videojs-demo.html |
The content is defined in src/data/video-streams.json, and the ads in src/data/sample-ad-playlist.xml, with a preroll and a midroll ad break that can contain TrueX and IDVx ads.
Flow:
- The video controller fields the IMA ad events in
onAdEvent. OnAdEvent.Type.STARTED,startInteractiveAd()identifies the ad: an<AdSystem>oftrueXat pod position 1 is a TrueX ad, andIDVxis an IDVx ad. Any other ad keeps playing in theadsManager. - For an Infillion ad, the app creates an
InteractiveAd(src/components/interactive-ad.js), which creates the renderer and starts it. The trafficking parameters come from the IMA ad object (getTraffickingParametersString()). - On a terminal event,
skipAdBreak()discards the ad break if the user earnedadFreePod; otherwiseresumeAdPlayback()lets theadsManagerplay the next ad.
Google IMA SSAI
Repository: truex-ctv-google-ima-ssai-ref-app, hosted at ctv.truex.com/web/ref-app-google-IMA/master/index.html. It uses Google Ad Manager to stitch the ads into the video stream.
The content and its ad breaks, preroll and midroll-1, are defined in src/data/video-streams.json:
timeOffset: the content time where the ad break starts. The ads are stitched in, so the real video time is the content plus all the ad durations.videoAdDuration: the length of the stitched fallback videovastUrl: the VAST config URL of the Infillion ad
Flow:
- The
VideoController(src/components/video-controller.js) receives the stream instartVideo, andsetAdPlaylistcreates anAdBreakfor each entry of thevmaparray. - When
onVideoTimeUpdatereaches the start of an ad break, anInteractiveAdcreates and starts the renderer over the playback page. - On a terminal event, the app seeks to the end of the placeholder if the user did not earn
adFreePod, or to the end of the pod if they did, and playback continues.
The VAST responses served to Google Ad Manager are hosted on dedicated endpoints - a change there is eventually picked up by Google Ad Manager.

