Non-skippable linear VAST ads
A non-skippable linear ad is the simplest and most widely used VAST creative type. It plays in-stream before, during, or after video content and cannot be dismissed by the viewer. Standard lengths are 15 or 30 seconds. This guide covers the exact XML structure required, tracking events, MediaFile requirements, and the most common validation failures.
Quick reference
| Creative element | <Linear> — no skipoffset attribute |
| Typical duration | 15s or 30s (platform-dependent cap) |
| Required tracking | Impression; start/quartile/complete strongly recommended |
| Required media | MP4 H.264 (all platforms); WebM optional on web |
| HTTPS | Required on all platforms |
Minimal valid VAST structure
A non-skippable linear ad requires an <InLine> ad with at least one <Impression>, a <Linear> element with a <Duration> and at least one <MediaFile>. The absence of a skipoffset attribute on <Linear> is what makes it non-skippable — do not set it to an empty string or zero.
<VAST version="4.2">
<Ad id="1">
<InLine>
<AdSystem>My Ad Server</AdSystem>
<AdTitle>My 30s Non-Skippable Ad</AdTitle>
<Impression id="imp1"><![CDATA[https://track.example.com/impression]]></Impression>
<UniversalAdId idRegistry="Ad-ID">8465903</UniversalAdId>
<Creatives>
<Creative id="creative1" sequence="1">
<Linear>
<!-- No skipoffset attribute = non-skippable -->
<Duration>00:00:30</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>
</TrackingEvents>
<VideoClicks>
<ClickThrough id="click1"><![CDATA[https://example.com/landing]]></ClickThrough>
<ClickTracking id="ctrack1"><![CDATA[https://track.example.com/click]]></ClickTracking>
</VideoClicks>
<MediaFiles>
<MediaFile id="mf1" delivery="progressive" type="video/mp4"
width="1920" height="1080" bitrate="2500" scalable="true" maintainAspectRatio="true">
<![CDATA[https://cdn.example.com/ad-1080p.mp4]]>
</MediaFile>
<MediaFile id="mf2" delivery="progressive" type="video/mp4"
width="1280" height="720" bitrate="1500" scalable="true" maintainAspectRatio="true">
<![CDATA[https://cdn.example.com/ad-720p.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
</VAST>Duration format
The <Duration> element uses HH:MM:SS or HH:MM:SS.mmm format. This is used by the player to display a countdown timer and to calculate quartile tracking offsets. A wrong or missing duration causes quartile events to fire incorrectly or not at all.
<!-- ✅ Correct -->
<Duration>00:00:30</Duration>
<!-- ✅ With milliseconds -->
<Duration>00:00:30.000</Duration>
<!-- ❌ Wrong — numeric seconds only, not valid -->
<Duration>30</Duration>
<!-- ❌ Wrong — minutes:seconds only, not valid -->
<Duration>0:30</Duration>→ vastlint rule: VAST-2.0-duration-format
MediaFile requirements
Always provide multiple <MediaFile> renditions at different bitrates. The player selects the best-fit based on available bandwidth and screen size. At minimum, include a 1080p and a 720p rendition. For CTV, also include a 480p fallback.
Required attributes on each <MediaFile>:
delivery—progressiveorstreamingtype— MIME type, e.g.video/mp4widthandheight— pixel dimensionsbitrate— kbps (used for adaptive selection)
→ vastlint rule: VAST-2.0-mediafile-missing
Tracking events
The <Impression> URL fires when the player renders the ad slot (not when the video starts). Standard linear tracking events fire at specific playback percentages:
| Event | Fires at |
|---|---|
start | First frame of video playback |
firstQuartile | 25% of duration |
midpoint | 50% of duration |
thirdQuartile | 75% of duration |
complete | Final frame / 100% |
mute / unmute | User mutes/unmutes |
pause / resume | User pauses/resumes |
fullscreen | User enters fullscreen |
Omitting start or complete is a common mistake that breaks delivery reporting for buyers. Most DSPs and ad exchanges require these events and will downgrade or reject tags that omit them.
ClickThrough and ClickTracking
<ClickThrough> is the destination URL when a viewer clicks the ad. It is required by most buyers. <ClickTracking> is a pixel that fires on click — it does not control where the user goes, it only records the event.
<VideoClicks>
<!-- Where the user lands — required by most buyers -->
<ClickThrough id="click1"><![CDATA[https://example.com/landing]]></ClickThrough>
<!-- Measurement pixel — fires on click, can be multiple -->
<ClickTracking id="ctrack1"><![CDATA[https://track.example.com/click]]></ClickTracking>
<ClickTracking id="ctrack2"><![CDATA[https://measure.partner.com/click]]></ClickTracking>
</VideoClicks>UniversalAdId
Added in VAST 4.0, <UniversalAdId> provides a cross-platform creative identifier used for frequency capping, deduplication, and reporting. It is strongly recommended for all new campaigns. The idRegistry attribute identifies the naming authority (e.g. Ad-ID, ISCI, ad-id.org).
<UniversalAdId idRegistry="Ad-ID">ABCD1234000H</UniversalAdId>Common mistakes checklist
- skipoffset set to empty string or "0" — some ad servers accidentally output
skipoffset="". This is parsed as a skip-eligible ad by most players. Omit the attribute entirely for non-skippable. - Duration mismatch — the
<Duration>value does not match the actual video length. Players calculate quartile offsets from the declared duration, so a mismatch causes incorrect event firing. - Missing Impression URL — required by the spec. Without it, the ad cannot be counted as delivered.
- HTTP MediaFile URLs — all URLs must be HTTPS. HTTP media files are blocked on iOS, tvOS, and any HTTPS page due to mixed-content rules.
- Only one MediaFile at one bitrate — on CTV, bandwidth varies. A single high-bitrate file will buffer and timeout. Provide multiple renditions.
- Missing width/height on MediaFile — required attributes. Players use them for bitrate-ladder selection.