Skip to content

API

The bundle exposes one global with one method:

const handle = window.adnzVP.renderVideoAd(config);

renderVideoAd is synchronous: it validates the configuration, mounts the slot and returns a lifecycle handle immediately; loading and playback continue in the background. Invalid configuration (no VAST source, both sources at once, missing or too-small targetEl) throws right away.

OptionTypeRequiredDescription
vastXmlstringone of the two sourcesInline VAST document. Preferred when you already have the XML (e.g. from a Prebid bid).
vastUrlstringone of the two sourcesVAST tag URL — the player fetches it itself. See vastUrl notes.
targetElHTMLElementyesThe slot element. Must be at least 256×256 px and sized by the page.
renderMode'native' | 'iframe'yesiframe renders the video engine in a same-origin iframe for full style isolation; controls stay on the parent page.
viewabilityobjectno{ threshold, dwellMs }. Fraction of the slot that must be visible (default 0.5) and how long it must stay visible before playback resumes (default 2000 ms). The threshold also gates the initial playback start: the ad does not start (and no impression fires) until the slot is first in view.
adLabelTextstringnoText of the ad disclosure badge. Default 'Werbung'.
consentobjectnoPre-fetched consent: { tcString, gdprApplies, gppString }. When omitted, the player reads window.__tcfapi (TCF v2) and window.__gpp (GPP) itself.

Exactly one of vastXml / vastUrl must be provided.

The ad request is sent as soon as the player mounts (after the consent read), but playback only starts when the slot first becomes visible: at least viewability.threshold of it inside the viewport, in a non-hidden tab. The VAST impression fires at playback start, not at render — an off-screen or background-tab slot does not consume impressions. If the rendering engine stops responding before playback starts, the player gives up after 15 seconds and emits error.

const handle = window.adnzVP.renderVideoAd(config);
const unsubscribe = handle.on('started', () => console.log('ad started'));
handle.dispose(); // remove the ad, its DOM and all listeners; idempotent
  • handle.on(event, listener) — subscribe to a lifecycle event; returns an unsubscribe function.
  • handle.dispose() — tear the ad down. Safe to call multiple times. Call it on SPA route changes in standalone integrations.
EventFired whenSlot after the event
startedPlayback starts (also fires again on replay).playing
completedThe ad played to the end.endcard with a replay button
pausedPlayback pauses (user click, the slot scrolled out of view, or the tab went to the background).paused
resumedPlayback resumes.playing
mutedSound muted.unchanged
unmutedSound unmuted.unchanged
clickThe viewer clicked through to the advertiser.unchanged (clickthrough opens in a new tab)
skippedThe viewer pressed skip.removed automatically
closedThe viewer pressed close.removed automatically
no-fillThe ad server returned no ad.removed automatically — show your fallback
errorLoading or playback failed, or the rendering engine gave no signal for 15 seconds. The listener receives { code?, message? }.removed automatically

Events marked removed automatically are terminal: the player cleans the slot up by itself, so the page can reclaim the space — there is no need to call dispose() after them. The event is always delivered to your listeners before the teardown.

Replay (the endcard button) re-plays the already-delivered media locally: started fires again on the handle, but no new impression and no quartile/progress events are sent to the ad server. User interactions during a replay still fire their pixels — a click-through pings ClickTracking (the user really visited the advertiser) and a skip pings the skip-tracking URLs. The replay button only appears when the media can actually be re-played; if a replay fails to load, the slot falls back to the endcard without the button.

handle.on('error', (info) => {
console.warn('ad failed', info?.code, info?.message);
});

info.code carries the IMA AdError code (a positive number) for VAST/media failures. Watchdog errors — the rendering engine gave no signal at all — use the distinct code -1 (exported as WATCHDOG_ERROR_CODE), so monitoring can separate the two.

When you pass vastUrl, the player fetches the document itself:

  • The request is sent with credentials (cookies). The ad server must answer with an echoed Access-Control-Allow-Origin and Access-Control-Allow-Credentials: true — standard for VAST endpoints, including Xandr. Servers that only send Access-Control-Allow-Origin: * get an automatic cookie-less retry.
  • The fetch times out after 10 seconds and surfaces as the error event.
  • URL macros are not expanded ([CACHEBUSTING], ${GDPR_CONSENT_…}, …) — pass a fully expanded URL.
  • Wrapper responses are resolved by the rendering engine; for wrapper tags the skip button and the clickthrough surface come from the engine UI rather than the player chrome.

With no consent option, the player queries the page CMP on every render: TCF v2 via window.__tcfapi and GPP via window.__gpp (CMP API 1.1). It waits for the CMP to reach a settled state, capped at one second, and only then requests the ad. If your integration already has the consent strings, pass them in config.consent to skip the CMP read.