as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Client-side ad insertion in Vega

In client-side ad insertion (CSAI), the video player manages both content and ad playback independently. Unlike server-side ad insertion (SSAI), where the server stitches ad segments into the content manifest, CSAI keeps the content stream unmodified. The client application manages the switch between content and ad streams.

CSAI enables dynamic ad insertion because the client fetches ads at runtime from an ad server using protocols such as Video Ad Serving Template (VAST) or Video Multiple Ad Playlist (VMAP). Ads can be targeted per user, per session, or per content in real time without modifying the content stream. This enables personalized ad experiences without any server-side manifest changes.

CSAI gives full control to the app for managing ad timing, playback, and transitions. The application has complete ownership of the ad lifecycle: deciding when to trigger ad breaks, controlling ad player initialization and playback behavior, and managing the shared surface for frame-accurate switching between main content and ads.

CSAI techniques

Vega supports two techniques for determining when to insert ads: out-of-band (standard) and in-band (advanced).

Standard CSAI: out-of-band ads

In standard CSAI, the client app relies on external information, not manifest tags, to determine when to insert ads. The player receives an unmodified content manifest and handles ad logic separately.

Ad triggering methods include:

  • VMAP: The player fetches an external XML file that schedules ad breaks at specific timestamps (for example, at 0s, 300s).
  • Hardcoded logic: The application triggers ad requests at fixed intervals based on the player's current time position (for example, every 20 seconds).
  • Sidecar files: The app downloads a separate configuration file (JSON/XML) from a content management system (CMS) that lists ad break times for a specific piece of content.
  • Ad SDKs: An SDK (like Google Interactive Media Ads) manages timing internally via ad rules, removing the need for the developer to manage specific timestamps or manifest tags.

In a typical out-of-band implementation, ad markers are defined in the UI layer (for example, hardcoded or fetched from a schedule) and the position listener triggers insertion directly. No ad information is sent to the service layer.

Advanced CSAI: in-band ads

In advanced CSAI, the player monitors the manifest for in-stream metadata markers that signal ad opportunities.

Common markers include:

Marker Protocol
#EXT-X-CUE-OUT / #EXT-X-CUE-IN HTTP Live Streaming (HLS)
#EXT-X-DATERANGE HLS Interstitials
Society of Cable Telecommunications Engineers (SCTE)-35 signals (translated into manifest tags) HLS / Dynamic Adaptive Streaming over HTTP (DASH)

