VAST validator for browser, WASM, and edge
Short answer: install vastlint and call validate(xml). It is the Rust validation core compiled to WebAssembly, so the same rules that run in the CLI run client-side or at the edge, with no server round trip.
This is the right binding when validation belongs in the browser, a build step, or an edge function: a publisher-side preflight before a tag reaches the player, a creative-upload UI that lints as you type, or a Worker that rejects malformed VAST before it ever hits an exchange.
Environment support
- Vite, Webpack 5, Rollup: supported (Webpack needs
asyncWebAssembly; Rollup needs@rollup/plugin-wasm) - Deno: supported via native static WASM imports
- Cloudflare Workers: supported with Workers-specific WASM binding syntax
- Plain
<script type="module">: not supported by this build; use a bundler
Install
npm install vastlintMinimal example
import { validate } from 'vastlint';
const result = validate(xmlString);
if (!result.summary.valid) {
for (const issue of result.issues) {
console.warn(`[${issue.severity}] ${issue.id}: ${issue.message}`);
}
}Beyond validate, the package also exports validateWithOptions, validateFiltered, inspectDocument for wrapper-chain structure, rules for the rule catalog, and fix / fixWithOptions for auto-remediation.
At the edge: Cloudflare Workers
// Cloudflare Worker: reject malformed VAST at the edge
import { validate } from 'vastlint';
export default {
async fetch(request) {
const xml = await request.text();
const result = validate(xml);
if (!result.summary.valid) {
return Response.json({ issues: result.issues }, { status: 422 });
}
return new Response(xml, { headers: { 'content-type': 'application/xml' } });
},
};Why validate VAST at the edge or in the browser
A broken VAST tag is a billed impression that renders nothing: the player loads, the auction clears, the publisher is charged, and the viewer sees a blank slot. The cheapest place to catch that is before the request fans out: if an edge function rejects a malformed tag, it never reaches the exchange, the player, or the impression counter.
Because this is the Rust engine compiled to WebAssembly, you get the same rule coverage as the CLI without a server round trip: no validation service to call, no XML leaving the client or the worker. That is what makes it usable in two places a normal library cannot go: inside the browser, and inside an edge runtime with a tight CPU budget.
Where it lands in an SSP, publisher, or edge stack
- Edge preflight (Cloudflare Workers / edge functions): sit in front of an ad server or SSP endpoint and reject malformed VAST before it is forwarded, turning a downstream wasted impression into a 4xx at the edge.
- Publisher-side gate: validate a tag in the page or app shell before handing it to the player, so a bad creative degrades to your fallback instead of a blank slot.
- Creative-upload UI: lint as the trafficker types or pastes, with errors shown live in the browser, with no backend round trip per keystroke.
- QA console: a browser tool that validates and previews tags during demand-partner onboarding.
For the in-page tooling case, the React layer wraps this engine with session, playback, and tracking hooks; see the React guide.
When not to use the WASM binding
For a server-side Node.js service, see the Node.js guide; it uses the same package. For a quick manual answer use the web validator, and for AI agents use the MCP server instead of bundling WASM.