VASTlint
Back to blog
Benchmark/11 min read

VAST Tag Benchmark 2026: 21.5 Percent of 694 Live Tags Had a Defect That Stops Playback or Counting

We linted 694 production VAST tags and all 75 of the IAB Tech Lab's public sample tags. One live tag in five could not be read, had no Impression, had no usable video, or was empty. Two IAB samples pass the official XSD and still break the VAST 4.1 specification text. The data and the script are public.

Author

Alex Sekowski

Published

October 3, 2026

Reading time

11 min read

VASTBenchmarkVAST validatorOpen dataCTV

This benchmark has two halves. The first is a production sample: 694 VAST documents that people pasted into or fetched through the vastlint.org tester, validator, and inspector between July 6 and September 22, 2026, from 49 countries. Checked for errors only, 149 of them (21.5 percent) had at least one defect that stops an ad from playing or from being counted: the response could not be parsed as VAST, an InLine had no Impression, the video had no usable MediaFile, or the document was empty.

The second half is fully reproducible. We ran the same linter over all 75 sample tags in the IAB Tech Lab's public VAST_Samples repository and over the official IAB XSD schemas with xmllint. Four sample files have specification errors. Two of those, the VAST 4.1 and 4.2 ad verification samples, pass XSD validation and still break the VAST 4.1 specification text, because the schema marks two attributes optional that the specification marks required.

Both halves come with their data. The production half is published as aggregate counts only. The IAB half is published per file, with the script that produced it, so anyone can rerun it in under a minute.

Three cards. 149 of 694 production VAST tags had a defect that stops playback or counting. Four of the IAB's 75 sample tags have errors, and two pass XSD while breaking the VAST 4.1 text. vastlint validated about 19,800 documents per second, close to xmllint's 21,500.
The production sample is self-selected and overstates the market rate. The IAB half and the timings can be rerun with the published script. Diagram by vastlint.org. An independent open-source project. The diagram restates figures already cited in this post.

The benchmark in one table

Each row names the corpus it comes from, because a self-selected production sample and a public sample repository answer different questions.

MeasureValueCorpus
Live tags with a defect that stops playback or counting149 of 694 (21.5%)Production sample, July 6 to September 22, 2026
Live responses that could not be read as VAST81 of 694 (11.7%)Production sample
IAB sample files with specification errors4 of 75IAB VAST_Samples, commit 6a60797
IAB sample files with at least one warning72 of 75IAB VAST_Samples
IAB sample files that pass XSD and break the specification text2VAST 4.1 and 4.2 ad verification samples
vastlint throughput, one threadAbout 19,800 documents per second, p50 50 µsIAB VAST_Samples, Node 22, Apple M4
xmllint XSD throughputAbout 21,500 documents per secondIAB VAST_Samples, libxml2 2.9.13

How the production sample was collected

vastlint.org stores a redacted copy of tags submitted to its web tools, as described on the privacy page: known device IDs, IP addresses, and consent query parameters are stripped before storage, and the client IP is not stored. The privacy page also allows aggregate statistics and rule-level findings from those tags to be published. Nothing in this article or its data file contains XML, hostnames, network owners, or per-document rows.

The cutoff is September 22, 2026 at 23:59:59.999 UTC. Of the 694 documents, 451 came through the tester, which fetches a live tag URL and lints the response it receives; 161 were pasted into the validator; 57 came through the IAB-format tester; 23 came through the wrapper inspector; and 2 came from older surfaces. 250 came from the United States and 143 from India. A further 882 documents arrived through the hosted MCP endpoint over the same period; they are excluded here and reported separately.

Every document was re-checked with vastlint on September 29, 2026 against the stored copy, counting errors only. Wrapper URLs were not fetched, so each document was judged on its own text. A Wrapper whose downstream InLine was broken counts as clean here if the Wrapper itself was valid.

Four defects that stop playback or counting

A document can sit in more than one class, so the classes add up to more than 149.

