The tag passed and the column is empty
The usual QA pass on a video tag is the XML. The document parses. Impression is present. start is present. The MediaFile is https. The line goes live. Billing is then short, or the quartile report is empty, and the argument becomes whether the player is strict.
A VAST response is two contracts stapled together. The elements say which event exists. The URL inside the element is a pixel: a GET the player will make only if the event happens and the URL is still usable after macros expand. Checking the document does not check the request. Checking the request does not check that the document declared the event on a container the player will actually call.
IAB Tech Lab publishes VAST as the document the player is implementing. The event pages are the reading of that document: when start fires, which container is legal, what a wrapper does to the count. The fired request is a different object. It can be a Floodlight activity, a measurement vendor, or a house beacon, and it fails for reasons that never appear as a missing XML node. VAST tracking events are pixels is that second contract.
Impression, start, and the quartiles are three counters
Impression, start, and the quartiles are not one number with three names. Impression can fire when the ad is displayed, including when a server-side stitcher has inserted the spot and the device never painted that frame. start fires when linear playback begins, the first frame rendered. firstQuartile, midpoint, thirdQuartile, and complete line up with start, against Duration. loaded, added in VAST 4.1, fires when the file is ready and playback has not begun. creativeView fires when the creative is shown and, on linear ads, often sits next to the impression.
A large gap between impression and start is playback or exit. The player displayed the ad, or the stitcher counted the stitch, and the first frame did not render. The Tracking element can be perfect. The column is empty because the playhead never moved. If the media file times out, the player fires an Error URL with code 402 and never reaches start. If the file arrives and will not decode, the code is 405. In both cases the start URL is unused. Look at the MediaFile before you treat an empty column as a broken tracking template.
Completion rate is complete divided by start. Dividing complete by impressions mixes ads that were only fetched with ads that played. Quartile beacons are progress, not a second billable impression. If a discrepancy meeting treats firstQuartile volume as unpaid impressions, it is mixing two counters. If the quartile URL 404s while Impression returns 204, the video played and the progress log is dead. A missing Tracking node is the other failure: the player never has a URL to GET. That is a trafficking omission, not a syntax bug in a URL that was never declared. The tracking event index is the set, including firstQuartile.
The URL inside the element is a second contract
Once the node exists, the string inside it has to become an absolute https URL with a host. VAST insertions often use square-bracket macros. After the player substitutes, a token left in the hostname is not a host. A fired start URL that still contains CACHEBUSTER did not uniquely count. You copied the template out of the ad server, or the player never expanded the token. Adding a second Impression does not repair that. It adds another request with the same defect.
ClickThrough is a redirect chain. Impression and the quartile trackers are load beacons. A collector that returns 204 is impression-class. A collector that 302s to a landing page is a click tracker. Reusing the click URL as Impression, with a different cache buster, either navigates the viewer when the ad merely loads or fails the impression host because a landing page is not a 1x1. Consent macros that expand to the single digit 1 are still not a TC String. gdpr_consent=1 is valid base64. It does not decode as a TCF core string, and the impression can still return 200.
Scheme fails after the XML looks fine. An http URL on an https page is dropped by the browser before the ad server records a miss. The event name can be right and the column can still be zero. VAST macros are the legal tokens and the slots they may occupy. Lint the HAR row as a fired URL and the string stored in the creative as a template. One fixture cannot be both. A pixel checker does not parse the VAST parent. It will not tell you that a wrapper three hops up dropped TrackingEvents. That is the document's job.
<NonLinear> <TrackingEvents> <Tracking event="start"><![CDATA[https://track.example.com/start?cb=[CACHEBUSTER]]]></Tracking> </TrackingEvents></NonLinear>The container decides whether the URL is requested
start under a NonLinear creative is legal XML and has no playhead. The player can render the overlay, fire creativeView, and leave this URL alone. event="Start" is a different name from start. The lookup is case-sensitive, and the player does not call the URL. The same URL under a Companion has no linear playhead either. VAST 2.0 already includes start, and no later version removed it. An empty column on a current player is not a version mismatch. A 4.x player that skips a correctly placed Linear start is not applying a spec removal.
Put start, the quartiles, and skip inside Linear TrackingEvents. skip stays quiet until the creative is skippable and the viewer skips. A tag with no skip tracker will not tell the vendor the skip happened. progress is offset-based and can repeat. A progress URL that 302s to a landing page is the impression-versus-click mix-up on a timer. The XML validator will not move that URL into the right container for you. It will tell you the event is in a container that does not have the playhead.
Paste a fragment and standalone validation fails, because a Tracking element is not a document. Wrap it in a full VAST response before you treat a parser error as a tracking bug. Then open the live tag, not the snippet, when the ad server still has to unwrap.
Get VAST spec updates, platform guides, and release notes in your inbox.
Wrappers multiply the request. They do not repair the URL.
Each hop may carry its own start tracker. The player requests the wrapper URL and the InLine URL. Four hops that each include start produce four requests for one playback. That is accumulation. It is not a second impression. A start count that is an integer multiple of the impression count is often this chain. You see it hop by hop. A schema pass on the outermost wrapper never shows it, because the inner documents are not in that file yet.
A tracker that exists only on a wrapper the player never fetched never fires, even though the InLine played. Follow the chain before you delete the event from the InLine. The reverse is also common: the InLine plays, the wrapper tracker is the one finance reconciles, and a hop that returned an error dropped that URL while the creative still ran.
Fetch the live tag in the VAST tester. That is the creative, the tracking list, and the click URLs after the fetch. Walk the hops in the inspector when the player printed a wrapper error or the count is an integer multiple of playbacks. Then copy the fired Impression or start URL and check it as a pixel. The document can be valid. The request can still be a macro, an http URL, or a click tracker in an impression slot. Pixellint is that URL check. It is independent of IAB Tech Lab. It does not decide whether the VAST declared the event. vastlint does not decide whether the expanded Floodlight activity has src, type, and cat.
What to open on Monday
- Open the live tag URL in the tester. Confirm Impression exists, and that start sits on Linear rather than only on NonLinear.
- If the response is a wrapper, open the inspector and see which hop actually carries the tracker you reconcile.
- Copy the fired Impression and start URLs from the player log or a HAR. Square brackets mean the macro did not expand.
- Lint the fired URL as fired, and the trafficking string as a template. Do not run one fixture as both.
- Do not add a second Impression to force a count when the first URL is http or still a macro.
- Do not treat quartile volume as unpaid impressions. Bill on Impression. Reconcile playback on start.
Fetch the tag, then check the beacon
Paste the live tag URL into the tester for the creative and the tracking list. If it is still a wrapper, open the inspector for the hops. Paste the fired Impression URL into the pixel checker when the XML is no longer the question.
Open a tag in the testerSources
IAB Tech Lab's Video Ad Serving Template, the document players implement.
When linear playback begins, how it differs from impression, and what a wrapper does to the count.
The event set, which container each one belongs on, and which versions include it.
Which tokens are legal, and where they may sit before the player expands them.
Impression, quartile, and click URLs as three pixel contracts on one tag.
Fetch a live tag URL, preview the creative, and read the tracking and click URLs.
Wrapper chain hop by hop, including which hop carries the tracker.