The IAB Tech Lab publishes VAST as two artifacts: a PDF specification document and a set of XSD schema files. The PDF is the normative authority. It defines what a conformant VAST response must, should, and may contain. The XSD describes the document structure in machine-readable form but has gaps; it does not cover business logic, ordering constraints, or anything involving URLs. Building a linter against VAST meant reading both and treating them as complementary sources of truth, not interchangeable ones.
The PDF extraction was manual and slow. Each version of the spec (2.0, 3.0, 4.0, 4.1, 4.2, 4.3) was read cover to cover and every normative statement was tagged by element, attribute, and constraint type. A rule like "InLine must contain AdTitle" comes directly from section language in the 2.0 spec that predates all subsequent versions and has never been relaxed. Deprecations were tracked version by version: conditionalAd deprecated in 4.1, Survey deprecated in 4.1, the fullscreen/exitFullscreen tracking events removed in 4.0. Each one becomes a versioned rule rather than a blanket error, so a VAST 3.0 document is not penalised for things that only matter in 4.x.
The XSD pass was more systematic. The schemas enumerate valid attribute values, allowed child elements, and content models for every element across spec versions. These became structural rules: unknown attributes, unknown child elements, invalid enum values for things like delivery, adType, renderingMode, and tracking event names. A third category of rules does not come from either the PDF or the XSD. It comes from what goes wrong in production. HTTPS enforcement on MediaFile and tracking URLs, duplicate Impression URLs causing billing disputes, missing quartile tracking events, the VPAID-in-CTV footgun: these are rules sourced from patterns that show up repeatedly in real VAST traffic. The source tag on each rule (VastSpec, VastXsd, IndustryBestPractice, Inferred, etc.) reflects exactly where it came from.
The full rule set is listed below. Each rule ID links to its dedicated page on vastlint.org with the exact spec section, severity, fix guidance, and examples.
| Rule ID | Description | Source |
|---|---|---|
| VAST-2.0-root-element | Root element must be <VAST>
|
VAST Spec |
| VAST-2.0-root-version |
<VAST> must have a version attribute |
VAST Spec |
| VAST-2.0-root-version-value | VAST version attribute must be a recognised version string | VAST XSD |
| VAST-2.0-root-has-ad-or-error |
<VAST> must contain at least one <Ad> or <Error>
|
VAST Spec |
| VAST-4.0-wrapper-root-error |
<VAST> root contains both <Ad> and <Error> elements (invalid per VAST 4.0) |
VAST Spec |
| VAST-2.0-ad-has-inline-or-wrapper | Each <Ad> must contain exactly one <InLine> or <Wrapper>
|
VAST Spec |
| VAST-2.0-inline-adsystem |
<InLine> must contain <AdSystem>
|
VAST Spec |
| VAST-2.0-inline-adtitle |
<InLine> must contain <AdTitle>
|
VAST Spec |
| VAST-2.0-inline-impression |
<InLine> must contain at least one <Impression>
|
VAST Spec |
| VAST-2.0-inline-creatives |
<InLine> must contain <Creatives> with at least one <Creative>
|
VAST Spec |
| VAST-4.1-adservingid-present |
<InLine> must contain <AdServingId> (VAST 4.1+) |
VAST Spec |
| VAST-4.0-universaladid-present |
<Creative> must contain <UniversalAdId> (VAST 4.0+) |
VAST Spec |
| VAST-4.0-universaladid-idregistry |
<UniversalAdId> must have an idRegistry attribute |
VAST Spec |
| VAST-4.0-universaladid-idvalue |
<UniversalAdId> missing required idValue attribute (VAST 4.0) |
VAST Spec |
| VAST-4.1-universaladid-idvalue-removed |
<UniversalAdId> idValue attribute was removed in VAST 4.1 |
VAST Spec |
| VAST-4.1-universaladid-content |
<UniversalAdId> must have text content in VAST 4.1+ |
VAST Spec |
| VAST-2.0-linear-duration |
<Linear> must contain <Duration>
|
VAST Spec |
| VAST-2.0-linear-mediafiles |
<Linear> must contain <MediaFiles> with at least one <MediaFile>
|
VAST Spec |
| VAST-2.0-mediafile-delivery |
<MediaFile> must have a delivery attribute |
VAST Spec |
| VAST-2.0-mediafile-delivery-enum |
<MediaFile> delivery must be "progressive" or "streaming" |
VAST XSD |
| VAST-2.0-mediafile-type |
<MediaFile> must have a type attribute |
VAST Spec |
| VAST-2.0-mediafile-dimensions |
<MediaFile> must have width and height attributes |
VAST Spec |
| VAST-2.0-wrapper-adsystem |
<Wrapper> must contain <AdSystem>
|
VAST Spec |
| VAST-2.0-wrapper-impression |
<Wrapper> must contain at least one <Impression>
|
VAST Spec |
| VAST-2.0-wrapper-vastadtaguri |
<Wrapper> must contain <VASTAdTagURI>
|
VAST Spec |
| VAST-2.0-companion-resource |
<Companion> must contain at least one StaticResource, IFrameResource, or HTMLResource |
VAST Spec |
| VAST-2.0-nonlinear-resource | InLine <NonLinear> must contain at least one StaticResource, IFrameResource, or HTMLResource |
VAST Spec |
| VAST-2.0-wrapper-depth | Wrapper chain depth exceeds the configured maximum | VAST Spec |
| VAST-2.0-ad-sequence | Mixed use of sequence attribute across <Ad> elements in a pod |
VAST Spec |
| VAST-2.0-duration-format |
<Duration> value does not match HH:MM:SS[.mmm] format |
VAST Spec |
| VAST-2.0-text-only-element | Text-only element contains a child element | VAST XSD |
| VAST-2.0-unknown-attribute | Element has an attribute not defined in the VAST spec | VAST XSD |
| VAST-2.0-inline-unknown-child |
<InLine> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-wrapper-unknown-child |
<Wrapper> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-creatives-unknown-child |
<Creatives> may only contain <Creative> elements |
VAST XSD |
| VAST-2.0-creative-unknown-child |
<Creative> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-linear-unknown-child |
<Linear> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-trackingevents-unknown-child |
<TrackingEvents> may only contain <Tracking> elements |
VAST XSD |
| VAST-2.0-mediafiles-unknown-child |
<MediaFiles> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-extensions-unknown-child |
<Extensions> may only contain <Extension> elements |
VAST XSD |
| VAST-2.0-videoclicks-unknown-child |
<VideoClicks> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-nonlinearads-unknown-child |
<NonLinearAds> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-nonlinear-unknown-child |
<NonLinear> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-companionads-unknown-child |
<CompanionAds> may only contain <Companion> elements |
VAST XSD |
| VAST-2.0-companion-unknown-child |
<Companion> contains an unrecognised child element |
VAST XSD |
| VAST-2.0-creativeextensions-unknown-child |
<CreativeExtensions> may only contain <CreativeExtension> elements |
VAST XSD |
| VAST-2.0-extension-misplaced-element |
<Extension> contains an element that has a dedicated location in the VAST spec |
VAST Spec |
| VAST-2.0-creative-extension-misplaced-element |
<CreativeExtension> contains an element that has a dedicated location in the VAST spec |
VAST Spec |
| VAST-2.0-mediafile-https |
<MediaFile> URL uses HTTP instead of HTTPS, blocked by mixed-content policy on secure inventory |
Industry Best Practice |
| VAST-2.0-tracking-https | Tracking or click URL uses HTTP instead of HTTPS, blocked by mixed-content policy, measurement signal lost | Industry Best Practice |
| VAST-2.0-url-empty | URL field is empty | VAST Spec |
| VAST-2.0-url-invalid | URL field does not appear to be a valid URI | RFC 3986 |
| VAST-2.0-parse-error | XML parse error, document may be malformed | XML |
| VAST-2.0-version-mismatch | Declared version does not match structural signals | Inferred |
| VAST-2.0-duplicate-impression | Duplicate <Impression> URL within the same <Ad>, causes double-counted billing and disputes |
Industry Best Practice |
| VAST-2.0-nonlinear-dimensions |
<NonLinear> missing width or height |
VAST Spec |
| VAST-2.0-companion-dimensions |
<Companion> missing width or height |
VAST Spec |
| VAST-2.0-flash-mediafile | Flash-based MediaFile type is no longer supported | Inferred |
| VAST-2.0-linear-tracking-quartiles |
<Linear> has no standard quartile tracking events, impression serves but measurement system receives no signal |
Industry Best Practice |
| VAST-3.0-icons-unknown-child |
<Icons> may only contain <Icon> elements |
VAST XSD |
| VAST-3.0-icon-unknown-child |
<Icon> contains an unrecognised child element |
VAST XSD |
| VAST-3.0-iconclicks-unknown-child |
<IconClicks> contains an unrecognised child element |
VAST XSD |
| VAST-3.0-progress-offset |
<Tracking event="progress"> requires an offset attribute |
VAST Spec |
| VAST-3.0-progress-offset-format | Tracking progress offset does not match required format | VAST Spec |
| VAST-3.0-icon-attrs | Icon missing recommended attributes (program/width/height/position) | VAST Spec |
| VAST-3.0-icon-program |
<Icon> missing required program attribute |
VAST Spec |
| VAST-3.0-icon-width |
<Icon> missing required width attribute |
VAST Spec |
| VAST-3.0-icon-height |
<Icon> missing required height attribute |
VAST Spec |
| VAST-3.0-icon-xposition |
<Icon> missing required xPosition attribute |
VAST Spec |
| VAST-3.0-icon-yposition |
<Icon> missing required yPosition attribute |
VAST Spec |
| VAST-3.0-icon-resource |
<Icon> must have at least one resource element |
VAST Spec |
| VAST-3.0-skipoffset-format | Linear skipoffset does not match HH:MM:SS[.mmm] or n% format | VAST Spec |
| VAST-3.0-skip-event-no-skipoffset | skip tracking event present but Linear has no skipoffset attribute | VAST Spec |
| VAST-3.0-minmaxbitrate-pair |
<MediaFile> must have both minBitrate and maxBitrate or neither |
VAST Spec |
| VAST-3.0-bitrate-conflict |
<MediaFile> has both bitrate and minBitrate/maxBitrate |
VAST Spec |
| VAST-3.0-pricing-model |
<Pricing> missing required model attribute |
VAST Spec |
| VAST-3.0-pricing-currency |
<Pricing> missing required currency attribute |
VAST Spec |
| VAST-3.0-pricing-model-case |
<Pricing> model value should be lowercase in VAST 3.0 (cpm/cpc/cpe/cpv) |
VAST XSD |
| VAST-3.0-pricing-currency-format |
<Pricing> currency attribute must be a 3-letter ISO-4217 code |
ISO 4217 |
| VAST-3.0-companion-required-attr |
<CompanionAds> required attribute must be all, any, or none |
VAST XSD |
| VAST-4.0-conditionalad | conditionalAd attribute is deprecated as of VAST 4.1 | VAST Spec |
| VAST-4.0-wrapper-clickthrough |
<ClickThrough> inside Wrapper <VideoClicks> was removed in VAST 4.0 (re-allowed in 4.2) |
VAST Spec |
| VAST-4.0-tracking-event-removed | fullscreen/exitFullscreen tracking events were removed in VAST 4.0 | VAST Spec |
| VAST-4.0-mediafile-apiframework |
<MediaFile apiFramework> is deprecated in VAST 4.0+, use <InteractiveCreativeFile>
|
VAST Spec |
| VAST-4.0-category-authority |
<Category> missing required authority attribute |
VAST Spec |
| VAST-4.0-companion-clicktracking-id |
<CompanionClickTracking> missing required id attribute |
VAST Spec |
| VAST-4.0-interactive-creative-no-api |
<InteractiveCreativeFile> should have an apiFramework attribute |
VAST Spec |
| VAST-4.1-adservingid-present |
<InLine> must contain <AdServingId> (VAST 4.1+) |
VAST Spec |
| VAST-4.1-ad-serving-id-empty |
<AdServingId> is present but empty |
Inferred |
| VAST-4.1-survey-deprecated |
<Survey> is deprecated as of VAST 4.1 |
VAST Spec |
| VAST-4.1-vpaid-apiframework | apiFramework="VPAID" is deprecated as of VAST 4.1 | VAST Spec |
| VAST-4.1-mezzanine-delivery |
<Mezzanine> missing required delivery attribute |
VAST Spec |
| VAST-4.1-mezzanine-type |
<Mezzanine> missing required type attribute |
VAST Spec |
| VAST-4.1-mezzanine-width |
<Mezzanine> missing required width attribute |
VAST Spec |
| VAST-4.1-mezzanine-height |
<Mezzanine> missing required height attribute |
VAST Spec |
| VAST-4.1-mezzanine-recommended |
<MediaFiles> has no <Mezzanine>, ad-stitching servers may reject in CTV/SSAI contexts |
Industry Best Practice |
| VAST-4.1-verification-no-resource |
<Verification> should have JavaScriptResource or ExecutableResource |
VAST Spec |
| VAST-4.1-verification-vendor |
<Verification> is missing required vendor attribute |
VAST Spec |
| VAST-4.1-blockedadcategories-no-authority |
<BlockedAdCategories> should have authority attribute |
VAST Spec |
| VAST-4.1-interactive-creative-type |
<InteractiveCreativeFile> should have a type attribute identifying the MIME type |
IANA Media Types |
| VAST-4.1-js-resource-apiframework |
<JavaScriptResource> is missing required apiFramework attribute |
VAST Spec |
| VAST-4.1-exec-resource-apiframework |
<ExecutableResource> is missing required apiFramework attribute |
VAST Spec |
| VAST-4.1-exec-resource-type |
<ExecutableResource> is missing required type attribute |
VAST Spec |
| VAST-4.1-tracking-event-value | Tracking event attribute not in the valid set for this VAST version | VAST XSD |
| VAST-4.1-adtype-value | Ad adType must be video, audio, or hybrid | VAST XSD |
| VAST-4.1-companion-renderingmode-value | Companion renderingMode must be default, end-card, or concurrent | VAST XSD |
| VAST-4.1-vpaid-in-interactive-context | VPAID MediaFile alongside InteractiveCreativeFile, VPAID unsupported in CTV, zero fill | Industry Best Practice |
| VAST-4.2-closedcaptionfiles-unknown-child |
<ClosedCaptionFiles> may only contain <ClosedCaptionFile> elements |
VAST XSD |
| VAST-4.2-icon-fallback-image-width-height |
<IconClickFallbackImage> should have width and height attributes |
VAST Spec |
| VAST-4.3-js-resource-browser-optional |
<JavaScriptResource> should have a browserOptional attribute |
VAST Spec |
| SIMID-1.0-simid-type-required |
<InteractiveCreativeFile apiFramework="SIMID"> must have type="text/html" |
SIMID Spec |
| SIMID-1.0-simid-url-empty |
<InteractiveCreativeFile apiFramework="SIMID"> must contain a non-empty URL |
SIMID Spec |
| SIMID-1.0-simid-url-https |
<InteractiveCreativeFile apiFramework="SIMID"> URL must use HTTPS |
SIMID Spec |
| SIMID-1.0-simid-variable-duration-value |
<InteractiveCreativeFile> variableDuration attribute must be "true" when present |
SIMID Spec |
| SIMID-1.0-simid-mediafile-required | Linear SIMID ad must include a video/audio <MediaFile> alongside the interactive creative |
SIMID Spec |
| SIMID-1.1-nonlinear-simid-no-iframe |
<NonLinear apiFramework="SIMID"> must contain an <IFrameResource>
|
SIMID Spec |
| SIMID-1.1-iframe-simid-type-required |
<IFrameResource> in SIMID <NonLinear> should have type="text/html" |
SIMID Spec |
| SIMID-1.1-iframe-simid-url-empty |
<IFrameResource> in SIMID <NonLinear> must contain a non-empty URL |
SIMID Spec |
| SIMID-1.1-iframe-simid-url-https |
<IFrameResource> in SIMID <NonLinear> URL must use HTTPS |
SIMID Spec |
Top comments (0)