Defect classDocumentsShare of 694Rules behind it
Unreadable8111.7%VAST-2.0-parse-error (58) or VAST-2.0-root-element (23)
Missing Impression324.6%No Impression on an InLine or Wrapper, or an empty Impression URL
Unusable video284.0%No MediaFiles, or a MediaFile missing type, delivery, width, height, or its URL
Empty wrapper or empty VAST142.0%A VAST root with no Ad and no Error (13), or a Wrapper with no VASTAdTagURI (1)
Any of the four14921.5%Union of the four classes

What each defect class does to a player

An unreadable document is the most common failure by a wide margin. The tester stores whatever the tag URL returned, so this class includes responses that were never VAST at all: an HTML error page, a JSON body, a truncated download, or XML whose root element is something other than VAST. A player that requests that URL receives the same bytes and has nothing to play. In VAST error-code terms that is usually a 100-series XML parsing or schema failure, and from the buyer's side it looks like a no-fill.

A missing Impression is quieter. The ad can play perfectly while the impression is never reported, because the Impression URI is the element the specification uses to count the view. Thirty-two documents had no Impression on an InLine or Wrapper, or carried an Impression element with an empty URL. For a publisher that is unbilled delivery; for an advertiser it is a discrepancy that no amount of creative QA will find.

Unusable video means the player has nothing it can pick. A MediaFile without a type cannot be matched to the player's codecs; without delivery the player cannot tell progressive from streaming; without width and height it cannot choose a rendition for the screen; and an empty URL is not a file. Empty documents are the last class: a VAST root with no Ad and no Error is a valid way to say no ad when it carries an Error URL, and an invalid one when it carries neither, which is what these 13 did.

The most common errors in live tags

Counted per document, not per occurrence, across the same 694 documents.

RuleDocumentsShare of 694What it means
VAST-2.0-parse-error588.4%The document is not well-formed XML
VAST-4.1-tracking-event-value365.2%A Tracking event name outside the set allowed for the declared version
VAST-4.0-universaladid-present294.2%A VAST 4.0+ Creative without UniversalAdId
VAST-2.0-url-empty284.0%A URL element with no URL in it
VAST-2.0-inline-impression243.5%An InLine with no Impression
VAST-2.0-mediafile-dimensions243.5%A MediaFile without width and height
VAST-2.0-root-element233.3%The root element is not VAST
VAST-2.0-root-version162.3%The VAST root has no version attribute
VAST-2.0-mediafile-delivery131.9%A MediaFile without a delivery attribute
VAST-2.0-root-has-ad-or-error131.9%A VAST root with no Ad and no Error
VAST-2.0-linear-duration111.6%A Linear creative without Duration
VAST-2.0-mediafile-type111.6%A MediaFile without a type attribute

Why the production rate is not a market rate

The 21.5 percent is a share of tags that people chose to check, and people check tags when something is wrong or when a launch is close. That pulls the rate up compared with every tag served on a given day. It is a fair estimate of how often a tag that reaches a QA tool is broken in a way that matters, and an unfair estimate of how often a random impression fails.

The sample also leans toward the formats people debug by hand. Open-web and CTV video tags pasted by ad operations teams, agencies, and publishers dominate; server-side stitched responses that never leave an SSAI vendor's systems are mostly absent. The 694 documents came from 49 countries, but 36 percent came from the United States and 21 percent from India, so country-level conclusions are out of reach.

What the sample does show is the shape of the failures. Most of them are not subtle specification arguments. They are responses that are not VAST, Impressions that are missing, and MediaFiles without the attributes a player needs to choose one. Each of those is detectable from the document alone, before a single impression is spent.

The IAB's own sample tags, linted

The IAB Tech Lab's VAST_Samples repository is the reference corpus most engineers reach for when they build or test a player. We cloned it at commit 6a60797 (May 22, 2023), which holds 75 XML files across VAST 1.0 through 4.2, from 444 bytes to 7.5 KB with a median of 2.9 KB, and ran vastlint 0.13.12 over every file.

