vastlint

VAST XML for Roku RAF

Roku is the largest CTV platform in the US by active accounts. Its Roku Advertising Framework (RAF) handles all ad serving for channel developers. RAF is strict about VAST compliance — non-conforming tags fail silently, with no error surfaced to the viewer. This guide covers everything your VAST tag needs to deliver cleanly on Roku.

Quick reference

VAST versions2.0, 3.0, 4.0, 4.1 (4.2/4.3 partially)
VPAIDCompletely blocked. No fallback.
Wrapper chain limit4 hops maximum; 3-second total timeout
Required media formatMP4, H.264 + AAC. WebM not supported.
Recommended resolution1080p (4–8 Mbps) or 720p (2–4 Mbps)
HTTPSRequired for all URLs

VPAID is completely blocked

This is the single most common source of missed impressions on Roku. RAF has no JavaScript execution environment at the ad layer. Any <MediaFile> with apiFramework="VPAID" is silently discarded. RAF moves on to the next media file in the tag — and if there is no non-VPAID fallback, the entire slot goes unfilled without any error signal.

<!-- ❌ This creative will be silently dropped on Roku -->
<MediaFile apiFramework="VPAID" type="application/javascript">
  <![CDATA[https://cdn.example.com/vpaid.js]]>
</MediaFile>

<!-- ✅ Always include a native MP4 fallback -->
<MediaFile type="video/mp4" width="1920" height="1080"
           bitrate="4500" delivery="progressive">
  <![CDATA[https://cdn.example.com/ad-1080p.mp4]]>
</MediaFile>

→ vastlint rule: VAST-4.1-vpaid-in-interactive-context

Wrapper chain depth and timeout

RAF enforces a 3-second timeout for resolving the entire wrapper chain. This is stricter than most web environments. Each wrapper hop adds a network round-trip; on a typical living-room WiFi connection with a mid-range Roku device, a single hop can take 200–600 ms. A 4-hop chain will frequently time out.

Best practice for Roku delivery: keep wrapper chains to 2 hops or fewer. If you are buying Roku inventory programmatically through a DSP, confirm that your trading desk is not adding additional redirect layers before the tag reaches the device.

Media file requirements

RAF supports only MP4 with H.264 video and AAC audio. WebM, VP8, VP9, and HLS are not supported for video ads (HLS is used for content streams, not ads).

Provide at least two bitrate variants to ensure RAF can pick an appropriate quality for the viewer's connection:

<MediaFiles>
  <!-- 1080p — strong WiFi connections -->
  <MediaFile type="video/mp4" width="1920" height="1080"
             bitrate="6000" delivery="progressive">
    <![CDATA[https://cdn.example.com/ad-1080p.mp4]]>
  </MediaFile>
  <!-- 720p — fallback for slower connections -->
  <MediaFile type="video/mp4" width="1280" height="720"
             bitrate="2500" delivery="progressive">
    <![CDATA[https://cdn.example.com/ad-720p.mp4]]>
  </MediaFile>
</MediaFiles>

→ vastlint rules: VAST-2.0-mediafiles-empty, VAST-2.0-mediafile-url

HTTPS requirement

All URLs in the VAST tag must use https://: media files, impression pixels, error tracking URLs, click-through URLs, and any companion assets. Roku devices reject HTTP URLs at the network layer. A single HTTP URL in your impression tracker will cause the impression to fire but be discarded by Roku's networking stack.

Companion ads

RAF does not render companion ads. Any <CompanionAds> blocks in your VAST tag are parsed but ignored at render time. Include them for cross-platform compatibility, but don't build Roku campaign KPIs around companion engagement.

Tracking events

RAF fires standard VAST tracking events: start, firstQuartile, midpoint, thirdQuartile, complete, and impression. The mute, unmute, pause, and resume events are also fired. Click tracking is supported when the remote control is used to navigate to a click-through URL.

Duplicate impression URLs — multiple <Impression> elements with identical URIs — will each fire, inflating counts. vastlint catches these automatically.

→ vastlint rule: VAST-2.0-duplicate-impression

Error tracking

Include an <Error> element in your VAST tag so RAF can report failures back to your ad server. Use the [ERRORCODE] macro to receive the IAB error code.

<Error>
  <![CDATA[https://track.example.com/error?code=[ERRORCODE]]]>
</Error>

VAST version declaration

Always declare the correct VAST version. RAF detects the version from the version attribute on the root <VAST> element. A missing version attribute causes RAF to treat the tag as invalid.

<!-- ❌ Missing version -->
<VAST>

<!-- ✅ Correct -->
<VAST version="4.1">

→ vastlint rule: VAST-2.0-root-version

Pre-flight checklist for Roku RAF

  • No VPAID creatives — provide MP4 H.264 only
  • Wrapper chain depth ≤ 2–3 hops
  • At least one MP4 H.264 <MediaFile> at 720p or 1080p
  • All URLs use HTTPS
  • <Duration> in HH:MM:SS format
  • <Impression> element present with a valid HTTPS URL
  • version attribute on the root <VAST> element
  • <Error> tracking URL present with [ERRORCODE] macro
  • No duplicate impression URLs

References

Validate your tag against all 118 IAB rules →