When the player encounters a marker (for example, #EXT-X-CUE-OUT), it interprets this as an ad avail opportunity and initiates a VAST or VMAP request to an ad server for the indicated duration. The ad content is fetched and buffered in parallel while the main content continues playing. The main content pauses only when the ad presentation time is reached. By this time, the ad is expected to be ready to play for a seamless experience.

In an in-band implementation using the Headless approach, the UI can send an ad list to the service layer via sendMessage({type: 'adList', ads}) to provide the same data that manifest parsing would produce. The service stores the ad list on the PlayerSession and processes ad markers during getCurrentPlaybackPosition(). When an ad's pre-buffer window is reached (5 seconds before startTime), the service sends an {type: 'adMarkers', ad} message back to the UI, which then triggers ad insertion.

Playback sync strategies

Both implementation approaches support two strategies for coordinating the main and ad players during transitions.

Pre-buffered ad (seamless)

The ad player is pre-initialized and buffered before the transition occurs. This provides a gapless user experience with no visual interruptions.

  1. Main content plays.
  2. Ad marker detected. Pre-initialize ad player with autoPlay=false.
  3. Ad player buffers. canplay event fires (JS) or service sends READY status (Headless).
  4. UI receives ready signal. Ad is ready to play, waits for scheduled playback time.
  5. Position listener detects ad start time reached. Pause main content.
  6. Main content paused. Clear main surface, set ad surface, play ad.
  7. Ad ends. Clear ad surface, clean up ad player, set main surface, resume main content.

Characteristics:

  • No visual interruption
  • Pre-buffers ad content before playback
  • Best for premium viewing experiences
  • autoPlay setting: false (manual control)

Instant autoplay ad (with gap)

The ad player is initialized on-demand when the ad break occurs. Because the ad loads at playback time with autoPlay=true, there may be a brief transition gap during ad player initialization.

  1. Main content plays.
  2. Ad marker detected. Pause main content.
  3. Main content paused. Clear main surface, initialize ad player with autoPlay=true.
  4. Ad player ready. Set ad surface, playback starts automatically.
  5. Ad ends. Clear ad surface, clean up ad player, set main surface, resume main content.

Characteristics:

  • Brief black or pause screen possible during transition
  • Loads ad on-demand
  • Simpler implementation
  • autoPlay setting: true (automatic playback)

Back-to-back advertisements

When your ad break contains multiple consecutive ads, you have three approaches depending on device capabilities:

  • Single ad player (resource-constrained devices): Create only a single ad player at a time to play a single advertisement. This may not provide seamless or gapless transitions and is only recommended for devices with limited memory or decoders.
  • Multiple ad players (high-performance devices): Use two ad player instances for seamless back-to-back ad playback. Provides gapless transitions between consecutive ads. Requires sufficient device resources.
  • Main content player recreation (alternative approach): Store the current playback position of primary content. Recreate the main player during the last ad playback. This allows creating two separate ad players on resource-constrained devices.

Challenges with CSAI

Consider the following challenges when implementing CSAI:

  • Buffering and latency: When ads are loaded on-demand (instant ads), pausing content to load ads can lead to buffering or latency. To resolve this, pre-buffered ads buffer the ad content before the actual presentation time and pause the main content only after sufficient buffering.
  • Device compatibility: Inconsistent performance across different devices due to varying hardware capabilities (memory, decoders, processing power).
  • Single surface rendering: The ad must play from the first frame after rendering the last frame of main content. There should not be missing frames or any overlap of frames during the surface switch.

Choose your implementation approach

Vega provides two implementation approaches for CSAI. Choose the approach that matches your app architecture.

JS approach

The JS approach uses direct React Native component integration. VideoPlayer instances are created and managed within the UI component layer. The application has direct access to W3C Media APIs and controls playback through direct method calls.

┌─────────────────────────────────────────────────────────┐
│              React Native Component Layer               │
│  ┌──────────────────┐        ┌──────────────────┐       │
│  │  Main Player     │        │   Ad Player      │       │
│  │  (VideoPlayer)   │        │   (VideoPlayer)  │       │
│  └──────────────────┘        └──────────────────┘       │
├─────────────────────────────────────────────────────────┤
│           KeplerVideoSurfaceView (Shared)               │
└─────────────────────────────────────────────────────────┘

Use this approach when:

  • Your app uses a single-threaded React Native architecture
  • You want direct access to W3C Media API
  • You prefer simpler component-level player management

Package: @amazon-devices/react-native-w3cmedia

To implement this approach, see Implement client-side ad insertion using the JS approach.

Headless approach

The Headless approach uses a client-server architecture. IPlayerClient instances in the UI layer communicate with VideoPlayer instances managed in a separate service layer via KeplerPlayerClientTurboModule using JavaScript Interface (JSI) for high-performance inter-process communication (IPC).

┌─────────────────────────────────────────────────────────┐
│                    UI Layer (PlayerUI)                  │
│  ┌──────────────────┐        ┌──────────────────┐       │
│  │  Main Player     │        │   Ad Player      │       │
│  │  Client          │        │   Client         │       │
│  │  (IPlayerClient) │        │   (IPlayerClient)│       │
│  └────────┬─────────┘        └─────────┬────────┘       │
│           │                            │                │
│           │      KeplerPlayerClientTurboModule          │
│           ▼                            ▼                │
├─────────────────────────────────────────────────────────┤
│                  IPC Bridge (JSI)                       │
├─────────────────────────────────────────────────────────┤
│           │      KeplerPlayerServerTurboModule          │
│           ▼                            ▼                │
│  ┌──────────────────┐        ┌──────────────────┐       │
│  │  PlayerServer    │        │   PlayerServer   │       │
│  │  Handler         │        │   Handler        │       │
│  └────────┬─────────┘        └─────────┬────────┘       │
│           │                            │                │
│         Service Layer (PlayerService - Headless JS)     │
│  ┌──────────────────┐        ┌──────────────────┐       │
│  │  Main Player     │        │   Ad Player      │       │
│  │  Session         │        │   Session        │       │
│  │  (VideoPlayer)   │        │   (VideoPlayer)  │       │
│  └──────────────────┘        └──────────────────┘       │
├─────────────────────────────────────────────────────────┤
│           KeplerVideoSurfaceView (Shared)               │
└─────────────────────────────────────────────────────────┘

Use this approach when:

  • Your app uses a multi-threaded architecture with separate UI and service layers
  • You need the performance benefits of JSI-based IPC
  • You want session-based player management with PlayerSession

Packages: Vega Player Client and Vega Player Sever

To implement this approach, see Implement client-side ad insertion using the Headless approach.


Last updated: Mar 26, 2026