Four files have errors. Two are Tremor Video VAST 2.0 samples: vast2Nonlinear.xml has ten InLine ads without an Impression, and vast2VPAIDLinear.xml has an InLine without an Impression and a MediaFile without the delivery attribute. Both elements are required by the VAST 2.0 schema, and xmllint agrees. A pull request adding them, #47 on the VAST_Samples repository, has been open since August 31, 2026.

The other two are the VAST 4.1 and 4.2 Ad_Verification-test.xml samples, and they are the more interesting finding, because the official schema does not catch them. Seventy-two of the 75 files also carry at least one warning. The most common is a tracking or click URL over plain HTTP (63 files), which modern browsers and many CTV platforms block as mixed content. Only two files are completely clean.

IAB sample results by folder

vastlint 0.13.12 on IAB VAST_Samples at commit 6a60797.

FolderFilesWith errorsWith warnings
VAST 1-2.0 Samples19218
VAST 3.0 Samples707
VAST 4.0 Samples16016
VAST 4.1 Samples18118
VAST 4.2 Samples15113
All75472

Get VAST spec updates, platform guides, and release notes in your inbox.

Where the VAST 4.1 schema and the VAST 4.1 specification disagree

VAST 4.1 introduced the AdVerifications element for Open Measurement. Section 3.17 of the VAST 4.1 specification lists vendor as a required attribute on Verification, with a recommended format such as company.com-omid. Section 3.17.1 lists apiFramework as required on JavaScriptResource. The published VAST 4.1 XSD declares both attributes with use="optional", and the 4.2 XSD inherits the same declarations.

The IAB's ad verification samples omit both attributes, so they pass XSD validation and fail the specification text. That is not a cosmetic gap. The vendor key is how a player or an OM SDK integration decides whose script it is loading and whether that vendor is allowed, and verificationNotExecuted reason code 3 exists precisely for a vendor the publisher does not recognize. A Verification with no vendor and no apiFramework gives the player nothing to make that decision with.

This is the general case for schema-only validation. An XSD can only express what fits in a schema: element order, cardinality, attribute types. Rules that live in the prose, in RFC 2119 words like must and required, are invisible to it. vastlint derives 39 of its 235 rules from the published XSDs and 80 from normative specification text, which is why it flags these two files and xmllint does not.

