VAST Tag Explained: How It Works, What's Inside, and Which Version to Use

Nov 03, 2026 10 min read
Author Photo
Kate Novatska AdTech Expert
VAST Ad Server: What It Is, Why It Matters, and How Epom Does It Better

A sponsor's pre-roll goes live across your network. Some players show a black screen, the advertiser's report shows zero quartiles, and every empty break is inventory you can't bill. What to do in this situation? We explain.

In most cases the creative is fine and the VAST tag is to blame. The tag is a URL that asks for the ad; the response is the XML that tells the player what to play and what to count. This guide shows where each one breaks, how to read the error codes, and how to fix them.

Got a tag that plays nothing right now? Paste it, or the raw XML, into the free Epom VAST Inspector. It plays the tag in a real player and, if it fails, shows the error code, what it means and where in the wrapper chain it broke.

TL;DR:
  • A VAST tag is an ad request URL that returns an XML response telling a video player which ad to play, where the media file is, and which events to track.
  • The tag goes wherever a player asks for ads: a web player's ad settings, Google's IMA SDK, an SSP or Google Ad Manager line item, or a server-side ad insertion (SSAI) stitcher.
  • Many failures report an error code. VAST codes 100–102 mean broken XML or an unsupported version, 301–303 point to wrappers, and 400–405 to media files. Google's IMA SDK adds its own codes from 1000.
  • Request the highest VAST version your player supports. VAST 4.1 added Open Measurement (OMID, the IAB's shared viewability interface) and VAST 4.2 added SIMID (the IAB standard for interactive video ads).
  • The player must fill a few macros: a cache buster, the page URL or app bundle, the device ID and the consent string. Without them, targeting and frequency capping break.
  • A VAST ad server generates the tag and decides what comes back. Epom Ad Server serves VAST 2.0 through 4.3 (4.2 by default in the new interface), fills ad pods of up to 20 ads, and adds Open Measurement on VAST 4.1+.

What Is a VAST Tag?

A VAST tag is an ad request URL that returns an XML response telling a video player which ad to play, where the media file is, and which events to track. It's also called a VAST ad tag or a VAST URL. VAST stands for Video Ad Serving Template, a standard the IAB introduced in 2008 and IAB Tech Lab maintains today.

The tag and the response are two different things. The VAST tag is the URL, with parameters and macros; the VAST response, or VAST XML, is what comes back.

VAST tag (the request the player sends):

```text
https://ads.example.com/vast?placement=12345&vastv=4.2&cb=[CACHEBUSTING]&pageurl=[PAGEURL]
```

VAST response (the XML that comes back, shortened):

```xml
<VAST version="4.2">
  <Ad id="20026">
    <InLine>
      <AdTitle>Spring Sale 15s</AdTitle>
      <Impression><![CDATA[https://track.example.com/imp]]></Impression>
      <Creatives>
        <Creative>
          <Linear>
            <Duration>00:00:15</Duration>
            <MediaFiles>
              <MediaFile type="video/mp4" width="1920" height="1080"><![CDATA[https://cdn.example.com/spring.mp4]]></MediaFile>
            </MediaFiles>
          </Linear>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>
```

VAST tags run in-stream (pre-roll, mid-roll and post-roll), in outstream video ads, in apps and on CTV. The ads they deliver are often called VAST ads, and a VAST tag is one type of ad tag.

Why Do Advertisers and Publishers Use VAST Tags?

VAST advertising works because every party shares one format. An advertiser sends the same tag, tracking pixels and companion banners to every player. A publisher can fill its player from any ad server, DSP or SSP that speaks VAST.

One VAST tag runs in web, app and CTV players, and one player accepts VAST from an ad server, a DSP and an SSP

How Does a VAST Tag Work?

A VAST tag works in five calls between four parties. The player calls the tag with macros filled in, and the ad server returns the VAST response.

The player then loads a media file from the CDN and fires tracking URLs as the ad plays. If anything fails, it calls the Error URL with a code.

How a VAST tag works: five calls between the video player, ad server, CDN and tracking servers


The ad server answers only the first call. Everything after it, including the counting, happens between the player, the CDN and the trackers.

Where Does a VAST Tag Go?

A VAST tag goes into whatever component requests ads for the VAST player. That choice decides who calls the tag, who fills the macros and how many hops stand between the player and the ad.

Where How the tag is used
Player configurationMost web players take an ad tag URL in their advertising settings, for example JW Player's VAST client or Video.js with the IMA plugin.
Google IMA SDKSet as `adTagUrl` in the ad request, on web, Android or iOS. IMA plays third-party VAST tags.
SSP, ad network or Google Ad ManagerAdded as third-party demand: a VAST redirect creative in Google Ad Manager, or a demand tag in an SSP. The SSP calls your tag and passes the response on.
SSAI stitcherSet as the ad decision server URL in the stitcher, such as AWS MediaTailor. The stitcher calls the tag server-side.

A player fills macros from the page or device, while a stitcher must forward the viewer's data. An SSP or Google Ad Manager in the middle usually adds a wrapper, which means more latency and one more place to fail.

VAST Tag Example: Anatomy of a VAST Response

This VAST example shows a complete inline VAST 4.2 response for a 15-second linear ad. Domains are placeholders.

```xml
<VAST version="4.2" xmlns="http://www.iab.com/VAST">
  <Ad id="20026" sequence="1">
    <InLine>
      <AdSystem version="1.0">Example Ad Server</AdSystem>
      <AdServingId>a1b2c3d4-e5f6</AdServingId>
      <AdTitle>Spring Sale 15s</AdTitle>
      <Impression id="imp-1"><![CDATA[https://track.example.com/imp?cb=[CACHEBUSTING]]]></Impression>
      <Error><![CDATA[https://track.example.com/error?code=[ERRORCODE]]]></Error>
      <AdVerifications>
        <Verification vendor="verifier.example.com-omid">
          <JavaScriptResource apiFramework="omid" browserOptional="true">
            <![CDATA[https://verify.example.com/omid.js]]>
          </JavaScriptResource>
        </Verification>
      </AdVerifications>
      <Creatives>
        <Creative id="cr-501" adId="ad-501">
          <UniversalAdId idRegistry="ad-id.org">ABCD1234000H</UniversalAdId>
          <Linear skipoffset="00:00:05">
            <Duration>00:00:15</Duration>
            <TrackingEvents>
              <Tracking event="start"><![CDATA[https://track.example.com/start]]></Tracking>
              <Tracking event="firstQuartile"><![CDATA[https://track.example.com/q1]]></Tracking>
              <Tracking event="midpoint"><![CDATA[https://track.example.com/mid]]></Tracking>
              <Tracking event="thirdQuartile"><![CDATA[https://track.example.com/q3]]></Tracking>
              <Tracking event="complete"><![CDATA[https://track.example.com/complete]]></Tracking>
              <Tracking event="skip"><![CDATA[https://track.example.com/skip]]></Tracking>
            </TrackingEvents>
            <VideoClicks>
              <ClickThrough><![CDATA[https://advertiser.example.com/spring]]></ClickThrough>
              <ClickTracking><![CDATA[https://track.example.com/click]]></ClickTracking>
            </VideoClicks>
            <MediaFiles>
              <MediaFile delivery="progressive" type="video/mp4" width="1920" height="1080" bitrate="4000">
                <![CDATA[https://cdn.example.com/spring-1080.mp4]]>
              </MediaFile>
              <MediaFile delivery="progressive" type="video/mp4" width="640" height="360" bitrate="800">
                <![CDATA[https://cdn.example.com/spring-360.mp4]]>
              </MediaFile>
              <Mezzanine delivery="progressive" type="video/mp4" width="1920" height="1080">
                <![CDATA[https://cdn.example.com/spring-mezzanine.mp4]]>
              </Mezzanine>
            </MediaFiles>
          </Linear>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>
```
Element What it does
`<Ad>` / `sequence`One ad; the sequence number orders ads inside an ad pod.
`<InLine>`Marks the response as carrying the ad itself, not a pointer to another server.
`<Impression>`URL the player calls when the ad starts rendering. This is where an impression is counted.
`<Error>`URL the player calls with an error code when playback fails.
`<AdVerifications>`Loads verification scripts. The element arrived in VAST 4.0; Open Measurement became the standard path in VAST 4.1.
`<UniversalAdId>`A creative ID, such as an Ad-ID code, that stays the same across ad servers. Required for linear ads since VAST 4.0.
`<Linear>` / `skipoffset`An in-stream ad; skipoffset sets when the Skip button appears.
`<TrackingEvents>`VAST tracking URLs that fire at playback milestones: start, quartiles, complete, skip.
`<VideoClicks>`ClickThrough is the landing page; ClickTracking records the click.
`<MediaFiles>` / `<Mezzanine>`The video renditions the player picks from, plus a high-quality source file for stitchers to transcode.

Overlays use a <NonLinear> element, and companion banners use <CompanionAds>. For more samples, see IAB Tech Lab's VAST repository on GitHub.

What Is a VAST Wrapper? Inline vs Wrapper Tags

A VAST wrapper is a VAST response that points the player to another ad server's VAST tag. It carries no ad itself: it adds its own tracking URLs and hands the player a new tag to call.

Each hop adds latency and a new point of failure. Players cap the number of hops they follow, and past the cap they report error 302. Ask demand partners for inline tags where possible.

How to Debug a VAST Tag: Symptoms, Error Codes and Fixes

Start with the symptom, find the error code in the player log or your Error URL reports, then check the likely cause. Run every tag through a VAST tag tester and validator before launch.

Symptom VAST error Likely cause What to check
Black screen, no ad request in the network panelnoneThe player never called the tagAd tag URL in the player config; ad blockers; CORS errors in the console
Response arrives but the player rejects it100, 101XML is malformed or fails schema validationRun the response through a validator; look for unescaped characters in URLs
Player ignores a valid response102VAST version not supported by the playerRequest a version the player supports
Empty response, nothing playsEmpty `<VAST/>` (303 if it came through a wrapper)No eligible ad: targeting, frequency cap, budget or unfilled macrosCampaign targeting and pacing; whether macros were replaced
Long delay, then nothing301A wrapper hop timed outResponse time of each partner in the chain
Nothing plays after several redirects302Wrapper chain longer than the player allowsNumber of hops; ask for an inline tag
Ad loads in a tester but not on the site401, 402Media file not found or too slow to loadOpen the file URL; CDN and CORS settings; a lower-bitrate rendition
Nothing plays on CTV or mobile403No media file matches the device, for example a VPAID-only creativeAdd an MP4 rendition in a supported size
Ad plays, quartiles stay at zerononeTracking URLs blocked, not fired or not URL-encodedWatch the tracking calls in the network panel
Your impression count is higher than the advertiser'snoneDifferent counting points, or trackers blocked on some devicesCompare counting definitions; see our guide to ad discrepancy

Paste a failing tag into the Epom VAST Inspector to see which code it triggers and what to fix.

Your Player Says X: IMA and VAST Error Codes Side by Side

Most players don't show the IAB code alone. Google's IMA SDK passes VAST codes (below 1000) through unchanged and adds its own codes from 1000 up. They run 1000–1099 for requests and responses, 1100–1199 for SDK usage and 1200–1299 for playback.

JW Player shows the same IMA errors with a five-digit prefix, so 1009 appears as 21009.

Your player says It means Fix
IMA 1009 (JW Player 21009)The ad server answered with an empty VAST response: no eligible adCheck targeting, frequency caps and pacing; check that macros were replaced
IMA or VAST 303A wrapper led to a third-party server that returned no adTest the third-party tag on its own; your campaign setup is usually fine
IMA or VAST 301The tag or a wrapper hop timed out. IMA gives each request only a few seconds, and every hop spends part of that timeCheck each partner's response time; remove hops
IMA or VAST 302Too many wrapper redirectsAsk the partner for an inline tag
IMA 1010The response couldn't be parsed as VAST, the IMA counterpart of VAST 100Validate the XML; look for HTML error pages or unescaped characters
IMA 1007 (JW Player 21007)No media file this player can use, close to VAST 403Add an MP4 rendition in a supported size; drop VPAID-only creatives
IMA 1005 (21005) or 1012 (21012)The ad request itself failed: network, CDN, CORS or a badly encoded tag URLOpen the tag URL in a browser; URL-encode macros; serve over HTTPS
IMA or VAST 402The media file took too long to loadOffer a lower-bitrate rendition; check the CDN
IMA 1205The browser blocked autoplayStart the ad muted, or after a user click
IMA or VAST 901The VPAID creative failedAsk for MP4 with Open Measurement instead of VPAID

Sources: Google IMA SDK error code reference (HTML5 and iOS) and JW Player's ad errors reference. The Epom VAST Inspector shows whichever code your tag triggers, VAST or IMA, with what it means and how to fix it.

From Epom Support: Three More Questions Behind "My VAST Tag Doesn't Work"

These questions came to Epom's support and product team. Each answer was checked against the ad server's code.

Why does the partner say they filled, while the report shows lost opportunities?

The ad server did its part: it picked the third-party banner and returned the wrapper. The third-party server then returned an empty VAST or timed out in the player, which counts as a lost opportunity, not as "no ads". The fix is to test the third-party tag in the Epom VAST Inspector, not your campaign setup.

Why do ads behind an SSAI stitcher get the wrong geo and low fill?

The ad server sees the stitcher's server, not the viewer. Geo then comes from the data centre, and the stitcher's user agent can trip bot filters.

The fix is to pass the viewer's IP address and user agent through the stitcher's macros. Epom video placements have an SSAI picker that adds them for AWS MediaTailor, Google DAI, SpringServe and Brightcove.

How do you run a mid-roll every five minutes on a 24/7 live stream?

Not with VMAP, because a live stream has no fixed timeline to schedule breaks on. The fix is a timer in the player that calls the same VAST tag every five minutes.

Which VAST Version Should You Use? VAST 2.0 to 4.3 Compared

Request the highest VAST version that both your player and your demand partners support. Older versions silently drop features: a VAST 2.0 response can't carry Open Measurement or a mezzanine file.

Version Released Key additions
VAST 2.02009Standardized tracking events and companion ads.
VAST 3.02012Ad pods, skippable ads (skipoffset), error codes, progress events.
VAST 4.0January 2016Mezzanine files for server-side insertion, Universal Ad ID, viewable impression, the AdVerifications element.
VAST 4.1November 2018Ad request guidance, Open Measurement as the standard verification path, audio ads merged in.
VAST 4.2June 2019SIMID interactivity, macros for ad break information, multiple Universal Ad IDs per creative.
VAST 4.3December 2022CTV viewing confirmation, earlier access to creative files for vetting; macros maintained separately on GitHub.

Sources: IAB Tech Lab VAST specifications (4.2, 4.3) and the IAB VAST repository.

Which Version and Media File to Request, by Environment

The version table shows what each release added. This one shows what to ask a demand partner for.

Environment VAST version Media file Verification and interactivity Avoid
Web player with Google IMAVAST 4.x (Epom's default is 4.2)MP4 (H.264) in several bitratesOpen Measurement through AdVerifications; SIMID if interactiveVPAID
Mobile app (IMA or native SDK)VAST 4.xMP4 renditions sized for mobileOM SDK through AdVerificationsVPAID; desktop-only file sizes
Roku and other CTV apps (client-side)VAST 4.xMP4 onlyPass the device ID macros (IFA and its type)VPAID and any JavaScript creative
Behind an SSAI stitcherVAST 4.1 or laterA mezzanine file plus MP4 renditions, with a Universal Ad ID so the stitcher can reuse its transcodesViewer IP address and user agent through macros or headersVPAID and interactive formats
Epom VMAP pre-roll breaksVAST 3.0 inside the VMAPMP4No Open Measurement in these breaksPer-break VAST 4.x calls when you need OM or mid-rolls

What about VPAID? VPAID let video ads run their own code inside the player. The IAB has replaced it with SIMID for interactivity and Open Measurement for verification. VPAID also doesn't run on most CTV devices or behind server-side insertion.

Accept VPAID only for legacy web demand, and ask partners for MP4 plus Open Measurement instead. The VAST vs VPAID comparison covers the migration.

Which VAST Macros Must the Player Fill?

Macros are placeholders in the tag that the player fills in at request time. If the player sends the literal text, the ad server can't target, cap or dedupe, and many requests come back empty.

Macro What it carries Why you need it
`[CACHEBUSTING]`A random numberStops browsers and CDNs from serving a cached response
`[PAGEURL]` / `[DOMAIN]`Where the ad will show (web)Brand safety, site targeting, reporting
`[APPBUNDLE]`App ID (in-app, CTV)App targeting and reporting
`[IFA]` / `[IFATYPE]`Device advertising ID (IFA) and its typeFrequency capping and audience targeting in apps and on CTV
`[LIMITADTRACKING]`Whether the user opted out of trackingRespecting device privacy settings
`[GDPRCONSENT]`The TCF consent string from the site's consent platformLegal basis for personalized ads in the EU
`[DEVICEIP]` / `[DEVICEUA]`Viewer's IP address and user agentGeo targeting and fraud checks when a server makes the request

On a web page, the viewer's browser calls the tag, so the IP address and user agent travel with the request. They need macros only when a server, such as a stitcher, calls the tag on the viewer's behalf.

How Do You Run Pre-Roll, Mid-Roll and Post-Roll Ads With a VAST Tag?

The player decides when to call the VAST tag: before, during or after the content. Use one tag per position, and per region if targeting differs, so pricing and reporting stay separate.

For long content with several breaks, use VMAP (Video Multiple Ad Playlist) to schedule the breaks, or call the VAST tag at each break. In Epom Ad Server, VMAP generates pre-roll breaks with VAST 3.0 inside, so call the tag per break for mid-rolls or Open Measurement.

What Is an Ad Pod in VAST?

An ad pod is a group of ads played back to back in one break, ordered by the sequence attribute on each <Ad> element. Ad pods arrived in VAST 3.0.

If a pod ad fails to load, the player can swap in a "buffet" ad: an ad in the same response without a sequence number. In Epom Ad Server, set the pod size with the maxAds parameter or the placement's "Return (ads in pod)" field, up to 20 ads.

Can VAST Tags Run on CTV and With Server-Side Ad Insertion?

Yes. On CTV, VAST tags run in the app's own player or behind an SSAI stitcher. The stitcher requests the tag for the viewer and inserts the ad into the stream.

Behind a stitcher, the stitcher must pass the viewer's IP address, user agent and device ID through macros or headers. Otherwise geo targeting, frequency capping and fraud checks see the stitcher instead of the viewer.

How Epom Ad Server Generates and Serves VAST Tags

Generate the tag from a video placement. Epom Ad Server works as both the VAST ad server and the VAST tag generator. Create a video banner, link it to a video placement and copy the tag from the new interface. It sets VAST 4.2 by default and lets you pick another version; the help docs cover the settings.

Epom Ad Server video banner form with an uploaded MP4 file, its in-form preview and video infoEpom Ad Server video placement with the version picker set to 4.2, plus VPAID and VMAP tags

Fill every break with ad pods. Epom serves VAST 2.0 through 4.3 and returns pods of up to 20 ads. You can also set a maximum pod duration and competitive separation inside a pod. A skip button setting and the SSAI stitcher picker sit on the same placement screen.

VAST configuration of a video placement: skip button, ads in pod, max pod duration, competitive separation and SSAI stitcher


Measure viewability without a vendor contract. On VAST 4.1 and higher, Epom adds its own Open Measurement verification to the response. The player reports viewability back into your normal Epom reports; see viewability and Open Measurement in the docs.

Mix direct and third-party demand. Your own video files and third-party VAST campaigns serve from the same placement, ordered by priority. Custom parameters pass your own values into targeting and reports.

Video banner of type Third Party VAST/VPAID Tag URL with options to follow wrappers, allow multiple ads and fall back on no adsNew campaign form in Epom Ad Server with the priority and weight fields that set delivery order


Run behind a stitcher. A video placement records which SSAI stitcher calls it: Google DAI, AWS MediaTailor, SpringServe or Brightcove. The tag then carries that stitcher's macros, including the viewer's IP address and user agent.

 SSAI macros for AWS Elemental MediaTailor on a video placement: clientIp, ifa, ifa_type, lmt and bundle with descriptions

Run outstream without your own player. Epom's players, built on IMA and Video.js, render outstream ads in a page slot as an overlay, in-feed or slider unit. For in-stream ads, use your own player with the VAST tag.

Want VAST 4.x tags with pods, priorities and full quartile reporting? Set up video ad serving with Epom Ad Server.

FAQ

Rate this article

2 ratings
Average: 3 of 5

Share this article

Which ad servers support VAST? See comparison.

Grab your file and move toward smarter advertising

Please choose company type
thank you image

Thank you!

Your guide is on its way to your inbox,
you'll get it in a second

Please disable Adblock
Are you using adblock? Disable it and reload the page to proceed to the destination page.
Please choose product

Thank you! We’ve received your message and will contact you soon.

A registration has already been submitted from this page. Please try again in 10 minutes.