Double Box Ad
The Double Box Ad integration enables cinematic, high-impact advertising within the StreamLayer TV SDK. When a promotion activates, the video player smoothly shrinks to half its width and an ad panel appears beside it. The SDK manages all positioning, animation, and layout — you only need to wire up a few props on the StreamLayerSDKTv component.
Overview
The double box ad format splits the screen into a 50/50 layout — the video player animates into the left half while ad content appears on the right. The SDK handles all positioning, animation, and responsive behavior automatically.
Prerequisites
Ensure you have completed the Integration Guide before adding double box ads.
Integration
Step 1 — Install Packages
Install the StreamLayer TV SDK:
npm install @streamlayer/web-osStep 2 — Import Styles
Import the SDK stylesheet in your application entry point. This is required — without it the double box layout, animations, and all other SDK UI will render without styles.
import '@streamlayer/web-os/style.css'Step 3 — Set Up the Layout
Pass the doubleBox prop to StreamLayerSDKTv alongside a videoRef pointing to your video container element. When a double box ad activates, the SDK takes control of the video element's position and smoothly animates it into the left frame of the 50/50 split layout.
import { useRef } from 'react'
import { StreamLayerProvider, StreamLayerSDKTv } from '@streamlayer/web-os'
import '@streamlayer/web-os/style.css'
export const Main = () => {
const videoContainerRef = useRef<HTMLDivElement>(null)
return (
<StreamLayerProvider sdkKey="your-sdk-key" event="your-event-id">
<div id="player-root" style={{ position: 'relative' }}>
<div ref={videoContainerRef}>
<video src="https://example.com/stream.m3u8" autoPlay controls />
</div>
<StreamLayerSDKTv
doubleBox
videoRef={videoContainerRef}
>
{/* StreamLayerSDKTv manages interactive units */}
</StreamLayerSDKTv>
</div>
</StreamLayerProvider>
)
}Important: The video's parent container must have
position: relativefor correct absolute positioning.
Props
| Prop | Type | Description |
|---|---|---|
doubleBox | boolean | Required. Enables double box ad mode. |
externalAd | boolean | Enables VAST/GAM external ad support. When true, the SDK renders VAST video ads. |
muted | boolean | Mutes the active ad video. Default: false. |
videoRef | React.RefObject<HTMLElement | null> | Required. Ref to the host video container for positioning. |
videoPlayerController | VideoPlayerCallback | Callback for video control events (mute, play) during ad playback. |
persistent | boolean | Show the ad each time it activates, ignoring the "already viewed" check. |
VideoPlayerCallback
type VideoPlayerCallback = (data: { muted?: boolean; play?: boolean }) => voidRegister this callback to react to SDK-initiated video control events. For example, when an external VAST ad plays, the SDK may request muting the host video.
How It Works
- Promotion activates — the SDK renders the ad layout off-screen to measure the target slot dimensions.
- Style capture — the SDK snapshots the video element's current inline styles so they can be restored later.
- Animated transition — the video element receives
position: absoluteand is smoothly transitioned (750ms) into the left half of the layout while the ad content fades in on the right. - Live tracking — a
ResizeObserverwatches the layout slot, keeping the video coordinates up-to-date on window or container resize. - Ad closes — the video transitions back to its original size and position, and the saved inline styles are restored.
Note: The SDK temporarily overrides the video element's inline styles while the ad is visible. Avoid setting the same style properties on the video element during this time.
Implementation Example
import { useCallback, useRef, useState } from 'react'
import { StreamLayerProvider, StreamLayerSDKTv, type VideoPlayerCallback } from '@streamlayer/web-os'
import '@streamlayer/web-os/style.css'
export const VideoView = () => {
const videoRef = useRef<HTMLVideoElement>(null)
const videoContainerRef = useRef<HTMLDivElement>(null)
const [muted, setMuted] = useState(false)
// Called when SDK requests video control (e.g., mute during external ad)
const videoPlayerController: VideoPlayerCallback = useCallback((data) => {
if (!videoRef.current) return
if (data.muted !== undefined) {
videoRef.current.muted = data.muted
setMuted(data.muted)
}
if (data.play === true) {
videoRef.current.play()
}
}, [])
return (
<StreamLayerProvider sdkKey="your-sdk-key" event="your-event-id">
<div style={{ position: 'relative' }}>
<div ref={videoContainerRef}>
<video
ref={videoRef}
src="https://example.com/stream.m3u8"
autoPlay
controls
/>
</div>
<StreamLayerSDKTv
doubleBox
externalAd
videoRef={videoContainerRef}
videoPlayerController={videoPlayerController}
muted={muted}
>
{/* StreamLayerSDKTv manages interactive units */}
</StreamLayerSDKTv>
</div>
</StreamLayerProvider>
)
}Key Points
videoRefis required: Pass a ref to your video container element. The video's parent must haveposition: relative.- Enable
externalAdfor VAST ads: If your promotions include external VAST/GAM video ads, passexternalAdalongsidedoubleBox. - Register
videoPlayerController: Implement this callback to respond to SDK-initiated mute/play requests during ad playback. - Don't fight inline styles: The SDK temporarily overrides video element styles during ad playback. Avoid modifying the same properties while an ad is active.
Muting the Host Video During Ad Playback
When a double box ad includes audio (e.g., an external VAST video ad), two audio sources play simultaneously — the host video stream and the ad. The SDK uses the videoPlayerController callback to request that the host video is muted while the ad is playing and unmuted when the ad ends.
How it works
- The SDK calls your
videoPlayerControllerwith{ muted: true }when an ad with audio starts playing. - When the ad ends, pauses, or is dismissed, the SDK calls it again with
{ muted: false }. - Your callback is responsible for actually muting the host
<video>element (or your third-party player).
Basic implementation
const videoPlayerController: VideoPlayerCallback = useCallback((data) => {
if (!videoRef.current) return
if (data.muted !== undefined) {
videoRef.current.muted = data.muted
}
}, [])Implementation with volume reduction
If you prefer to reduce volume instead of fully muting, you can lower the volume and restore it when the ad finishes:
const savedVolume = useRef(1)
const videoPlayerController: VideoPlayerCallback = useCallback((data) => {
if (!videoRef.current) return
if (data.muted === true) {
savedVolume.current = videoRef.current.volume
videoRef.current.volume = 0.1 // reduce to 10%
} else if (data.muted === false) {
videoRef.current.volume = savedVolume.current
}
}, [])Important: Always pass the
videoPlayerControllercallback alongsideexternalAdwhen using external VAST ads. Without it, the host video and the ad will play audio simultaneously, resulting in a poor user experience.
Related
- Integration Guide — Full TV SDK setup and configuration
- Exposed Pause Ad — Pause ad overlay integration
- Split Components — Independent component placement
- Getting Started — Supported platforms and quick-start path
Updated about 2 months ago