The IAB 4.1 sample, and what the specification text asks for
xml
<!-- IAB VAST_Samples, VAST 4.1 Samples/Ad_Verification-test.xml (passes the 4.1 XSD) --><AdVerifications>  <Verification>    <JavaScriptResource>      <![CDATA[https://verificationcompany1.com/verification_script1.js]]>    </JavaScriptResource>  </Verification></AdVerifications> <!-- VAST 4.1 §3.17 and §3.17.1: vendor and apiFramework are required --><AdVerifications>  <Verification vendor="verificationcompany1.com-omid">    <JavaScriptResource apiFramework="omid" browserOptional="true">      <![CDATA[https://verificationcompany1.com/verification_script1.js]]>    </JavaScriptResource>  </Verification></AdVerifications>

What each check caught on the 75 IAB samples

xmllint was run against the IAB XSD matching each file's declared version. The six VAST 1.0 files have no VAST XSD and were not checked by xmllint.

Checkxmllint with IAB XSDvastlint 0.13.12
Files checked6975
Files failing24
VAST 2.0 InLine without Impression, MediaFile without deliveryCaughtCaught
VAST 4.1 and 4.2 Verification without vendor or apiFrameworkPasses; the XSD marks both optionalCaught, citing §3.17 and §3.17.1
Tracking or click URL over HTTPNot checkedWarning on 63 files
MediaFile with both bitrate and minBitrate or maxBitrateNot checkedWarning on 45 files
URL not wrapped in CDATANot checkedWarning on 28 files
conditionalAd, deprecated in VAST 4.1Not checkedWarning on 17 files
VAST 1.0 root element instead of VASTNo schemaWarning on 6 files

How fast each check runs

Speed matters when validation sits in a request path: an ad server checking a creative at upload, an SSP checking a response before it forwards it, or a CI job checking hundreds of tags on every commit. We timed vastlint's npm build, which is the Rust core compiled to WebAssembly, running in Node 22.16 on an Apple M4, single-threaded. After 50 warm-up passes, 400 timed passes over all 75 files gave 30,000 validations at 19,824 documents per second (19,563 on a rerun), about 53 MB per second of XML. Median latency per document was 50 microseconds, p95 was 82, p99 was 175, and the slowest single validation took 249.

For a reference point we timed xmllint from libxml2 2.9.13, native C, validating the same files against the IAB XSDs: about 21,500 documents per second, with one process per VAST version and every file repeated 100 times so each run paid for one process start and one schema compile. The two numbers are close, and they are not measuring the same work. xmllint performs one structural pass. vastlint parses the document and runs 235 rules, including the XSD-derived ones, the specification-text rules that found the verification gap, and URL, media type, and macro checks.

The practical reading is that full specification validation costs roughly what schema validation costs on real tags, so there is no performance argument for stopping at the XSD. These timings cover documents under 8 KB, which is the size of a typical InLine or Wrapper; a very large ad pod was not part of this run.

Latency per document

vastlint 0.13.12 npm WASM build, Node 22.16, Apple M4, one thread, 30,000 validations of the IAB samples.

Statisticvastlintxmllint with IAB XSD
Documents per second19,824About 21,500
Median (p50)50 µsNot measured per document
p9582 µsNot measured per document
p99175 µsNot measured per document
Work per documentParse plus 235 rulesOne XSD validation pass
Reproduce the IAB half
bash
git clone --depth 1 https://github.com/InteractiveAdvertisingBureau/VAST_Samples.gitnpm init -y >/dev/null && npm i [email protected]curl -sO https://vastlint.org/data/vast-benchmark-2026/bench.mjsnode bench.mjs VAST_Samples # 75 files, 4 with errors, 72 with warnings# 30000 validations, ~19600 docs/s on an Apple M4 # The schema comparison, one version at a time:xmllint --noout --schema vast_4.1.xsd "VAST_Samples/VAST 4.1 Samples/Ad_Verification-test.xml"# validates, although VAST 4.1 §3.17 requires Verification@vendor

What this benchmark does not show

  • The production rate is a share of tags people chose to check, so it overstates how often a random served impression fails.
  • Wrapper chains were not followed in the production re-check, so a valid Wrapper in front of a broken InLine counts as clean.
  • A linter reads the document; it does not play the creative, so a valid tag can still fail on a player that lacks a codec, an OM SDK, or SIMID support.
  • The IAB samples were written as examples, not as production tags, and several predate later versions of the specification.
  • The throughput figures come from one machine and documents under 8 KB, and they will move with hardware, Node version, and document size.
  • The xmllint comparison measures schema validation only; other validators that add their own rules were not part of this run.

How to cite this benchmark

Sekowski, A. (2026). VAST Tag Benchmark 2026: 694 production tags and the IAB VAST_Samples corpus. vastlint.org, October 3, 2026. https://vastlint.org/blog/vast-tag-benchmark-2026/

The per-file IAB results are in iab-samples.json, the production aggregates are in production-aggregates.json, and the script is bench.mjs. The data may be reused with attribution.

Run your own tag through the same rules

The validator runs the same rules on VAST 2.0–4.4, VMAP, and DAAST, and shows the rule, the line, and the specification reference for every finding.

Open the VAST validator

Sources and data

The 75-file sample corpus, linted at commit 6a60797 (May 22, 2023).

Open pull request fixing the two VAST 2.0 samples with errors.

VAST specifications and XSD schemas, including VAST 4.1 sections 3.17 and 3.17.1.

Version 0.13.12, the WebAssembly build timed here.

vastlint and xmllint results for every sample file, with timings.

Aggregate defect and rule counts for the 694 production documents.

Benchmark scriptvastlint.org

The script behind the IAB half of this benchmark.

Privacyvastlint

What vastlint.org stores from its web tools and how stored tags may be used.

Methodologyvastlint

How vastlint derives rules from XSDs and from normative specification text.

The verification node behind the 4.1 schema gap.

Related stories

All posts