VAST ad pods & sequencing
An ad pod is a group of video ads played back-to-back in a single ad break, similar to a commercial break on TV. A pod might contain a 6s bumper, a 30s main ad, and another 6s bumper, all playing sequentially before content resumes.
In VAST XML, ad pods are represented by multiple <Ad> elements in a single <VAST> response, each with a sequence attribute that defines play order. There is no pod container element in any VAST version. The pod is the set of sibling <Ad> elements, and nothing more.
Test the pod tag
Paste the live URL to see which ads in the pod resolve. Inspect wrappers if later sequence ads never arrive.
Quick reference
| Sequencing | sequence attribute on each <Ad> element |
| Play order | Ascending numeric order of sequence values |
| allowMultipleAds | Must be true on wrapper tags for pods to pass through |
| Pod container | None. No VAST version defines <AdPod>, maxAds or maxDuration |
| Pod size limits | Set in the request (OpenRTB poddur, maxseq), not the response |
| CTV support | Widely supported on Roku, Fire TV, Apple tvOS, Samsung, LG |
The sequence attribute
The sequence attribute on <Ad> is a positive integer that defines the ad's position in the pod. Ads play in ascending order of their sequence value. Gaps in sequence numbers are allowed: the player fills them in order.
An <Ad> without a sequence attribute is treated as a standalone ad, not part of a pod. Players that receive a mixed response (some with sequence, some without) should play sequenced ads in pod order and ignore unsequenced ads or treat them as separate requests.
→ vastlint rule: VAST-2.0-ad-sequence
<VAST version="4.2">
<!-- Ad 1: Opening bumper (sequence=1) -->
<Ad id="bumper-1" sequence="1">
<InLine>
<AdSystem>My Ad Server</AdSystem>
<AdTitle>Opening Bumper</AdTitle>
<AdServingId>pod-a-bumper-open</AdServingId>
<Impression><![CDATA[https://track.example.com/bumper1-imp]]></Impression>
<Creatives>
<Creative sequence="1">
<UniversalAdId idRegistry="Ad-ID">BUMPOPEN01</UniversalAdId>
<Linear>
<Duration>00:00:06</Duration>
<TrackingEvents>
<Tracking event="start"><![CDATA[https://track.example.com/bumper1-start]]></Tracking>
<Tracking event="complete"><![CDATA[https://track.example.com/bumper1-complete]]></Tracking>
</TrackingEvents>
<MediaFiles>
<MediaFile delivery="progressive" type="video/mp4"
width="1920" height="1080" bitrate="2000">
<![CDATA[https://cdn.example.com/bumper-open.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
<!-- Ad 2: Main 30s ad (sequence=2) -->
<Ad id="main-1" sequence="2">
<InLine>
<AdSystem>My Ad Server</AdSystem>
<AdTitle>Main Ad</AdTitle>
<AdServingId>pod-a-main</AdServingId>
<Impression><![CDATA[https://track.example.com/main-imp]]></Impression>
<Creatives>
<Creative sequence="1">
<UniversalAdId idRegistry="Ad-ID">MAINAD0001</UniversalAdId>
<Linear>
<Duration>00:00:30</Duration>
<TrackingEvents>
<Tracking event="start"><![CDATA[https://track.example.com/main-start]]></Tracking>
<Tracking event="complete"><![CDATA[https://track.example.com/main-complete]]></Tracking>
</TrackingEvents>
<MediaFiles>
<MediaFile delivery="progressive" type="video/mp4"
width="1920" height="1080" bitrate="2500">
<![CDATA[https://cdn.example.com/main-ad.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
<!-- Ad 3: Closing bumper (sequence=3) -->
<Ad id="bumper-2" sequence="3">
<InLine>
<AdSystem>My Ad Server</AdSystem>
<AdTitle>Closing Bumper</AdTitle>
<AdServingId>pod-a-bumper-close</AdServingId>
<Impression><![CDATA[https://track.example.com/bumper2-imp]]></Impression>
<Creatives>
<Creative sequence="1">
<UniversalAdId idRegistry="Ad-ID">BUMPCLOSE1</UniversalAdId>
<Linear>
<Duration>00:00:06</Duration>
<TrackingEvents>
<Tracking event="start"><![CDATA[https://track.example.com/bumper2-start]]></Tracking>
<Tracking event="complete"><![CDATA[https://track.example.com/bumper2-complete]]></Tracking>
</TrackingEvents>
<MediaFiles>
<MediaFile delivery="progressive" type="video/mp4"
width="1920" height="1080" bitrate="2000">
<![CDATA[https://cdn.example.com/bumper-close.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
</VAST>allowMultipleAds on wrapper tags
If your ad pod response passes through one or more VAST wrapper tags, each wrapper must set allowMultipleAds="true". A wrapper that sets it to false tells the player to keep only the first ad, which collapses the whole pod to one spot.
Set it explicitly on every wrapper you control. The VAST XSD declares allowMultipleAds as an optional xs:boolean with no default value, so a wrapper that omits the attribute leaves the decision to the player. Some treat the absence as permission, some as refusal. Neither reading is a schema violation, which is why this failure survives validation and only shows up as a pod that is shorter than it should be.
<!-- Wrapper must allow multiple ads for pods to pass through -->
<VAST version="4.2">
<Ad id="wrapper1">
<Wrapper allowMultipleAds="true" followAdditionalWrappers="true">
<AdSystem>SSP</AdSystem>
<VASTAdTagURI><![CDATA[https://adserver.example.com/pod-vast]]></VASTAdTagURI>
<Impression><![CDATA[https://track.ssp.com/impression]]></Impression>
</Wrapper>
</Ad>
</VAST>There is no pod container element in VAST
A pod is not a container. It is a convention: several sibling <Ad> elements that happen to carry sequence attributes. No VAST version defines an <AdPod> element, and there is no maxAds or maxDuration anywhere in the VAST 4.1, 4.2 or 4.3 XSD. If you have seen those names, they came from the request side, not the response.
Pod size and duration are negotiated when the ad is requested. In OpenRTB 2.6 that is imp.video.podid, poddur, maxseq and podseq. In VMAP it is the <AdBreak> that owns the slot, with allowMultipleAds on its <AdSource>. The VAST response then fills that slot and carries no pod-level metadata of its own.
The practical consequence: a VAST response cannot tell you whether the pod is complete. Nothing in the XML says "this pod should have had four ads." If the third ad is missing, the document is still perfectly valid.
Each ad in a pod fires its own Impression
Every <Ad> in a pod has its own <Impression> URL that fires independently when that ad plays. There is no single pod-level impression event in classic VAST sequencing. This means a 3-ad pod will fire 3 separate impression URLs, one per ad, as each ad plays.
Common mistakes checklist
- Duplicate or missing sequence values: two ads with the same sequence number cause undefined play order. Always use unique, consecutive integers starting from 1.
- allowMultipleAds not set on wrappers: the most common reason pods are truncated to a single ad in production. Every wrapper in the chain must have
allowMultipleAds="true". - Mixing sequenced and unsequenced ads: all ads in a pod should have explicit
sequenceattributes. Mixing sequenced and unsequenced ads in one VAST response leads to inconsistent player behaviour. - Pod total duration exceeds break length: the publisher defines the break length. If the pod's total declared duration exceeds it, the player may truncate the pod mid-break. Always confirm maximum break duration with the publisher.
- Expecting a single pod-level impression: pods fire one impression per ad. Ad server reporting will show N impressions for an N-ad pod, not 1. Adjust your reporting expectations accordingly.