mpwa Video Player
VAST 4.0 InLine + AdPod + Companion player for the web. Vanilla TypeScript, ~11 KB minified, zero runtime dependencies.
Version 0.1.0 · ~11 KB
VAST-ready in one tag
Drop a single <script> + a data-attributed slot anywhere on your page. The player fetches the VAST XML, picks the best MP4 (or HLS) MediaFile for the viewer's bandwidth, renders quartile + click tracking, and gracefully exits on completion or skip.
Quick start (auto-init)
The simplest path: a script + a data-attribute. The player auto-wires on DOMContentLoaded.
<!-- 1. Load the player. ~11 KB minified, no dependencies. -->
<script async src="https://mpwa.to/sdk/v1/video-player.min.js"></script>
<!-- 2. Drop a slot that auto-plays a VAST ad. -->
<div data-mpwa-video-ad
data-vast-url="https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID"
data-skip-after="5"
data-locale="en"
style="width:640px; max-width:100%"></div>Programmatic control
Need to start an ad on a user gesture, hook lifecycle events, or destroy on route change? Use the JS API.
<script async src="https://mpwa.to/sdk/v1/video-player.min.js"></script>
<div id="my-video-slot" style="width:640px; max-width:100%"></div>
<div id="my-companion-slot"></div>
<script>
window.addEventListener('DOMContentLoaded', async function () {
const handle = await MpwaVideoPlayer.play({
container: document.getElementById('my-video-slot'),
companionContainer: document.getElementById('my-companion-slot'),
url: 'https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID',
skipAfter: 5,
autoplay: true,
muted: true,
locale: 'en',
onEvent: function (event, ad) { console.log('vast.event', event, ad.id); },
onError: function (err) { console.warn('player error', err); },
});
// handle.skip() to skip programmatically
// handle.destroy() to tear down
await handle.done;
});
</script>AdPod (sequenced ads)
The ad-server emits N sequenced <Ad> elements when you pass ?pod_size=N. The player plays them back to back; quartiles + tracking fire per ad.
<!-- AdPod: 3 ads, sequenced. Player plays them back to back. -->
<div data-mpwa-video-ad
data-vast-url="https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID&pod_size=3"
data-skip-after="5"></div>Outstream (in-article / in-feed)
Outstream mode auto-pauses when the player scrolls out of viewport and resumes when it scrolls back in (IntersectionObserver). The slot collapses on completion so the editorial flow reclaims the space.
<!-- Outstream: auto-pauses when scrolled out of viewport. -->
<!-- Drop between paragraphs of editorial content. -->
<div data-mpwa-video-ad
data-vast-url="https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID"
data-outstream="true"
data-viewability-threshold="0.5"
data-skip-after="5"
style="width:100%; max-width:640px; margin:24px auto"></div>Same behaviour via the JS API. Tune the visibility threshold and decide whether to collapse the slot on completion.
import { play } from 'https://mpwa.to/sdk/v1/video-player.esm.js';
await play({
container: document.getElementById('slot'),
url: 'https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID',
outstream: true,
viewabilityThreshold: 0.5, // 50% of player visible to play
collapseOnComplete: true, // collapse the slot when the ad ends
});ESM import
For bundlers (Vite/Rollup/webpack) — same surface as the IIFE.
import { play } from 'https://mpwa.to/sdk/v1/video-player.esm.js';
await play({
container: document.getElementById('slot'),
url: 'https://ads.mpwa.to/v1/ad/vast?ad_unit_id=YOUR_AD_UNIT_ID',
skipAfter: 5,
});Options
| Name | Type | Default | Description |
|---|---|---|---|
| container | HTMLElement | — | DOM element the player attaches to. Required. |
| url | string | — | VAST XML endpoint to fetch. Either url or xml is required. |
| xml | string | — | VAST XML body inline. Useful when you've pre-fetched it. |
| skipAfter | number | 5 | Seconds before the Skip button activates. 0 disables skip. |
| autoplay | boolean | true | Start playing immediately. Browsers require muted=true for unattended autoplay. |
| muted | boolean | true | Start muted. Toggle via the native controls. |
| controls | boolean | true | Show native browser video controls in addition to the Skip button. |
| companionContainer | HTMLElement | — | DOM element where Companion ads render. |
| locale | 'en' | 'ar' | 'en' | UI string locale for the Skip button + ad label. |
| outstream | boolean | false | Enable outstream mode. Auto-pauses on scroll-out, auto-plays on scroll-in. |
| viewabilityThreshold | number | 0.5 | Fraction of player area (0–1) that must be visible to play. Outstream only. |
| collapseOnComplete | boolean | outstream | Hide the slot when the ad finishes. Defaults to true in outstream mode, false otherwise. |
| onEvent | (event, ad) => void | — | Lifecycle callback fired after each VAST event (debug/analytics hook). |
Tracking events
These VAST verbs are fired automatically; corresponding <Tracking> URLs in the VAST XML are pixel-pinged via navigator.sendBeacon.
Direct downloads
Both the IIFE and ESM bundles cache for 1 year on /sdk/v1/. Breaking changes bump to /sdk/v2/.