External VAST Ads
Render your own VAST tag through the StreamLayer Element with the externalAdData prop, in side-by-side, sidebar, or L-bar format.
Overview
By default, ad units arrive from StreamLayer Studio through the event feed. The externalAdData
prop lets your app drive the ad itself: you hand the SDK a VAST tag URL and the format you want,
and the SDK builds an ad unit from it and renders it through the same pipeline as a Studio-scheduled
ad — including VAST impression, quartile, and click-through tracking.
Use this when the creative is selected by your own ad stack rather than by StreamLayer Studio.
Requires
@streamlayer/react2.0.0 or later.
Quick Start
import { useMemo, useRef } from 'react'
import { StreamLayerProvider } from '@streamlayer/react'
import { StreamLayerSDKAdvertisement } from '@streamlayer/react/advertisement'
import '@streamlayer/react/style.css'
export const Player = () => {
const videoContainerRef = useRef<HTMLDivElement>(null)
// Memoize the object — the SDK keys the injected ad unit on its identity.
const externalAdData = useMemo(
() => ({
vastUrl: 'https://example.com/vast.xml',
uiType: 'side-by-side' as const,
}),
[]
)
return (
<div id="player-root" style={{ position: 'relative' }}>
<div ref={videoContainerRef}>
<video src="https://example.com/stream.m3u8" autoPlay controls />
</div>
<StreamLayerProvider sdkKey="your-sdk-key" event="your-event-id" containerId="player-root">
<StreamLayerSDKAdvertisement
sideBySide
videoRef={videoContainerRef}
externalAdData={externalAdData}
/>
</StreamLayerProvider>
</div>
)
}The ad unit appears as soon as the VAST tag resolves, and is removed when externalAdData changes
to a different tag or the component unmounts.
ExternalAdInput
ExternalAdInputtype ExternalAdUiType = 'side-by-side' | 'sidebar' | 'l-bar'
type ExternalAdInput = {
/** VAST tag URL — raw VAST/VMAP, or a Google Ad Manager ad-tag URL. */
vastUrl: string
/** Which format the ad unit renders in. */
uiType: ExternalAdUiType
}| Field | Type | Description |
|---|---|---|
vastUrl | string | Required. VAST tag URL. Raw VAST/VMAP is fetched directly; a pubads.g.doubleclick.net tag is resolved through Google PAL. |
uiType | 'side-by-side' | 'sidebar' | 'l-bar' | Required. Where the ad unit renders. See the table below. |
Formats
uiType | Renders as | Creative used |
|---|---|---|
'side-by-side' | Double box beside the host video | VAST linear creative, played in the SDK's own player |
'sidebar' | Ordinary sidebar slot | VAST linear creative as the sidebar media |
'l-bar' | Sidebar plus bottom banner strip | Linear creative in the sidebar; the VAST companion ad as the strip |
An 'l-bar' tag whose VAST carries no companion ad degrades to a plain sidebar — no empty strip is
reserved.
The sidebar video autoplays muted. Title and description come from the VAST <AdTitle> and
<Description> elements.
Slot Placement
Explicit host intent wins: an ad injected with uiType renders where the uiType says, regardless
of the VAST streamlayer extension. Ads that arrive from the event feed continue to follow the VAST
extension's adType (side-by-side when absent).
Because an external ad normally belongs to the side-by-side slot, useStreamLayerUI() alone can't
tell you whether to keep your sidebar and banner slots mounted for one. The
useExternalAdPlacement hook resolves this:
import { useStreamLayerUI } from '@streamlayer/react'
import {
StreamLayerSDKAdvertisement,
useExternalAdPlacement,
} from '@streamlayer/react/advertisement'
const Layout = () => {
const uiState = useStreamLayerUI()
const { externalSidebar, externalLbar } = useExternalAdPlacement(uiState.promotionExternalAd)
return (
<>
<aside style={{ width: externalSidebar || uiState.promotionSidebar ? 320 : 0 }}>
<StreamLayerSDKAdvertisement sidebar="right" externalAdData={externalAdData} />
</aside>
{externalLbar && (
<div className="banner">
<StreamLayerSDKAdvertisement banner="bottom" externalAdData={externalAdData} />
</div>
)}
</>
)
}| Return value | Meaning |
|---|---|
externalSidebar | The active external ad resolves to the sidebar or L-bar format — keep the sidebar slot sized. |
externalLbar | The active external ad resolves to L-bar and its VAST carries a companion — keep the banner slot sized. |
Both flip only once the VAST has been parsed, so the sidebar never opens on an empty creative.
Rules and Limits
- Memoize
externalAdData. The SDK derives a stable id fromvastUrl+uiType, but a fresh
object literal on every render still churns the effect that injects and removes the ad unit. Use
useMemo, or a module-level constant when the tag is fully static. - One injected ad at a time. The advertisement store holds a single ad unit, so only one
externalAdDatainstance per page is supported. Injecting replaces any active ad unit, and a
Studio-scheduled ad replaces an injected one. externalAdDataimplies external-ad mode. You do not also need to pass the boolean
externalAdprop for it to render.- Don't double up slots. A slot marked with the boolean
externalAdprop is the programmatic
GAM/PAL slot; it stands down for sidebar and L-bar placements so the plain slot renders the ad
once. This behavior changed in 2.0.0. - Mute the host video. Pass a
videoPlayerControllerso the host stream is muted while the ad's
audio plays. See Video Controller.
Related
- Advertising — Advertisement component integration
- Double Box Ad — Side-by-side layout setup and positioning
- Video Controller — Muting the host video during ad playback
- Integration Guide — Full Web SDK setup and configuration
Updated 10 days ago
