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.

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.
| Measure | Value | Corpus |
|---|---|---|
| Live tags with a defect that stops playback or counting | 149 of 694 (21.5%) | Production sample, July 6 to September 22, 2026 |
| Live responses that could not be read as VAST | 81 of 694 (11.7%) | Production sample |
| IAB sample files with specification errors | 4 of 75 | IAB VAST_Samples, commit 6a60797 |
| IAB sample files with at least one warning | 72 of 75 | IAB VAST_Samples |
| IAB sample files that pass XSD and break the specification text | 2 | VAST 4.1 and 4.2 ad verification samples |
| vastlint throughput, one thread | About 19,800 documents per second, p50 50 µs | IAB VAST_Samples, Node 22, Apple M4 |
| xmllint XSD throughput | About 21,500 documents per second | IAB 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 class | Documents | Share of 694 | Rules behind it |
|---|---|---|---|
| Unreadable | 81 | 11.7% | VAST-2.0-parse-error (58) or VAST-2.0-root-element (23) |
| Missing Impression | 32 | 4.6% | No Impression on an InLine or Wrapper, or an empty Impression URL |
| Unusable video | 28 | 4.0% | No MediaFiles, or a MediaFile missing type, delivery, width, height, or its URL |
| Empty wrapper or empty VAST | 14 | 2.0% | A VAST root with no Ad and no Error (13), or a Wrapper with no VASTAdTagURI (1) |
| Any of the four | 149 | 21.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.
| Rule | Documents | Share of 694 | What it means |
|---|---|---|---|
| VAST-2.0-parse-error | 58 | 8.4% | The document is not well-formed XML |
| VAST-4.1-tracking-event-value | 36 | 5.2% | A Tracking event name outside the set allowed for the declared version |
| VAST-4.0-universaladid-present | 29 | 4.2% | A VAST 4.0+ Creative without UniversalAdId |
| VAST-2.0-url-empty | 28 | 4.0% | A URL element with no URL in it |
| VAST-2.0-inline-impression | 24 | 3.5% | An InLine with no Impression |
| VAST-2.0-mediafile-dimensions | 24 | 3.5% | A MediaFile without width and height |
| VAST-2.0-root-element | 23 | 3.3% | The root element is not VAST |
| VAST-2.0-root-version | 16 | 2.3% | The VAST root has no version attribute |
| VAST-2.0-mediafile-delivery | 13 | 1.9% | A MediaFile without a delivery attribute |
| VAST-2.0-root-has-ad-or-error | 13 | 1.9% | A VAST root with no Ad and no Error |
| VAST-2.0-linear-duration | 11 | 1.6% | A Linear creative without Duration |
| VAST-2.0-mediafile-type | 11 | 1.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.
| Folder | Files | With errors | With warnings |
|---|---|---|---|
| VAST 1-2.0 Samples | 19 | 2 | 18 |
| VAST 3.0 Samples | 7 | 0 | 7 |
| VAST 4.0 Samples | 16 | 0 | 16 |
| VAST 4.1 Samples | 18 | 1 | 18 |
| VAST 4.2 Samples | 15 | 1 | 13 |
| All | 75 | 4 | 72 |
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.
<!-- 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.
| Check | xmllint with IAB XSD | vastlint 0.13.12 |
|---|---|---|
| Files checked | 69 | 75 |
| Files failing | 2 | 4 |
| VAST 2.0 InLine without Impression, MediaFile without delivery | Caught | Caught |
| VAST 4.1 and 4.2 Verification without vendor or apiFramework | Passes; the XSD marks both optional | Caught, citing §3.17 and §3.17.1 |
| Tracking or click URL over HTTP | Not checked | Warning on 63 files |
| MediaFile with both bitrate and minBitrate or maxBitrate | Not checked | Warning on 45 files |
| URL not wrapped in CDATA | Not checked | Warning on 28 files |
| conditionalAd, deprecated in VAST 4.1 | Not checked | Warning on 17 files |
| VAST 1.0 root element instead of VAST | No schema | Warning 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.
| Statistic | vastlint | xmllint with IAB XSD |
|---|---|---|
| Documents per second | 19,824 | About 21,500 |
| Median (p50) | 50 µs | Not measured per document |
| p95 | 82 µs | Not measured per document |
| p99 | 175 µs | Not measured per document |
| Work per document | Parse plus 235 rules | One XSD validation pass |
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@vendorWhat 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 validatorSources 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.
The script behind the IAB half of this benchmark.
What vastlint.org stores from its web tools and how stored tags may be used.
How vastlint derives rules from XSDs and from normative specification text.
The verification node behind the 4.1 schema gap.