🎬 VAST Integration Guide
Everything you need to know about VAST (Video Ad Serving Template) — from what it is and how it works, to live code examples for every major video player.
📚 On this page
1. What is VAST?
VAST (Video Ad Serving Template) is an XML-based specification published by the IAB (Interactive Advertising Bureau) that defines a standard way for video players to communicate with ad servers. It has been the industry standard since 2008 and is supported by virtually every video player and ad platform in existence.
Before VAST, every ad network had its own proprietary video ad format. Publishers had to integrate each ad network separately. VAST solved this by defining one universal contract between a video player (the client) and an ad server (the server):
Why use VAST?
- Universal compatibility — one VAST URL works with JW Player, Video.js, Flowplayer, Brightcove, and hundreds of other players
- Standardized tracking — impression, click, quartile events all reported automatically by the player
- No SDK required — the player does all the work; you just supply the tag URL
- Full creative control — supports MP4/WebM video files, companion banners, and click-through URLs
- Works with Google IMA — Google's widely-used IMA SDK is fully VAST-compatible
2. How VAST Works — The Request/Response Cycle
Every time a video starts (or a mid-roll position is reached), this sequence happens automatically:
The VAST XML response contains everything the player needs: the video file URL, duration, click-through URL, skip offset, and a list of tracking pixel URLs the player must call at specific moments (start, 25%, 50%, 75%, 100% watched, click, etc.).
3. VAST Versions
Our ad server supports VAST 2.0, 3.0, and 4.0. Here's what each version adds:
VAST 2.0 (2008)
- Core linear (pre-roll) video ads
- Media files (MP4, WebM)
- Click-through tracking
- Impression tracking pixel
- Non-linear (overlay) ads
- Companion banners
- Ad wrapping (VAST Wrapper)
VAST 3.0 Recommended
- Everything in 2.0
- Ad pods (multiple ads in sequence)
- Skippable ads (skip offset)
- Progress tracking events
- Error codes (standardised 900 range)
- Social actions tracking
- Icon support
VAST 4.0 / 4.2 (2016–2022)
- Everything in 3.0
- Universal Ad ID (ISCI code)
- Viewability measurement (OMID)
- InteractiveCreativeFile (SIMID)
- Muted autoplay support
- AdVerifications (third-party)
- Category / content targeting
4. Your Personal VAST URL
Your VAST URL is unique to your publisher account. It contains your publisher key which identifies you for earnings attribution and tracking. Keep it private.
YOUR_PUBLISHER_KEY with your actual key from the dashboard.https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY
Adding optional parameters
You can append parameters to control targeting and ad selection. For example, to serve only pre-roll ads at 1920×1080:
https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY&position=preroll&width=1920&height=1080
See the full URL Parameters reference below for all options.
5. Player Integration Examples
Choose the player you use. All examples use your VAST URL — replace YOUR_VAST_URL with the value from the box above.
JW Player 8 / 9
Add the advertising block to your existing jwplayer().setup() call.
jwplayer("player-container").setup({ playlist: [{ file: "https://example.com/your-video.mp4", image: "https://example.com/thumb.jpg" }], advertising: { client: "vast", // use "googima" for IMA SDK on JW8+ tag: "https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY", schedule: [{ offset: "pre", // "pre", "post", or seconds for mid-roll tag: "https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY" }] } });
client: "googima" for better skip-ad and quartile tracking support.Video.js + Google IMA3 SDK (recommended)
The most robust approach — uses Google's free IMA3 SDK which handles all VAST/VPAID logic.
<!-- 1. Include dependencies in <head> --> <link href="https://vjs.zencdn.net/8/video-js.css" rel="stylesheet"> <script src="https://vjs.zencdn.net/8/video.js"></script> <script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-ads/6.9.0/videojs.ads.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-ima/1.10.1/videojs.ima.min.js"></script> <!-- 2. Player element --> <video id="my-player" class="video-js vjs-default-skin" controls preload="auto" width="640" height="360" data-setup="{}"> <source src="https://example.com/video.mp4" type="video/mp4"> </video> <!-- 3. Initialise IMA plugin --> <script> var player = videojs('my-player'); player.ima({ adTagUrl: 'https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY', debug: false, prerollTimeout:5000 // ms to wait for VAST response }); </script>
Video.js + videojs-vast-vpaid Plugin (lightweight)
<script src="https://vjs.zencdn.net/8/video.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-ads/6.9.0/videojs.ads.min.js"></script> <!-- videojs-vast by MailOnline --> <script src="https://cdn.jsdelivr.net/npm/[email protected]/bin/videojs.vast.vpaid.js"></script> <script> var player = videojs('player'); player.vast({ url: 'https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY' }); </script>
Flowplayer 7 / 8
flowplayer('#player', { clip: { sources: [ { type: 'video/mp4', src: 'https://example.com/video.mp4' } ] }, ima: { ads: [ { time: 0, // 0 = pre-roll; integer seconds for mid-roll adTag: 'https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY' } ] } });
npm install @flowplayer/player-ima or add the CDN script.Plain HTML5 + Google IMA SDK (no framework)
Minimum code to serve a pre-roll ad with Google's free IMA SDK, no video.js required.
<!DOCTYPE html> <html><head> <script src="https://imasdk.googleapis.com/js/sdkloader/ima3.js"></script> </head><body> <div id="content-wrapper" style="position:relative;width:640px;height:360px;"> <video id="content-video" width="640" height="360" src="https://example.com/video.mp4"></video> <div id="ad-container" style="position:absolute;top:0;left:0;width:100%;height:100%;"></div> </div> <script> var adDisplayContainer, adsLoader, adsManager; var videoElement = document.getElementById('content-video'); var adContainer = document.getElementById('ad-container'); var AD_TAG_URL = 'https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY'; function init() { adDisplayContainer = new google.ima.AdDisplayContainer(adContainer, videoElement); adsLoader = new google.ima.AdsLoader(adDisplayContainer); adsLoader.addEventListener(google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded); var req = new google.ima.AdsRequest(); req.adTagUrl = AD_TAG_URL; req.linearAdSlotWidth = 640; req.linearAdSlotHeight = 360; adsLoader.requestAds(req); } function onAdsManagerLoaded(e) { adsManager = e.getAdsManager(videoElement); adsManager.init(640, 360, google.ima.ViewMode.NORMAL); adsManager.start(); } videoElement.addEventListener('play', function() { adDisplayContainer.initialize(); init(); }, { once: true }); </script> </body></html>
MediaOnDemand / UVP
- Login → Playlists → Edit your playlist.
- Enable Monetization tab → set Ad Delivery Format to VAST XML.
- Paste your VAST URL into the VAST Tag field.
- Set Ad Position to Pre-roll, Mid-roll, or Post-roll and save.
6. VAST XML Structure Explained
When a player fetches your VAST URL it receives XML like this. Understanding it helps when debugging:
<VAST version="3.0"> <Ad id="ad-123"> <InLine> <!-- Ad server name (informational) --> <AdSystem>Unlimited Text Ads</AdSystem> <AdTitle>My Video Campaign</AdTitle> <!-- Fires once when ad starts rendering in player --> <Impression></Impression> <Creatives> <Creative> <Linear> <!-- Total video length --> <Duration>00:00:30</Duration> <!-- User can skip after 5s (remove to make non-skippable) --> <SkipOffset>00:00:05</SkipOffset> <TrackingEvents> <Tracking event="start"></Tracking> <Tracking event="firstQuartile"></Tracking> <Tracking event="midpoint"></Tracking> <Tracking event="thirdQuartile"></Tracking> <Tracking event="complete"></Tracking> </TrackingEvents> <!-- Where user goes on click --> <VideoClicks> <ClickThrough></ClickThrough> <ClickTracking></ClickTracking> </VideoClicks> <!-- Actual video files, in order of preference --> <MediaFiles> <MediaFile type="video/mp4" width="1280" height="720" bitrate="2000" delivery="progressive"> </MediaFile> </MediaFiles> </Linear> </Creative> </Creatives> </InLine> </Ad> </VAST>
7. Tracking Events
The player automatically fires HTTP GET requests (pixel pings) to the tracking URLs in the VAST XML at each of these moments. Each event is recorded in your dashboard:
8. URL Parameters — Control Which Ads Play
Append these query parameters to your VAST URL to customise ad delivery per placement or per page.
| Parameter | Required? | Values | Description |
|---|---|---|---|
publisher_id | Required | 32-char hex key | Your publisher key — identifies your account for earnings and tracking |
position | Optional | preroll, midroll, postroll | Tells the ad server which position ad should fill (default: preroll) |
width | Optional | Integer pixels | Preferred video width. Ad server picks the closest matching media file (default: 1280) |
height | Optional | Integer pixels | Preferred video height (default: 720) |
ad_id | Optional | Integer ID | Force a specific ad to play. Useful for previewing or guaranteed delivery |
campaign_id | Optional | Integer ID | Serve only ads from a specific campaign (rotated randomly) |
placement | Optional | Placement code | Link to a placement. Enables 30% house-ad rotation for that placement owner |
house | Optional | 0 or 1 | Set 1 to serve 100% house ads for the placement (requires placement) |
url | Optional | URL-encoded page URL | Referring page URL for geo/context targeting. Auto-captured by referer header if omitted |
ip | Optional | IPv4 / IPv6 | Override visitor IP for geo-targeting (useful for server-side VAST proxy setups) |
Example URLs
# Default — serve random active video ad https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY # Pre-roll at 1920×1080 resolution https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&position=preroll&width=1920&height=1080 # Mid-roll: fires at whatever time the player requests https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&position=midroll # Only ads from campaign 42 https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&campaign_id=42 # Force a specific ad (by ID) — for testing https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&ad_id=7 # Placement with 30% house ads, 70% network ads https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&placement=PLC_XXXXXX # Force 100% house ads for a placement https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_KEY&placement=PLC_XXXXXX&house=1
9. Testing & Validation Tools
Google IMA Video Suite Inspector
Paste your VAST URL and Google plays it in a full IMA-powered test player. Shows all parsed events in real time.
IAB VAST Inspector
Official IAB VAST inspecting and validation tool. Verifies XML structure and compliance.
SpringServe VAST Debugger
Detailed VAST tag debugger with wrapper chain analysis, media file preview, and tracking event check.
Browser DevTools
Open Network tab and filter for vast.php to inspect the raw XML response and all tracking pixel fires.
Quick test with curl
# Fetch and pretty-print your VAST XML curl -s "https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY" | xmllint --format - # Check HTTP status code only curl -o /dev/null -s -w "%{http_code}" "https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY" # Follow redirects (for VAST Wrapper chains) curl -L -s "https://unlimitedtextads.com/api/vast.php?publisher_id=YOUR_PUBLISHER_KEY" | xmllint --format -
A valid response returns HTTP 200 with Content-Type: application/xml and starts with <VAST version=. An empty VAST (no active ads) still returns 200 with an empty <VAST></VAST> document — this is correct IAB behaviour.
10. Troubleshooting
| Symptom | Most likely cause | Fix |
|---|---|---|
| Empty VAST / no ad plays | No active video ads in the system | Create an active video ad with a valid MP4 URL in the Ads page |
| Video loads but won't play | Media file is HTTP not HTTPS, or not MP4 | Ensure the media URL is HTTPS and encodes as H.264 / AAC MP4 |
| CORS error in browser console | Server blocks cross-origin VAST requests | Our server sends Access-Control-Allow-Origin: *. If error persists, check your hosting's WAF rules |
| Impression tracked but no click earnings | Click tracking URL not pinged by player | Ensure ClickTracking is present in VAST XML (curl and inspect). Some lightweight players skip this. |
| Duration shows 0:00 | Video file has no duration metadata | Re-encode with FFmpeg: ffmpeg -i input.mp4 -c copy -movflags +faststart output.mp4 |
| VAST wrapper chain error | 3+ wrapper hops timing out | Test each VAST URL in the wrapper chain individually using curl |
| Ads not serving on mobile | Some mobile browsers block autoplay | Add muted attribute and use playsinline on video element. Use IMA SDK v3.550+ |
| Skip button not showing | Player doesn't support VAST 3.0 skip | Upgrade to JW Player 8+ or use Google IMA SDK |
11. Frequently Asked Questions
Ready to run video ads?
Create a video campaign as an advertiser, or paste your VAST URL into your video player as a publisher to start earning.