The artifact decides the install
Install the surface that sees the tag at the moment you are allowed to reject it.
| What you hold | Surface | Who runs it | What it will not do |
|---|---|---|---|
| One tag in a thread or a ticket | Website: validate, tester, inspector | A person, once | It will not remember the next tag |
| A repository of tag fixtures | CLI in CI | The build | It will not fetch a production URL unless you ask a separate step to |
| The VAST response inside a server | In-process library | The bid path, the ad server, or the stitcher | It will not play the creative on a device |
| An agent setting up campaigns | MCP | The agent, as a tool call | It will not replace the human pass on a wrapper you have not fetched |

Someone evaluating vastlint is usually one of four seats, and they are easy to mix because the rules are the same. A verification manager holds a tag in a thread. A trafficker holds a URL and an attachment. A publisher ad ops lead holds advertiser tags arriving all week. A platform engineer holds the response inside a process that will either forward it or drop it. The website satisfies the first two on a slow day. It does not satisfy the last two, because a person with a tab is not in the path.
Pick the surface from the artifact at the moment you can still reject it. If that moment is a ticket, use the website and write down what you checked. If that moment is a pull request, the CLI belongs in CI. The CI doc shows vastlint check on a path of XML files, with --fail-on-warning when a warning should fail the build, a GitHub Action that wraps the binary, and a container image for GitLab. No Rust toolchain is required to run the check. If that moment is the process that already fetched the demand or the advertiser tag, the library belongs in that process. The Go note walks a chain: fetch a hop, validate it, unwrap only when the wrapper is sound, stop at a depth limit. The ad server doc is the same idea for an SSP, a DSP, or a stitcher that cannot pay a network round trip for the check.
What the website is for
The website is a single tag, in front of a person who can read the result. Validate when you already have XML. Test when you have a URL and need the body, the media, and the trackers that URL returns now. Inspect when the body is a wrapper and the failure is on a later hop. That split matters. A tester result that looks fine on hop one is how a dropped verification node survives until the buyer complains.
Do not make the website the control for a team that ships tags daily. It has no memory of yesterday's tag, and it is not on the request path. It is the debugger for the tag the other surfaces rejected, and the only surface a non-engineer will open. The verification manager and the trafficker notes are that use. Send engineers elsewhere.
What CI is for
CI is a tree of files you are willing to store. Creative fixtures, golden wrappers, tags exported from a template. vastlint check exits non-zero when there are errors, so the build fails. --fail-on-warning is how you treat the advisory class as a break when you have decided those advisories cost money. The files in the repo are the contract. A production URL that changes under you is not in that contract unless a job fetches it and writes the body where the checker can see it.
This is the right install for a creative pipeline and for a publisher or an agency that wants a known-bad tag to fail review before a person trafficks it. It is the wrong install for a bid response that exists for a few hundred milliseconds and is never a file. Do not staff an engineer to commit every demand response so CI can look at it.
Get VAST spec updates, platform guides, and release notes in your inbox.
What in-process is for
In-process is the response you already have in memory. An ad server accepting programmatic demand, a stitcher about to insert, a DSP checking a creative before it bids. The Go integration validates each fetched hop instead of waiting for the player to discover a malformed body, and it can keep stable rule IDs so partner quality is a trend rather than a screenshot. The ad server page describes embedding the same core in Rust, Go, or Elixir, including an OTP port when the BEAM service must survive a bad response. The latency claim on that page is a measurement of the checker on stated tag sizes, not a promise about your whole bid. Read it as a budget inside the time you already spend, and measure your own tags.
In-process will not fetch a wrapper unless your code fetches it. Validating the first hop and forwarding a wrapper you did not open repeats the trafficker's mistake inside a service. If you unwrap, validate again. If you do not unwrap, do not claim you checked the inline.
An agent that sets up campaigns is a fourth seat. MCP is a tool call the agent can make, so the check is not a tab someone remembers. It is still only as good as the document or URL the agent passed. The ad ops MCP note is that workflow. It does not remove the wrapper walk.
What you should refuse to buy it for
None of the surfaces classify invalid traffic, score viewability, or decide brand suitability. A clean result is not a DoubleVerify report and not a Pixalate benchmark. None of them prove a television played the file. Device labs and the stitcher's own transcoder logs do that. Buying the embed because a slide said CTV fraud was 19 percent is a category error: the 19 percent is someone else's log, and the embed is a structural gate on your responses.
Evaluate with one hostile tag from your own traffic: a wrapper, an insecure media file, a missing verification node your buyers require, a VPAID file on a CTV fixture. Run it on the website so a non-engineer can see the result. Run the same file in CI so the build fails. If you are the service, run it in process on the hop you actually forward. If those three agree, you understand the install. If they do not, you are checking different documents and calling it one product.
Questions that pick the surface
- At the moment we can still reject the tag, is it in a ticket, a git tree, or a running process?
- Do we need the first body, or the inline at the end of the wrappers?
- Should a warning fail the build, or only an error?
- Are we promising a fraud number? If yes, this is the wrong tool.
- Who debugs the reject? They get the website. The path that must not forget gets CI or the process.
Try the one-tag surface before you install anything
Paste XML or a live URL. If the result is the reject you wanted, the same rules are what CI and the in-process check run. Nothing is stored.
Sources
GitHub Actions, GitLab, pre-commit, and Docker. vastlint check exits non-zero on errors.
Validate each fetched hop before you forward programmatic demand.
In-process checks for a service that already holds the response.
When the caller is an agent and the check has to be a tool call.
The one-tag seat that should stay on the website.