Server-Side Ad Insertion User Guide
This revision adds MPEG-DASH support alongside existing HLS. Section 3.2 is new. Section 3.1 has been lightly updated to clarify HLS-specific context. The macro table, implementation steps, and example URLs in Sections 3.3 and 4.5 have been updated to reflect both protocols.
1. Introduction
This guide explains how to implement Smart Ad Stitching technology using the provided URL structure and macros. Its goal is to help content owners, broadcasters, and publishers seamlessly integrate Server-Side Ad Insertion (SSAI) into their CTV (Connected TV) environments.
By following the steps and examples in this document, you'll learn how to configure SSAI parameters, understand how each macro works, and deliver a smooth, ad-supported streaming experience over both HLS and MPEG-DASH.
2. Overview
Server-Side Ad Insertion (SSAI) is a technique that inserts ads directly into your video stream from the server, rather than the app or player. This approach has several key benefits:
- Better user experience: Ads become part of the content stream, so viewers enjoy smooth transitions without buffering or app-side interruptions.
- Ad Blocker Resistance: Because ads are served inside the main stream, they're less likely to be blocked by device ad-blockers.
- Personalized Ads: SSAI supports dynamic targeting, allowing you to serve ads tailored to user data or viewing context.
- Seamless Content Integration: The
isNoSlateoption lets you weave ads alongside content without pausing playback. - Protocol Flexibility: The ad stitcher supports both HLS (.m3u8) and MPEG-DASH (.mpd) source manifests, letting you serve the format best suited to your device ecosystem.
3.1 Prepare the Master Playlist URL (HLS)
Your master playlist URL is the foundation of the streaming and ad insertion process for HLS streams. It tells the SSAI system where to find your video content and where to insert ads.
Understanding the HLS Master Playlist
The HLS (HTTP Live Streaming) master playlist (.m3u8) is a crucial element in streaming. It references multiple variant playlists, each representing the same content encoded at different bitrates or resolutions. This setup allows the player to automatically choose the best quality based on the viewer's device and network connection.
Encoding the URL
To send the master playlist URL as a parameter, it must first be Base64 encoded.
- Why Base64? Encoding ensures your URL can safely be passed as a query parameter by converting special characters into standardized ASCII format.
- How to Encode: Use a Base64 encoding tool such as Base64 Guru, or a Base64 function in your own application.
Example:https://example.com/stream.m3u8→aHR0cDovL2V4YW1wbGUuY29tL3N0cmVhbS5tM3U4 - Once the URL is encoded, replace the
{m}macro in your provided ad insertion template with the encoded Base64 string.
3.2 DASH Support NEW
MPEG-DASH (Dynamic Adaptive Streaming over HTTP) is an ISO-standard adaptive bitrate protocol widely supported across Android TV, Fire TV, Samsung Tizen, and LG webOS. For devices that do not support HLS natively — or deployments where DASH is preferred — the Ad Insertion can accept a DASH manifest (.mpd) as the source, stitch ads at SCTE-35/SCTE-214 event boundaries, and return a stitched DASH manifest to the player.
How DASH Stitching Works
The overall flow mirrors HLS stitching: the DASH manifest URL is Base64 encoded and passed in the {m} macro, just like an HLS source. The stitcher detects the manifest type automatically based on the .mpd extension or the Content-Type: application/dash+xml response header.
- Pass a
.mpdmanifest URL in the{m}macro (Base64 encoded), exactly as you would for HLS. - Ad breaks are signaled via
EventStreamelements in the MPD, usingschemeIdUri="urn:scte:scte35:2014:xml+bin"— the standard SCTE-35 in-band signaling method for DASH. - No-slate mode (
isNoSlate=true) andadIntervalwork identically to HLS. Use them for DASH streams that do not contain SCTE-214 event signaling. - The stitched output is a DASH MPD with ad periods inserted. The player must be a DASH-capable player (e.g., ExoPlayer, Shaka Player, dash.js).
DASH vs. HLS — Key Differences for SSAI
| Feature | HLS (.m3u8) | DASH (.mpd) |
|---|---|---|
Source macro ({m}) | ||
| Ad break signaling | SCTE-35 in #EXT-X-CUE-OUT | SCTE-35/214 in EventStream |
No-slate mode (isNoSlate) | ||
Pre-roll (preroll) | ||
cuePoint macro | ||
| Low-latency (LL) mode | LL-HLS | LL-DASH (contact support) |
| Player requirement | HLS-capable (AVPlayer, ExoPlayer, etc.) | DASH-capable (ExoPlayer, Shaka, dash.js) |
| Stitched manifest output | .m3u8 with ad segments | .mpd with ad Period elements |
Example: DASH Source URL
Base64-encode your MPD URL:
https://example.com/live/manifest.mpd?m=aHR0cHM6Ly9leGFtcGxlLmNvbS9saXZlL21hbmlmZXN0Lm1wZA==
Then construct your stitcher URL exactly as you would for HLS, using the encoded MPD URL as the m value:
https://demo-telos.live.indicue.com/stream.m3u8?m=aHR0cHM6Ly9leGFtcGxlLmNvbS9saXZlL21hbmlmZXN0Lm1wZA==&u={u}&adDuration={adDuration}&aid={aid}
3.3 Ad Insertion Macros
Ad Insertion macros control how ads are requested and inserted during playback. These macros also pass additional parameters needed for ad calls.
Keep in mind:
- You must include all required parameters for your ad request along with these macros.
- For examples and detailed guidance, refer to the SSP Macros Documentation.
- The Ad Insertion service acts as a proxy: it passes through all non-stitcher parameters but doesn't generate them directly from the SSP.
Stitcher Control Parameters
| Name | Macro | Description | Example | Allowed Values | Constraints |
|---|---|---|---|---|---|
| Master playlist / manifest source URL | {m} |
The Base64-encoded source URL. Accepts both HLS (.m3u8) and MPEG-DASH (.mpd) manifests. The stitcher detects the protocol automatically. |
m=aHR0cDovL... |
Base64 encoded URL string | Required Must be a valid Base64-encoded URL. |
| User ID | {u} |
A unique identifier for the user accessing the stream. | u=testuser | String | Required |
| Ad triggers included in playlist source? | {isNoSlate} |
Controls whether ads are inserted as additional content without replacing the main content. For HLS use this when no EXT-X-CUE-OUT markers exist. For DASH, use when no EventStream cue points are present. |
isNoSlate=true | Boolean (true, false, 1, 0) | Optional Default: false. |
| Ad insertion interval | {adInterval} |
Time interval in seconds between consecutive ad insertions. Only works when no-slate mode is enabled (HLS and DASH). | adInterval=600 | Integer (seconds) | Optional Required if isNoSlate=1. |
| Ad pod duration | {adDuration} |
Maximum duration of each ad break in seconds. | adDuration=60 | Integer (seconds) | Required if ads are being inserted. |
| Pre-roll ad block | {preroll} |
Enables pre-roll ads before main content. Supported for both HLS and DASH. | preroll=1 | Boolean | Optional Default: false. |
| Pre-roll offset | {prerollOffset} |
Duration in seconds before preroll ads play. Result depends on segment duration. | prerollOffset=5 | Integer (seconds) | Optional Default: 8 seconds. |
| Cue Point | {cuePoint} |
For HLS: use only SCTE-35 cues from EXT-X-CUE-OUT markers. For DASH: use only EventStream SCTE-35/214 cues. |
cuePoint=1 | Boolean (true, 1, TRUE) | Optional Default: false. |
| Format override | {format} |
Override default encoding ladder for a specific OTT partner (bitrate, codecs, etc.). | format=ott-studio-p31 | String | Optional |
CTV Ad Request Parameters
| Name | Macro | Description | Example | Constraints |
|---|---|---|---|---|
| Source ID | {aid} | Identifies the Source ID within the stitching system. Used for reporting and analytics. | aid=478241 | Required |
| Traffic Router | {troute} | Identifies the Traffic Router ID. Required when linking to a Traffic Router. | troute=83 | Required if using Traffic Router |
| Site full URL | {site_full_url} | Full URL of the site where video content is being streamed. | site_full_url=test.com | Optional |
| Device User Agent | {ua} | User-Agent string from the device. Used for analytics and content adaptation. | ua=Mozilla/5.0... | Optional |
| IP Address | {uip} | IP address of the device. Used for geolocation and personalization. Handle with care. | uip=192.168.1.1 | Optional |
| App Name | {app_name} | Name of the application making the request. | app_name=ExampleApp | Optional |
| App Bundle | {app_bundle} | Unique bundle identifier for the application (reverse DNS format). | app_bundle=com.example.app | Optional |
| Device Model | {device_model} | Model of the device accessing the stream. | device_model=iPhone10,6 | Optional |
| Device Manufacturer | {device_make} | Manufacturer of the device (e.g., Apple, Samsung). | device_make=Apple | Optional |
| Device Type | {device_type} | Type of device: 1=PC, 2=Smartphone, 3=Tablet, 4=Smart TV, 5=Set-Top Box. | device_type=4 | Optional |
| App Store URL | {app_store_url} | URL of the application in the app store. | app_store_url=https://itunes.apple.com/... | Optional |
| Device ID | {device_id} | Unique identifier for the device. Important for session tracking. | device_id=abcd1234 | Optional |
| GDPR | {gdpr} | Signals whether data processing is subject to GDPR. | gdpr=1 | Optional |
| TCF String | {gdpr_consent} | IAB TCF consent string under GDPR. | gdpr_consent=COtybn4... | Required if gdpr=1 |
| US Privacy | {us_privacy} | U.S. state privacy string (CCPA). Fixed 4-character format (e.g., 1YNN). | us_privacy=1YNN | Optional |
| Limit Ad Tracking | {lmt} | 0 = tracking unrestricted; 1 = tracking must be limited. | lmt=0 | Optional |
| COPPA | {coppa} | 1 = user is under 13 (COPPA applies); 0 = COPPA does not apply. | coppa=1 | Optional |
4. Ad Insertion Implementation
This section provides a step-by-step guide to implementing "Telos" ad insertion. The steps below apply to both HLS and DASH unless noted.
4.1 Set Up User Identification
The User ID ({u}) is a unique identifier assigned to each viewer or session. Replace the {u} macro with the actual user ID — this can be a string (e.g., a username) or a numeric identifier assigned by your system.
4.2 Configure Ad Insertion Parameters
-
Set "No Slate" Mode (Optional):
The{isNoSlate}flag controls whether ads are inserted as additional content. Default isfalse. Set totrueif your stream (HLS or DASH) does not include cue points. Whentrue, the maximum ad block length is set by{adDuration}, but the actual length depends on available fill. -
Specify Ad Insertion Interval (Optional):
The{adInterval}determines how frequently ads are inserted (in seconds). Required whenisNoSlate=true. -
Define Ad Duration:
The{adDuration}specifies the maximum duration of each ad block in seconds (e.g.,adDuration=30). Required if ads are being inserted.
4.3 Enable Pre-Roll Ads (Optional)
Pre-roll ads play before the main content begins and are supported for both HLS and DASH.
- Activate Pre-Roll: Set
{preroll}totrueor1. - Define Pre-Roll Offset: Use
{prerollOffset}to specify a delay in seconds before pre-roll ads play. Default is 8 seconds.
4.4 Provide Device, App, and Content Information
Providing detailed device, app, and content information helps optimize ad delivery across platforms.
- Device Information:
{ua}(User-Agent),{uip}(IP Address),{device_model} - App Information:
{app_name},{app_bundle},{app_store_url} - Additional Device Details:
{device_make},{device_type},{device_id} - Content Data: Content ID, Content URL, Content Series, Language, Genre, Categories. See indicue.com/macros for the full list.
4.5 Test the URL
Before deploying to production, test the URL in a controlled environment to confirm that ads are inserted as expected and the stream plays correctly. Use stream analyzers or your ad insertion platform's testing features.
HLS Example Template
https://demo-telos.live.indicue.com/stream.m3u8?m={m}&u={u}&isNoSlate={isNoSlate}&adInterval={adInterval}&adDuration={adDuration}&preroll={preroll}&site_full_url={site_full_url}&ua={ua}&uip={uip}&app_name={app_name}&app_bundle={app_bundle}&device_model={device_model}&device_make={device_make}&device_type={device_type}&app_store_url={app_store_url}&device_id={device_id}&aid={aid}
DASH Example Template NEW
https://demo-telos.live.indicue.com/stream.mpd?m={m_dash_base64}&u={u}&isNoSlate={isNoSlate}&adInterval={adInterval}&adDuration={adDuration}&preroll={preroll}&site_full_url={site_full_url}&ua={ua}&uip={uip}&app_name={app_name}&app_bundle={app_bundle}&device_model={device_model}&device_make={device_make}&device_type={device_type}&device_id={device_id}&aid={aid}
The endpoint path is the same for both HLS and DASH. The stitcher automatically detects the source manifest type from the Base64-decoded {m} value. Ensure your player is configured for the appropriate playback protocol (HLS-capable or DASH-capable) before testing.
4.6 Finalize the Production URL
Double-check that all relevant macros have been replaced with the correct values. Missing or incorrect values can lead to errors or failed ad insertions.
HLS Production URL Example
https://ott-studio.telos.indicue.com/stream.m3u8?m=aHR0cDovL2hscy10cmFuc2NvZGVyLnR2c3RpdGNoLmNvbS9uby1zbGF0ZS9tYXN0ZXIubTN1OA==&u=testuser&isNoSlate=true&adInterval=60&adDuration=60&preroll=1&site_full_url=test.com&ua=Mozilla/5.0%20(Linux;%20U;%20Android%202.2)%20AppleWebKit/533.1%20(KHTML,%20like%20Gecko)%20Version/4.0%20Mobile%20Safari/533.1&uip=167.235.198.190&app_name=test_app_name&app_bundle=test_app_bundle&device_model=Android%202.2&device_make=Android&device_type=2&app_store_url=test_app_store_url.com&device_id=1&aid=1401
DASH Production URL Example NEW
https://ott-studio.telos.indicue.com/stream.mpd?m=aHR0cHM6Ly9leGFtcGxlLmNvbS9saXZlL21hbmlmZXN0Lm1wZA==&u=testuser&isNoSlate=true&adInterval=60&adDuration=60&preroll=1&site_full_url=test.com&ua=Mozilla/5.0%20(Linux;%20Android%2012;%20SHIELD%20Android%20TV)%20AppleWebKit/537.36&uip=167.235.198.190&app_name=test_app_name&app_bundle=com.example.tvapp&device_model=SHIELD%20Android%20TV&device_make=NVIDIA&device_type=4&device_id=abcd5678&aid=1401
Replace ott-studio with your subdomain. Contact your Indicue sales representative if you haven't yet been issued your subdomain.