vastlint

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 duration15s or 30s (platform-dependent cap)
Required trackingImpression; start/quartile/complete strongly recommended
Required mediaMP4 H.264 (all platforms); WebM optional on web
HTTPSRequired 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>:

  • deliveryprogressive or streaming
  • type — MIME type, e.g. video/mp4
  • width and height — pixel dimensions
  • bitrate — 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:

EventFires at
startFirst frame of video playback
firstQuartile25% of duration
midpoint50% of duration
thirdQuartile75% of duration
completeFinal frame / 100%
mute / unmuteUser mutes/unmutes
pause / resumeUser pauses/resumes
fullscreenUser 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.