{
  "posts": [
    {
      "slug": "how-to-validate-viewableimpression",
      "title": "How to Validate ViewableImpression in VAST Tags",
      "description": "ViewableImpression URLs that are empty or HTTP-only fail the viewability join even when quartiles fire.",
      "publishedAt": "2026-09-19",
      "updatedAt": "2026-09-19",
      "author": "Alex Sekowski",
      "readingTime": "11 min read",
      "heroKicker": "Viewability",
      "tags": [
        "ViewableImpression",
        "VAST 4.0",
        "Viewability",
        "How-to",
        "CTV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A CTV line item can show one hundred percent quartile completion in the DSP while the viewability vendor reports undetermined on the same impressions. The trafficking export lists ViewableImpression because someone migrated the tag to VAST 4.0. The player fired start, firstQuartile, midpoint, thirdQuartile, and complete on schedule. The viewability dashboard stayed flat because the URLs that were supposed to carry the MRC-style state never executed.",
            "The production bug is rarely a player that refuses to measure viewability on principle. It is a ViewableImpression subtree that exists in XML but cannot complete the join: empty CDATA inside Viewable, NotViewable, or ViewUndetermined, HTTP-only asset hosts on HTTPS-only CTV apps, creative tracking pasted under ViewableImpression where the schema allows only the three viewability children, or a wrapper chain that drops the block while quartile TrackingEvents survive on the merged InLine.",
            "IAB Tech Lab introduced ViewableImpression in VAST 4.0 as a dedicated container for viewability-state beacons, separate from the standard Impression URL and separate from quartile TrackingEvents. VAST 4.3 refined semantics and wrapper-chain handling for server-side insertion environments. This piece is the envelope check: where ViewableImpression lives, which child URLs must be fetchable before a player or measurement script can classify an impression, and what validation can catch while linear video still plays normally. It is not a substitute for OMID; AdVerifications remains the path for third-party viewability scripts."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why hollow viewability beacons look like a player bug",
          "paragraphs": [
            "Buyers reconcile viewability in a different pipeline than delivery. DSP and ad-server dashboards count starts and completes. Viewability vendors and in-house MRC-style reports count Viewable, NotViewable, and ViewUndetermined firings against their thresholds. When only quartiles arrive, delivery looks healthy and viewability looks broken, which sends engineers to firmware and SDK release notes before anyone pastes the resolved VAST.",
            "That delay is expensive because quartile URLs and viewability URLs share the same trafficking template in many tools. A generator that copies the complete beacon into TrackingEvents and leaves ViewableImpression as an empty placeholder satisfies a spreadsheet column named viewability without giving the player anything to ping when OMID is absent.",
            "SSAI paths make the gap worse. Stitchers that rebuild InLine from MediaFiles and Impression often preserve quartile TrackingEvents because those URLs are wired into transcode and pod timing. ViewableImpression is easier to drop as optional metadata from an upstream wrapper. The living-room device plays the spot and fires completes while the viewability join never receives a non-empty HTTPS URL.",
            "Open auction metadata does not rescue the join. Sellers expose viewability measurement in deal notes or verification product flags while the VAST the player resolves carries ViewableImpression with blank children. The buy looked measured. The classification pipeline had nothing to classify."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What ViewableImpression actually measures",
          "paragraphs": [
            "ViewableImpression is not the impression pixel. The InLine Impression element fires on load or on a player-defined threshold that may or may not align with MRC viewability rules. ViewableImpression holds up to three optional child URLs, Viewable, NotViewable, and ViewUndetermined, that fire when the player or an integrated measurement layer decides which state applies.",
            "Quartile TrackingEvents measure media progress against Duration. They do not prove that fifty percent of pixels were in view for two continuous seconds. A tag can fire midpoint on a minimized outstream unit or on a CTV panel where the ad rendered off-screen. ViewableImpression is where the document declares separate endpoints for viewability classification, when the stack implements VAST 4.x viewability semantics at all.",
            "The population that matters for QA is the resolved InLine the player parses after redirects and after SSAI, not the first wrapper hop and not the trafficking PDF. Validating ViewableImpression on hop one while the final chain omits the block is the same category error as validating UniversalAdId only on the entry URL.",
            "OMID AdVerifications can run parallel to ViewableImpression or replace reliance on the three child URLs entirely, depending on the verification vendor and player. Many CTV stacks prefer OMID for third-party viewability while still accepting ViewableImpression for legacy server-side classification. Empty ViewableImpression plus missing AdVerifications leaves you with quartiles only, which is the failure mode this check targets."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where ViewableImpression lives and what the player reads",
          "paragraphs": [
            "In typical VAST 4.x linear traffic, ViewableImpression sits at InLine level alongside Impression, Error, Creatives, and Extensions, not inside Linear TrackingEvents. That placement matters because players walk different trees for creative progress beacons versus ad-level viewability containers. Pasting a Tracking event under ViewableImpression violates the schema and can cause strict parsers to reject the entire block.",
            "Each allowed child is a URI element: CDATA holds the HTTPS URL the player or measurement layer should request when the corresponding viewability state is determined. Viewable fires when the ad meets the implemented viewability definition. NotViewable fires when measurement completes and the ad did not qualify. ViewUndetermined fires when the environment cannot decide, which is common on SSAI-only paths without client-side confirmation.",
            "The optional id attribute on ViewableImpression helps when multiple viewability vendors appear in one document. Duplicate ids or duplicate Viewable URLs across wrapper hops can double-count in downstream logs if the player merges chains naively. VAST 4.3 guidance emphasizes clearer wrapper handling; operational QA still needs the merged view the device will see.",
            "Nothing in ViewableImpression executes at ad-server response time beyond XML parsing. The player selects MediaFile, begins playback, evaluates viewability through OMID or native APIs if present, and then fires the appropriate child URL. If every child is empty or uses HTTP on a secure app, most stacks skip the viewability join silently and continue firing quartiles."
          ]
        },
        {
          "type": "list",
          "heading": "What ViewableImpression validation can catch before playback",
          "items": [
            "ViewableImpression containing anything other than Viewable, NotViewable, and ViewUndetermined.",
            "Empty CDATA on any populated viewability child (VAST-2.0-url-empty class findings on URI fields).",
            "HTTP viewability beacon URLs on HTTPS-only CTV inventory.",
            "Malformed URLs that fail URI parsing while quartile TrackingEvents on the same Linear still look valid.",
            "ViewableImpression present on the trafficking export but absent on the unwrapped live InLine or post-SSAI output.",
            "Viewability children present but every URL blank while Impression and complete still fire (spreadsheet false positive).",
            "Creative TrackingEvents mistakenly nested under ViewableImpression instead of Linear TrackingEvents."
          ]
        },
        {
          "type": "code",
          "heading": "A ViewableImpression block that should pass validation",
          "language": "xml",
          "code": "<InLine>\n  <Impression><![CDATA[https://track.example.com/impression]]></Impression>\n  <ViewableImpression id=\"viewability-vendor-a\">\n    <Viewable><![CDATA[https://track.example.com/viewable]]></Viewable>\n    <NotViewable><![CDATA[https://track.example.com/not-viewable]]></NotViewable>\n    <ViewUndetermined><![CDATA[https://track.example.com/undetermined]]></ViewUndetermined>\n  </ViewableImpression>\n  <Creatives>\n    <Creative>\n      <Linear>\n        <Duration>00:00:30</Duration>\n        <TrackingEvents>\n          <Tracking event=\"complete\"><![CDATA[https://track.example.com/complete]]></Tracking>\n        </TrackingEvents>\n      </Linear>\n    </Creative>\n  </Creatives>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "What a player does with that viewability envelope",
          "paragraphs": [
            "After the InLine resolves, the player fires Impression according to its own rules, starts linear playback, and evaluates viewability through OMID verification scripts and/or native viewability APIs where implemented. When classification completes, it requests the matching Viewable, NotViewable, or ViewUndetermined URL.",
            "Quartile and complete TrackingEvents on Linear proceed independently. A valid ViewableImpression block does not guarantee MRC-compliant numbers on every device; it guarantees the tag declared fetchable endpoints for the three states the VAST 4.x model expects.",
            "If all three child URLs are non-empty HTTPS endpoints, downstream vendors can still disagree on counts when wrapper merges duplicate beacons or when SSAI fires server-side impressions without client confirmation. Envelope validation proves the document handed the stack a complete viewability contract in XML shape; it does not prove agreement between verification vendors."
          ]
        },
        {
          "type": "code",
          "heading": "A ViewableImpression block that lists viewability but should be flagged",
          "language": "xml",
          "code": "<ViewableImpression id=\"vi1\">\n  <Viewable><![CDATA[]]></Viewable>\n  <NotViewable><![CDATA[http://track.example.com/not-viewable]]></NotViewable>\n  <Tracking event=\"viewable\">\n    <![CDATA[https://track.example.com/wrong-node]]>\n  </Tracking>\n</ViewableImpression>"
        },
        {
          "type": "paragraphs",
          "heading": "Why that block still looks compliant in a spreadsheet",
          "paragraphs": [
            "Trafficking exports often reduce viewability to a yes/no column: ViewableImpression present. The container exists and id is set, so the row looks migrated to VAST 4.0. Viewable CDATA is empty, so the primary state beacon has nothing to fetch even if the player implements native viewability.",
            "NotViewable uses HTTP, which mixed-content rules block on many HTTPS CTV apps. The stray Tracking node under ViewableImpression is not a valid child; parsers that strict-reject the container drop the entire block, including the partially valid NotViewable entry, while Linear TrackingEvents elsewhere in the document continue to fire.",
            "Fix order: move creative tracking back under Linear TrackingEvents, require non-empty HTTPS URIs on each viewability child you intend to use, remove unknown children, and re-run validation on the unwrapped InLine the player will see after SSAI."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "ViewableImpression versus OMID and SSAI",
          "paragraphs": [
            "MRC viewability on CTV often depends on OMID AdVerifications or on vendor SDKs embedded in the app, not on VAST child URLs alone. SSAI guidance from measurement bodies stresses that server-fired beacons cannot confirm viewability the way client-side confirmation can, which is why client beacons remain recommended even under stitchers.",
            "ViewableImpression still matters for stacks that map native viewability results to the three URLs without loading a full verification script, and for legacy integrations that never adopted AdVerifications. Validating the container catches the case where someone added the 4.0 element for compliance optics but left every URL blank.",
            "Do not treat a passing ViewableImpression check as OMID readiness. JavaScriptResource under Verification carries apiFramework omid, vendor codes, and executable URLs. That hop is documented in the AdVerifications how-to. This hop is the simpler tri-state beacon envelope."
          ]
        },
        {
          "type": "list",
          "heading": "A pre-launch ViewableImpression checklist",
          "items": [
            "Declared VAST version is 4.0+ and ViewableImpression sits at InLine level on the document the player resolves.",
            "Each viewability child you rely on has non-empty HTTPS CDATA and parses as a valid URI.",
            "ViewableImpression contains only Viewable, NotViewable, and ViewUndetermined; quartile beacons stay under Linear TrackingEvents.",
            "The unwrapped live chain, including post-SSAI output, still contains the same ViewableImpression subtree as the trafficking export.",
            "If the buy requires third-party viewability, AdVerifications is present and OMID-capable, not only empty ViewableImpression placeholders.",
            "Wrapper merge review: duplicate Viewable URLs across hops are intentional or deduped in player config.",
            "Compare viewability vendor logs against resolved VAST when quartiles fire but viewability stays undetermined."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What viewability envelope validation cannot prove",
          "paragraphs": [
            "A valid ViewableImpression block is necessary, not sufficient. XML checks do not download every beacon, confirm MRC thresholds on each CTV firmware build, or prove OMID scripts executed. They will not catch a stitcher that removes ViewableImpression after you validated the upstream chain.",
            "They also will not replace vendor-side reconciliation when Impression fires from the ad server while viewability fires from the client. Timing skew between those hops is a measurement design problem, not something URI validation resolves.",
            "If complete fires and viewability still reports undetermined, compare the resolved InLine against the trafficking export. If the video never starts, fix MediaFiles first. If the video plays and ViewableImpression is absent or hollow on the live chain, this checklist is the one."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate ViewableImpression in your VAST tag",
          "paragraph": "Paste a tag or fetch a live URL. vastlint checks ViewableImpression shape, URI fields, and allowed children on the unwrapped chain before launch.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "IAB VAST standard",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "VAST 4.0 ViewableImpression for viewability-state tracking URLs.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST-4.0-viewableimpression-unknown-child",
              "href": "/docs/rules/VAST-4.0-viewableimpression-unknown-child/",
              "description": "ViewableImpression may only contain Viewable, NotViewable, and ViewUndetermined.",
              "source": "Rules"
            },
            {
              "label": "VAST-2.0-url-empty",
              "href": "/docs/rules/VAST-2.0-url-empty/",
              "description": "Empty URI fields on viewability children fail silently at fetch time.",
              "source": "Rules"
            },
            {
              "label": "VAST 3.0 to 4.0 migration",
              "href": "/docs/vast-3-to-4/",
              "description": "ViewableImpression introduction and example tri-state beacons.",
              "source": "Docs"
            }
          ]
        }
      ]
    },
    {
      "slug": "how-to-validate-closed-captions-in-vast",
      "title": "How to Validate Closed Captions in VAST Tags",
      "description": "ClosedCaptionFiles with an empty URL or a non-caption MIME type leave CTV inventory looking captioned in the bid while the player has nothing to render.",
      "publishedAt": "2026-09-16",
      "updatedAt": "2026-09-16",
      "author": "Alex Sekowski",
      "readingTime": "12 min read",
      "heroKicker": "Accessibility",
      "tags": [
        "Closed captions",
        "VAST 4.1",
        "MediaFiles",
        "How-to",
        "CTV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A CTV pod can complete every quartile, pass viewability, and still ship zero captions on the glass. The trafficking sheet says CC: yes because someone checked a box when the creative uploaded. The buyer's accessibility review assumes WebVTT or TTML arrived with the MediaFile. The seller's player logs a completed view. None of those dashboards inspect whether ClosedCaptionFile CDATA resolves to a fetchable track.",
            "The production bug is rarely a player that refuses captions on principle. It is a ClosedCaptionFiles subtree that exists in XML but cannot render: an empty URI inside ClosedCaptionFile, a type attribute that names video/mp4 instead of text/vtt, language missing on a multilingual pod, or ClosedCaptionFiles copied on the trafficking export but stripped by SSAI before the living-room device parses the InLine.",
            "IAB Tech Lab added ClosedCaptionFiles under MediaFiles in VAST 4.1 as an accessibility container for sidecar caption tracks. VAST 4.2 tightened MediaFiles child rules and VAST 4.4 extends the same container to NonLinear MediaFiles. This piece is the envelope check: where captions live, which attributes must be present before a CTV SDK fetches a track, and what validation can catch while linear video still plays normally."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why hollow captions are a compliance and reach problem",
          "paragraphs": [
            "Regulated and brand-led CTV buys increasingly treat captions as part of the creative contract, not a post-production nice-to-have. When the track never loads, the campaign can be out of policy with the publisher or the advertiser's accessibility checklist even though delivery metrics look fine. Support tickets arrive after manual review on one device model shows no CC button or no visible text during dialogue.",
            "That delay is expensive because nobody reconciles caption presence in the same pipeline as quartile completion. DSP dashboards count impressions. Publisher ad servers count starts and completes. SSAI logs transcode success on the mezzanine or the highest MediaFile rung. None of those signals prove ClosedCaptionFile returned 200 with a caption MIME type.",
            "Open auction metadata makes the gap worse. Sellers expose accessibility or language flags in deal notes, ad server UI, or downstream OpenRTB extensions while the VAST the player resolves carries ClosedCaptionFiles with placeholder URLs copied from a template. The bid looked captioned. The rendered pod did not.",
            "Wrapper chains and stitchers compound silent loss. Captions can sit under MediaFiles inside an InLine three redirects deep. QA that validates hop one sees ClosedCaptionFiles and assumes compliance. The final InLine the player resolves under timeout may have dropped the entire container when an intermediary flattened the document for latency."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What ClosedCaptionFiles actually carries",
          "paragraphs": [
            "ClosedCaptionFiles is a sibling of MediaFile, Mezzanine, and InteractiveCreativeFile inside Linear MediaFiles (and, in VAST 4.4 portfolio work, under NonLinear MediaFiles as well). The XSD allows one or more ClosedCaptionFile children. Each ClosedCaptionFile is a URI element: CDATA holds the HTTPS URL to the sidecar track, not embedded caption text.",
            "The type attribute identifies the MIME type of the caption file. Production examples use text/vtt for WebVTT, application/ttml+xml for TTML, or other text-based caption formats the player supports. Treating type as optional in generators is a mistake on 4.4 schema work where type is required on ClosedCaptionFile: players use type to decide whether to attempt a fetch before showing the CC affordance.",
            "The language attribute uses ISO 639-1 codes with an optional locale suffix per VAST 4.2 XSD documentation. Omitting language on a single-track ad is survivable on some SDKs. Omitting it on multi-language pods means the player cannot match the viewer's UI language to the correct ClosedCaptionFile when several siblings are present.",
            "Nothing in ClosedCaptionFiles executes at ad-server response time beyond XML parsing. The player selects a MediaFile, begins decode, and optionally fetches one or more ClosedCaptionFile URIs to mux text into the render pipeline or expose a system caption track. If the URI is empty or the MIME type does not match bytes on the wire, most stacks skip captions silently and continue linear playback."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where to validate: wrapper depth and post-SSAI output",
          "paragraphs": [
            "Operational QA should mirror how the player resolves the chain. Paste or fetch the entry URL, follow VASTAdTagURI redirects until you hold the InLine the device will parse, and validate ClosedCaptionFiles on that merged view. A green first hop plus missing captions on the final InLine is the same category error as validating Duration only on hop one.",
            "For SSAI, validate the document the device receives after stitching, not only the pre-stitch asset in the creative library. Stitchers that rebuild InLine from MediaFiles alone often omit ClosedCaptionFiles even when the upstream chain included them. The living-room player never sees the caption contract the trafficker exported.",
            "Version declarations matter. ClosedCaptionFiles under MediaFiles requires VAST 4.1 or later. Feeds that declare 2.0 or 3.0 while injecting ClosedCaptionFiles rely on lenient parsers. Strict CTV SDKs ignore unknown 4.x children on older version strings, which looks like captioned trafficking with no CC at playback.",
            "Bid-side reviewers who only read OpenRTB video fields never see ClosedCaptionFiles at all. Caption assurance belongs on the VAST hop after the win, the same place you validate MediaFile HTTPS and tracking consistency."
          ]
        },
        {
          "type": "list",
          "heading": "What caption validation can catch before playback",
          "items": [
            "ClosedCaptionFiles containing anything other than ClosedCaptionFile elements.",
            "ClosedCaptionFile with empty CDATA URL (VAST-2.0-url-empty class findings on URI fields).",
            "Missing or incorrect type when the declared VAST version requires MIME on ClosedCaptionFile.",
            "HTTP caption asset URLs on HTTPS-only CTV inventory.",
            "language absent when multiple ClosedCaptionFile siblings target different locales.",
            "ClosedCaptionFiles present on the trafficking export but absent on the unwrapped live InLine or post-SSAI output.",
            "type naming a video MIME while CDATA points at a sidecar caption path (player may never invoke the caption loader)."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "MIME type and empty URL failures in practice",
          "paragraphs": [
            "Trafficking tools sometimes copy the MediaFile type attribute into ClosedCaptionFile because both live under MediaFiles. A ClosedCaptionFile typed video/mp4 with a .vtt URL is internally inconsistent: the player may classify the track as video and refuse to parse cues.",
            "Empty CDATA is worse because schema validators and lenient parsers disagree. Some SDKs treat empty ClosedCaptionFile as absent. Others allocate a caption slot, attempt fetch against an empty string, fail without surfacing an error code, and leave the CC toggle visible but inert.",
            "Sidecar captions are not burned-in video. If the only caption artifact is a soft subtitle inside the mezzanine MP4 and ClosedCaptionFiles is empty, accessibility reviewers watching the exported MP4 in desktop tools see text while CTV players that expect sidecar WebVTT see nothing. Validation separates sidecar contract from baked-in pixels."
          ]
        },
        {
          "type": "code",
          "heading": "A ClosedCaptionFiles block that should pass validation",
          "language": "xml",
          "code": "<MediaFiles>\n  <ClosedCaptionFiles>\n    <ClosedCaptionFile type=\"text/vtt\" language=\"en\">\n      <![CDATA[https://cdn.example.com/spot-en.vtt]]>\n    </ClosedCaptionFile>\n    <ClosedCaptionFile type=\"text/vtt\" language=\"es\">\n      <![CDATA[https://cdn.example.com/spot-es.vtt]]>\n    </ClosedCaptionFile>\n  </ClosedCaptionFiles>\n  <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n    <![CDATA[https://cdn.example.com/spot.mp4]]>\n  </MediaFile>\n</MediaFiles>"
        },
        {
          "type": "paragraphs",
          "heading": "What a player does with that caption envelope",
          "paragraphs": [
            "After Linear resolves, the player reads MediaFiles, chooses a MediaFile rung, and inspects ClosedCaptionFiles before or during startup depending on the SDK. For each ClosedCaptionFile it records type and language, fetches the CDATA URL, and attaches the parsed cues to the render surface or exposes them through the system caption API.",
            "If both language siblings return 200 with valid WebVTT, the viewer can switch EN and ES where the app supports multi-track selection. The video decode path is unchanged: captions ride alongside MediaFile bytes rather than replacing them.",
            "If every field in the passing example is present, captions still might not appear on a given CTV device because the SDK ignores ClosedCaptionFiles on that firmware build or because the app hides CC when the stream declares embedded captions elsewhere. Envelope validation proves the tag handed the player a complete sidecar contract in the shape VAST expects; it does not prove pixel-perfect rendering on every panel."
          ]
        },
        {
          "type": "code",
          "heading": "A ClosedCaptionFiles block that lists captions but should be flagged",
          "language": "xml",
          "code": "<ClosedCaptionFiles>\n  <ClosedCaptionFile type=\"video/mp4\" language=\"en\">\n    <![CDATA[]]>\n  </ClosedCaptionFile>\n  <ClosedCaptionFile language=\"en\">\n    <![CDATA[http://cdn.example.com/captions.vtt]]>\n  </ClosedCaptionFile>\n  <Tracking event=\"start\">\n    <![CDATA[https://track.example.com/start]]>\n  </Tracking>\n</ClosedCaptionFiles>"
        },
        {
          "type": "paragraphs",
          "heading": "Why that block still looks compliant in a spreadsheet",
          "paragraphs": [
            "Trafficking exports often reduce captions to a yes/no column: ClosedCaptionFiles present. The first ClosedCaptionFile declares language en and type video/mp4, so the row looks populated while the MIME type tells the player not to treat the resource as a text track. The CDATA is empty, so there is nothing to fetch even if type were corrected.",
            "The second ClosedCaptionFile points at a plausible .vtt path but uses HTTP and omits type on versions that require it. Mixed-content rules block many HTTPS CTV apps from fetching the track. The stray Tracking node under ClosedCaptionFiles is not a valid child; parsers that strict-reject the container drop the entire block, including any partially valid ClosedCaptionFile entries.",
            "Fix order: non-empty HTTPS URIs, caption MIME types on type, language on each sibling, move creative tracking back under Linear TrackingEvents, and re-run validation on the unwrapped InLine the player will see."
          ]
        },
        {
          "type": "list",
          "heading": "A pre-launch closed-caption checklist",
          "items": [
            "Declared VAST version is 4.1+ and ClosedCaptionFiles sits under MediaFiles on the InLine the player resolves.",
            "Every ClosedCaptionFile has non-empty HTTPS CDATA and a caption MIME type in type.",
            "language is set when multiple ClosedCaptionFile siblings exist or when the buy specifies locale.",
            "The unwrapped live chain, including post-SSAI output, still contains the same ClosedCaptionFiles subtree as the trafficking export.",
            "curl -sI each caption URL returns 200 with a text-compatible Content-Type.",
            "ClosedCaptionFiles contains only ClosedCaptionFile children.",
            "Caption sidecar presence is not inferred from burned-in video inside MediaFile alone."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when hollow captions should block launch",
          "language": "sh",
          "code": "vastlint check tag.xml --format json\n\nvastlint check tag.xml --fail-on-warning\n\nvastlint check \"https://ad.example.com/vast?cid=9001\" --unwrap"
        },
        {
          "type": "paragraphs",
          "heading": "What caption validation cannot prove",
          "paragraphs": [
            "A valid ClosedCaptionFiles envelope is necessary, not sufficient. XML checks do not download every WebVTT, verify cue timing against the mezzanine, or confirm the CTV SDK implements sidecar captions on that firmware. They will not catch a stitcher that removes ClosedCaptionFiles after you validated the upstream chain.",
            "They also will not replace manual CC review on reference devices. Some players render captions only on web and ignore ClosedCaptionFiles on native CTV even when the XML passes. Session logs from those SDKs rarely mention captions; they simply never attach a text track.",
            "If quartiles fire and accessibility still reports missing captions, compare the resolved InLine against the trafficking export. If the video never starts, fix MediaFiles first. If the video plays and ClosedCaptionFiles is absent or hollow on the live chain, this checklist is the one."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate closed captions in your VAST tag",
          "paragraph": "Paste a tag or fetch a live URL. vastlint checks ClosedCaptionFiles shape, URI fields, and container rules on the unwrapped chain before launch.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "IAB VAST standard",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "VAST 4.1+ ClosedCaptionFiles under MediaFiles for sidecar caption tracks.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST-4.2-closedcaptionfiles-unknown-child",
              "href": "/docs/rules/VAST-4.2-closedcaptionfiles-unknown-child/",
              "description": "ClosedCaptionFiles may only contain ClosedCaptionFile elements.",
              "source": "Rules"
            },
            {
              "label": "VAST-2.0-url-empty",
              "href": "/docs/rules/VAST-2.0-url-empty/",
              "description": "Empty URI fields on ClosedCaptionFile CDATA fail silently at fetch time.",
              "source": "Rules"
            },
            {
              "label": "VAST 4.0 to 4.1 migration",
              "href": "/docs/vast-4-to-4-1/",
              "description": "ClosedCaptionFiles introduction and example WebVTT sidecar.",
              "source": "Docs"
            }
          ]
        }
      ]
    },
    {
      "slug": "how-to-validate-vast-icons",
      "title": "How to Validate VAST Icons",
      "description": "An Icon without program, height, width, position, and a renderable resource never appears on CTV, so AdChoices and why-this-ad overlays fail silently while the spot still plays.",
      "publishedAt": "2026-09-13",
      "updatedAt": "2026-09-13",
      "author": "Alex Sekowski",
      "readingTime": "11 min read",
      "heroKicker": "Industry icons",
      "tags": [
        "Icons",
        "AdChoices",
        "VAST 3.0",
        "How-to",
        "CTV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A CTV pod can deliver a clean :15, fire every quartile, and still ship zero visible disclosure. The buyer's compliance review assumes AdChoices appeared because the trafficking sheet says Icons: yes. The seller's player logs a completed view. Neither dashboard names the overlay that never rendered, because the linear MediaFile played and the impression pixel fired on schedule.",
            "The usual production bug is not a missing DAA browser extension on the living-room device. It is an Icon element that exists in the XML but cannot be drawn: program missing so the player does not know which overlay slot to fill, width and height absent so layout math fails, xPosition and yPosition empty so the badge lands off-screen or defaults unpredictably, or a StaticResource with an empty CDATA body so there is metadata but no fetchable image.",
            "IAB Tech Lab introduced Icons under Linear in VAST 3.0 so ad servers could ship industry overlays (AdChoices, why-this-ad, custom program badges) inside the same document as the creative. VAST 4.4 draft work extends Icons to NonLinearAds for pause and portfolio formats. This piece is the container check: where Icons lives, which attributes must be present before any CTV SDK paints pixels, and what validation can catch while the video still plays normally."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why a silent icon failure is a compliance and revenue problem",
          "paragraphs": [
            "Self-regulatory programs treat visible AdChoices as part of the buy, not a creative nice-to-have. When the badge never renders, the campaign can be out of policy with the publisher and the program even though delivery metrics look fine. Support tickets arrive weeks later when a manual screen capture on one device model shows no triangle in the corner.",
            "That delay is expensive because nobody reconciles icon presence in the same pipeline as quartile completion. DSP dashboards count impressions. Publisher ad servers count starts and completes. Neither side tracks whether Icons resolved to a bitmap on the glass. The failure mode looks like a player bug until someone pastes the VAST and notices the Icon block is hollow.",
            "SSAI stitchers compound the problem. Many templates copy MediaFiles and Impression faithfully and treat Icons as optional decoration from an upstream era. The stitched InLine the device receives may declare version 4.2 while omitting the Icons subtree that lived on the pre-stitch Linear. The spot transcodes and plays. The disclosure overlay from the trafficking export never reaches the player parser.",
            "Wrapper chains create the same invisible loss. Icons can sit on Linear inside an InLine three redirects deep. QA that validates hop one sees an Icon with program AdChoices and assumes compliance. The final InLine the player resolves under timeout may have dropped Icons when an intermediary flattened the document to VAST 2.0 shape for latency."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What Icons actually carries in the document",
          "paragraphs": [
            "Icons is a container under Linear (and, in VAST 4.4 draft guidance, under NonLinearAds for pause-style units). It holds one or more Icon children. Each Icon names its purpose with program (commonly AdChoices), declares width and height in pixels for layout, and pins placement with xPosition and yPosition, which accept keywords like left, right, top, bottom or numeric offsets per the schema.",
            "Optional duration and offset attributes tell the player how long the overlay stays visible and when it enters relative to the linear timeline. Without them, behavior is player-defined: some SDKs show the badge for the full ad, others hide it after a few seconds, and QA across devices diverges even when the XML is identical.",
            "The Icon is not the image. Like Companion and NonLinear, it must wrap a renderable resource: StaticResource for PNG and GIF badges, IFrameResource or HTMLResource for markup-heavy disclosures. IconClicks optionally carries IconClickThrough and IconClickTracking so the badge links to the opt-out or why-this-ad page. VAST 4.2 added IconClickFallbackImages for environments where click-through is blocked.",
            "None of this executes at ad-server response time. The player parses the final document, reserves a rectangle from width, height, and position, fetches the resource URL, and composites the overlay on the video surface for the declared window. If any required attribute or the resource URL is missing, most stacks skip the overlay silently and continue linear playback."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where Icons lives: Linear, NonLinearAds, and the chain you must fetch",
          "paragraphs": [
            "On VAST 3.0 through 4.3, Icons is a sibling of MediaFiles and TrackingEvents under Linear inside Creatives. It is not an InLine-level metadata field and not a substitute for CompanionAds. Checking a trafficking export that lists Icons on a wrapper while never unwrapping to the InLine is the same category error as validating Duration on hop one only.",
            "Operational QA should mirror how the player resolves the chain. Paste or fetch the entry URL, follow VASTAdTagURI redirects until you hold the InLine (or the deepest document your player timeout allows), and validate Icons on that merged view. A green first hop plus a missing Icons block on the InLine is a common false negative in manual review.",
            "For SSAI, validate the document the device receives after stitching, not only the pre-stitch asset in the creative library. Stitchers that rebuild InLine from MediaFiles alone often omit Icons even when the upstream chain included them. The living-room player never sees the upstream overlay contract.",
            "VAST 4.4 draft work places Icons under NonLinearAds as well, so pause and portfolio formats can carry the same AdChoices disclosure as linear pods. The attribute and resource rules on Icon itself do not change; only the parent path moves. Validation must target the creative type you actually traffic."
          ]
        },
        {
          "type": "list",
          "heading": "What Icon validation can catch before playback",
          "items": [
            "Icons containing anything other than Icon elements.",
            "Icon missing the required program attribute, or program present but empty.",
            "Icon missing required width, height, xPosition, or yPosition.",
            "Icon with no StaticResource, IFrameResource, or HTMLResource child.",
            "StaticResource missing creativeType or carrying an empty CDATA URL.",
            "HTTP icon asset URLs on HTTPS-only CTV inventory.",
            "IconClicks with unknown child elements that break schema parsing.",
            "Duplicate program values when the player expects one badge per program slot.",
            "Icons present on the trafficking export but absent on the unwrapped live InLine or post-SSAI output."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Required attributes versus the attributes players actually use",
          "paragraphs": [
            "VAST 3.0 made program, width, height, xPosition, and yPosition required on Icon. That is stricter than many legacy feeds assume. Trafficking tools sometimes emit duration and offset copied from a template while leaving width and height blank, expecting the player to infer size from the asset. Parsers that enforce the schema reject or skip the Icon; lenient parsers may draw a zero-size box.",
            "program identifies which industry overlay this entry represents. AdChoices is the common value for the DAA triangle. Custom program strings are valid when you ship proprietary badges, but empty program gives the player no slot key. Multiple Icon entries with the same program and overlapping geometry can collide on screen.",
            "xPosition and yPosition use vastIntegerOrPercent_type in the schema, so right and top are valid keywords and numeric offsets are valid on Icon (unlike QrCodePosition in VAST 4.4, which is percent-only). Copying pixel coordinates from a QR block into an Icon without reading the type difference is a recurring generator bug."
          ]
        },
        {
          "type": "code",
          "heading": "A Linear Icons block that should pass validation",
          "language": "xml",
          "code": "<Linear>\n  <Duration>00:00:30</Duration>\n  <Icons>\n    <Icon program=\"AdChoices\" width=\"77\" height=\"15\" xPosition=\"right\" yPosition=\"top\"\n          duration=\"00:00:30\" offset=\"00:00:00\">\n      <StaticResource creativeType=\"image/png\">\n        <![CDATA[https://cdn.example.com/adchoices-77x15.png]]>\n      </StaticResource>\n      <IconClicks>\n        <IconClickThrough>\n          <![CDATA[https://optout.aboutads.info/?c=2&lang=EN]]>\n        </IconClickThrough>\n        <IconClickTracking>\n          <![CDATA[https://track.example.com/icon-click]]>\n        </IconClickTracking>\n      </IconClicks>\n    </Icon>\n  </Icons>\n  <MediaFiles>\n    <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n      <![CDATA[https://cdn.example.com/spot.mp4]]>\n    </MediaFile>\n  </MediaFiles>\n</Linear>"
        },
        {
          "type": "paragraphs",
          "heading": "What a player does with that Icons envelope",
          "paragraphs": [
            "After Linear resolves, the player reads Icons before or during startup depending on the SDK. For each Icon, it records program, computes screen coordinates from width, height, xPosition, and yPosition, fetches the StaticResource URL, and composites the PNG for the window defined by duration and offset.",
            "IconClickThrough is separate from Linear VideoClicks. Tapping the badge should open the disclosure URL, not the advertiser landing page, unless you deliberately wire the same destination. IconClickTracking fires on interaction; it does not replace impression or quartile beacons.",
            "If every field in the passing example is present, the badge still might not appear on a given CTV device because the SDK ignores Icons on that firmware build or because safe-area clipping removes a right-top overlay on ultrawide layouts. Envelope validation proves the tag handed the player a complete Icon contract in the shape VAST 3.0 expects; it does not prove pixel-perfect placement on every panel."
          ]
        },
        {
          "type": "code",
          "heading": "An Icons block that lists AdChoices but should be flagged",
          "language": "xml",
          "code": "<Icons>\n  <Icon width=\"77\" height=\"15\" xPosition=\"right\" yPosition=\"top\">\n    <StaticResource creativeType=\"image/png\">\n      <![CDATA[]]>\n    </StaticResource>\n  </Icon>\n  <Icon program=\"AdChoices\" xPosition=\"120\" yPosition=\"10\">\n    <StaticResource creativeType=\"image/png\">\n      <![CDATA[http://cdn.example.com/adchoices.png]]>\n    </StaticResource>\n  </Icon>\n  <Tracking event=\"start\">\n    <![CDATA[https://track.example.com/start]]>\n  </Tracking>\n</Icons>"
        },
        {
          "type": "paragraphs",
          "heading": "Why that block still looks compliant in a spreadsheet",
          "paragraphs": [
            "Trafficking exports often reduce icons to a yes/no column: Icons present. The first Icon has width, height, and position, so the row looks populated. program is missing, so the player cannot classify the overlay as AdChoices versus a custom badge. The StaticResource CDATA is empty, so there is nothing to fetch even if program were fixed.",
            "The second Icon declares program AdChoices but omits width and height, which are required in VAST 3.0+. xPosition 120 is schema-valid on Icon as an integer offset, but without height the layout engine may collapse the overlay to zero vertical space. The asset URL uses HTTP, which mixed-content rules block on many HTTPS CTV apps.",
            "The stray Tracking node under Icons is not a valid child. Parsers that strict-reject the Icons container drop the entire block, including any partially valid Icon entries. Fix order: require non-empty program, width, height, xPosition, yPosition, a non-empty HTTPS StaticResource with creativeType, move creative tracking back under Linear TrackingEvents, and re-run validation on the unwrapped InLine the player will see."
          ]
        },
        {
          "type": "list",
          "heading": "What the Icon rule set should complain about",
          "items": [
            "VAST-3.0-icon-program because the first Icon has no program attribute.",
            "VAST-3.0-icon-resource or empty URL warnings because the first StaticResource CDATA is empty.",
            "VAST-3.0-icon-width and VAST-3.0-icon-height because the second Icon omits dimensions.",
            "VAST-3.0-icons-unknown-child because Tracking is not allowed directly under Icons.",
            "VAST-3.0-icon-attrs when recommended attribute combinations are incomplete.",
            "HTTPS-related warnings when icon assets use HTTP on secure inventory."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "IconClicks, fallback images, and CTV remote input",
          "paragraphs": [
            "IconClickThrough is how the viewer reaches the why-this-ad or opt-out experience. Omitting IconClicks entirely is schema-valid but weak for programs that expect a tappable disclosure. Many CTV remotes cannot click arbitrary overlays; some platforms treat IconClickThrough as informational only and open the URL on a dedicated button.",
            "VAST 4.2 IconClickFallbackImages provides alternate static assets when click-through is unsupported. Each IconClickFallbackImage should carry width and height so the player knows the fallback dimensions before fetch. Missing those attributes produces the same silent skip pattern as a bare Icon.",
            "Do not confuse Icon overlays with OpenRTB regs.ext.adchoices, which carries the DAA Protect My Choices signal in the bid request. That signal and the VAST Icon solve different hops: one is auction-time preference, the other is render-time disclosure on the creative. A bid can carry adchoices while the VAST Icon is hollow, and the viewer sees no badge."
          ]
        },
        {
          "type": "list",
          "heading": "A pre-launch Icons checklist",
          "items": [
            "Declared VAST version is 3.0+ and Icons sits under Linear (or NonLinearAds for 4.4 portfolio traffic) inside the InLine the player resolves.",
            "Every Icon has a non-empty program value appropriate to the badge (AdChoices for the industry triangle).",
            "Every Icon includes width, height, xPosition, and yPosition.",
            "Every Icon includes StaticResource, IFrameResource, or HTMLResource with a non-empty HTTPS URL and correct creativeType for static assets.",
            "IconClicks present when the buy requires a clickable disclosure, with IconClickThrough pointing at the program URL.",
            "duration and offset set explicitly when QA needs consistent timing across devices.",
            "Icons contains only Icon children; creative TrackingEvents stay under Linear.",
            "The unwrapped live chain, including post-SSAI output, still contains the same Icons subtree as the trafficking export."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when hollow icons should block launch",
          "language": "sh",
          "code": "vastlint check tag.xml --format json\n\nvastlint check tag.xml --fail-on-warning\n\nvastlint check \"https://ad.example.com/vast?cid=9001\" --unwrap"
        },
        {
          "type": "paragraphs",
          "heading": "What Icon validation cannot prove",
          "paragraphs": [
            "A valid Icons envelope is necessary, not sufficient. XML checks do not download the PNG, verify the CDN returns 200, or confirm the CTV SDK implements Icons on that firmware. They do not prove the badge clears notch and overscan safe areas. They will not catch a stitcher that removes Icons after you validated the upstream chain.",
            "They also will not replace manual capture on reference devices. Some players render Icons only on web and ignore them on native CTV even when the XML passes. Session logs from those SDKs rarely mention Icons; they simply never allocate the overlay layer.",
            "If quartiles fire and compliance still reports missing AdChoices, compare the resolved InLine against the trafficking export. If the video never starts, fix MediaFiles first. If the video plays and Icons is absent or hollow on the live chain, this checklist is the one."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate Icons in your VAST tag",
          "paragraph": "Paste a tag or fetch a live URL. vastlint checks Icon attributes, resources, Icons container shape, and wrapper chain before launch.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "IAB VAST standard",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "VAST 3.0 Icons under Linear; industry icon overlays and AdChoices placement.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST-3.0-icon-program",
              "href": "/docs/rules/VAST-3.0-icon-program/",
              "description": "Icon requires a non-empty program attribute.",
              "source": "Rules"
            },
            {
              "label": "VAST-3.0-icon-resource",
              "href": "/docs/rules/VAST-3.0-icon-resource/",
              "description": "Icon must include a renderable StaticResource, IFrameResource, or HTMLResource.",
              "source": "Rules"
            },
            {
              "label": "VAST-3.0-icon-attrs",
              "href": "/docs/rules/VAST-3.0-icon-attrs/",
              "description": "Width, height, and position together define a renderable overlay.",
              "source": "Rules"
            },
            {
              "label": "VAST 2.0 to 3.0 migration",
              "href": "/docs/vast-2-to-3/",
              "description": "Icons introduction and AdChoices XML example.",
              "source": "Docs"
            },
            {
              "label": "How to validate VAST wrappers",
              "href": "/blog/how-to-validate-vast-wrappers/",
              "description": "Why Icons on hop one is not proof it survives the chain.",
              "source": "Blog"
            }
          ]
        }
      ]
    },
    {
      "slug": "how-to-validate-adverifications-in-vast-tags",
      "title": "How to Validate AdVerifications in VAST Tags",
      "description": "A tag can list AdVerifications and still ship zero OMID measurement if Verification has no executable resource or the vendor key is empty.",
      "publishedAt": "2026-09-10",
      "updatedAt": "2026-09-10",
      "author": "Alex Sekowski",
      "readingTime": "12 min read",
      "heroKicker": "Verification envelope",
      "tags": [
        "AdVerifications",
        "OMID",
        "VAST 4.1",
        "How-to",
        "CTV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A VAST InLine can play a clean MP4, fire every quartile, and still deliver zero third-party measurement. The buyer's verification vendor sees an unmeasured impression. The seller's ad server logs a completed view. Both sides think the other side broke something, because the XML looked verified at trafficking time.",
            "The usual production bug is not a missing OM SDK build on the player. It is an AdVerifications envelope that exists on paper but cannot execute: a Verification node with an empty vendor attribute, a JavaScriptResource with no URL inside the CDATA, or a wrapper chain where Impression pixels survive every hop but AdVerifications never reaches the InLine the player actually parses.",
            "IAB Tech Lab moved verification out of Extensions and into a first-class AdVerifications element in VAST 4.1. That envelope is the contract between trafficking, the player, and the measurement vendor. This piece is the container check: where the block has to live, which fields must be present before OM SDK ever runs, and what XML validation can catch while the video still plays normally."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the verification envelope is a money problem",
          "paragraphs": [
            "Programmatic video buys increasingly price verification into the deal. A PMP that requires viewability or IVT measurement assumes the tag carries a parseable Verification entry with a loadable resource. When that entry is hollow, the impression still clears. The buyer's post-bid report simply marks it unmeasured, and reconciliation drifts toward the buyer's lower count.",
            "That drift is slow until it is not. Inventory that persistently fails measurement gets repriced without a support ticket. DSP algorithms shade bids on supply that cannot prove itself. The seller sees CPM decay and assumes creative fatigue, when the actual failure is a Verification shell that never pointed at an executable script.",
            "SSAI makes the envelope problem worse because the stitcher is a new publisher of VAST. It may copy Impression and MediaFiles faithfully and drop AdVerifications because the downstream player template only understands VAST 3.0 shapes. The stitched InLine plays. The verification block from the pre-stitch package is gone. Buyer and seller reports disagree, and neither side's dashboard names XML as the root cause.",
            "Wrapper chains create the same invisible loss. AdVerifications can legally sit on a Wrapper or on the InLine. Players that accumulate verification from every hop will merge entries from outer wrappers with the final InLine. A QA paste of hop one that shows a Verification block is compatible with an InLine three redirects later that never inherited it, especially when an intermediary SSP re-renders the document and strips 4.x-only children."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What AdVerifications actually carries",
          "paragraphs": [
            "AdVerifications is a container, not a measurement session. It holds one or more Verification children. Each Verification names a vendor and points at the resource the player should load: JavaScriptResource for web and many CTV SDK paths, ExecutableResource for native binaries on some platforms. Optional VerificationParameters pass vendor-specific configuration. TrackingEvents under Verification should include verificationNotExecuted so the vendor learns when load or execution failed instead of inferring silence.",
            "None of that runs at ad-server response time. The player parses the final document, discovers Verification entries, and asks OM SDK (or a legacy integration) to load the resource. If vendor is missing, both resource types are absent, or the JavaScript URL is empty, the player has nothing to execute. Many stacks still start the linear creative. Quartile pixels fire. The verification vendor sees nothing.",
            "That is the distinction from an OMID runtime guide. OM SDK integration, access modes, and session APIs matter after the envelope is valid. Envelope validation asks a narrower question: did this tag actually hand the player an identifiable vendor and a fetchable resource, in the place and shape the declared VAST version expects?"
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where the block lives: InLine, Wrapper, and the chain you must fetch",
          "paragraphs": [
            "On VAST 4.1 and later, AdVerifications is a direct child of InLine or Wrapper. It is not a Creative child and not a substitute for Linear tracking. Checking a Wrapper paste for verification while never unwrapping to the InLine is the same category error as demanding Duration on hop one.",
            "Operational QA should mirror how the player resolves the chain. Paste or fetch the entry URL, follow VASTAdTagURI redirects until you hold the InLine (or the deepest document your player timeout allows), and validate that merged view. A green first hop plus a missing block on the InLine is a common false negative in manual review.",
            "For SSAI, validate the document the device receives after stitching, not only the pre-stitch asset in the creative library. Stitchers that downgrade version or rebuild InLine from MediaFiles often omit AdVerifications even when the upstream chain included it. The player never sees the upstream envelope."
          ]
        },
        {
          "type": "list",
          "heading": "What AdVerifications envelope validation can catch before playback",
          "items": [
            "AdVerifications containing anything other than Verification elements.",
            "Verification missing the required vendor attribute, or vendor present but empty.",
            "Verification with neither JavaScriptResource nor ExecutableResource.",
            "JavaScriptResource or ExecutableResource missing apiFramework, or OMID resources not declaring apiFramework=\"omid\".",
            "ExecutableResource missing type when the platform requires it.",
            "Empty or HTTP verification script URLs on secure inventory.",
            "Duplicate vendor identifiers inside one AdVerifications block.",
            "VerificationParameters missing or empty when the vendor script requires runtime configuration.",
            "verificationNotExecuted tracking missing the [REASON] macro, weakening post-mortems.",
            "Extension type=\"AdVerifications\" on pre-4.1 documents where the player expects a top-level block instead."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "VAST 4.1+ top-level placement versus the Extension compatibility path",
          "paragraphs": [
            "VAST 4.1 introduced AdVerifications as a first-class sibling of Creatives under InLine and Wrapper. That is the shape modern OM SDK integrations target. Google IMA and other players document that 4.1 and higher should use the top-level element; older traffic sometimes wrapped the same data inside Extension type=\"AdVerifications\".",
            "The compatibility path matters in legacy feeds, but it is not interchangeable with 4.1 placement. A player configured for top-level AdVerifications will ignore verification buried only in Extensions on a document that declares version=\"4.2\". The XML can contain the data in a spec-valid Extension and still deliver zero measurement on that player.",
            "Migration work is therefore two-part: move verification to the top-level element for 4.1+ trafficking, and stop declaring 4.x while serializing pre-4.1 Extension shapes. Version honesty and envelope placement have to match, or parsers pick one shape and discard the other."
          ]
        },
        {
          "type": "code",
          "heading": "A VAST 4.2 AdVerifications envelope that should pass",
          "language": "xml",
          "code": "<InLine>\n  <AdSystem version=\"1.0\">Example Ad Server</AdSystem>\n  <AdTitle>Spring CTV :15</AdTitle>\n  <Impression><![CDATA[https://track.example.com/imp]]></Impression>\n  <AdVerifications>\n    <Verification vendor=\"measurement.example.com-omid\">\n      <JavaScriptResource apiFramework=\"omid\" browserOptional=\"true\"><![CDATA[https://cdn.measurement.example.com/omsdk/omid.js]]></JavaScriptResource>\n      <VerificationParameters><![CDATA[{\"placement\":\"ctv-spring\"}]]></VerificationParameters>\n      <TrackingEvents>\n        <Tracking event=\"verificationNotExecuted\"><![CDATA[https://track.example.com/vne?reason=[REASON]]]></Tracking>\n      </TrackingEvents>\n    </Verification>\n  </AdVerifications>\n  <Creatives>\n    <Creative id=\"9001\">\n      <Linear>\n        <Duration>00:00:15</Duration>\n        <MediaFiles>\n          <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\"><![CDATA[https://cdn.example.com/spot.mp4]]></MediaFile>\n        </MediaFiles>\n      </Linear>\n    </Creative>\n  </Creatives>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "What a player does with that envelope",
          "paragraphs": [
            "After the InLine resolves, the player reads AdVerifications before or during linear startup depending on the SDK. For each Verification, it records vendor, fetches the JavaScriptResource URL (unless browserOptional and native integration apply), passes VerificationParameters into the vendor script, and registers verificationNotExecuted if load fails.",
            "Quartile TrackingEvents on Linear are unrelated to Verification TrackingEvents. Wiring start or firstQuartile under Verification is a schema and semantics error: those events belong on the creative, not on the measurement vendor block. The player may still play media while ignoring miswired verification tracking.",
            "If every field in the passing example is present, OM SDK still might not run on a given CTV device. That is an integration question. Envelope validation only proves the tag handed the player a vendor key and a non-empty HTTPS script URL in the shape VAST 4.1 expects."
          ]
        },
        {
          "type": "code",
          "heading": "An AdVerifications block that lists verification but should be flagged",
          "language": "xml",
          "code": "<AdVerifications>\n  <Verification vendor=\"\">\n    <VerificationParameters><![CDATA[{\"campaign\":\"spring\"}]]></VerificationParameters>\n    <TrackingEvents>\n      <Tracking event=\"start\"><![CDATA[https://track.example.com/start]]></Tracking>\n    </TrackingEvents>\n  </Verification>\n  <Verification vendor=\"moat\">\n    <JavaScriptResource apiFramework=\"OMSDK\"><![CDATA[]]></JavaScriptResource>\n  </Verification>\n  <Verification vendor=\"moat\">\n    <JavaScriptResource apiFramework=\"omid\"><![CDATA[http://measurement.example.com/omid.js]]></JavaScriptResource>\n  </Verification>\n</AdVerifications>"
        },
        {
          "type": "paragraphs",
          "heading": "Why that block still looks verified in a spreadsheet",
          "paragraphs": [
            "Trafficking exports often reduce verification to a yes/no column: AdVerifications present. The first Verification has Parameters and Tracking, so the row looks populated. vendor is empty, so the player cannot disambiguate which integration to load. No JavaScriptResource or ExecutableResource exists on that entry, so there is nothing to fetch even if vendor were fixed.",
            "The second and third entries share a bare vendor name and duplicate moat, which violates the domain-qualified vendor convention and triggers duplicate-vendor warnings. The second entry's JavaScriptResource declares the wrong apiFramework and an empty CDATA body. The third points at HTTP. A shallow DOM count says three verifications. Runtime executes zero.",
            "Fix order: require non-empty vendor in domain-omid form, exactly one Verification per vendor, a non-empty HTTPS JavaScriptResource with apiFramework=\"omid\", move creative tracking off the Verification node, and add verificationNotExecuted with [REASON]. Re-run validation on the unwrapped InLine the player will see, not on the wrapper cover sheet."
          ]
        },
        {
          "type": "list",
          "heading": "What the AdVerifications rule set should complain about",
          "items": [
            "VAST-4.1-verification-vendor because the first Verification has an empty vendor attribute.",
            "VAST-4.1-verification-no-resource because the first Verification has no JavaScriptResource or ExecutableResource.",
            "VAST-4.1-verification-vendor-format because moat is not domain-qualified.",
            "VAST-4.1-verification-duplicate-vendor because moat appears twice.",
            "VAST-4.1-js-resource-apiframework-value because OMSDK is not omid.",
            "VAST-4.1-js-resource-https because the script URL uses HTTP.",
            "Verification tracking event errors because start is not a valid Verification tracking event.",
            "VAST-4.1-verification-parameters may warn on entries that need parameters; the empty-vendor entry has parameters but no resource to consume them."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Wrapper hops that drop the envelope",
          "paragraphs": [
            "Verification injected at the outermost wrapper survives only if every downstream hop preserves AdVerifications and the player merges wrapper-level entries correctly. Some SSPs flatten wrappers into a single InLine for latency and copy only Impression, Creatives, and MediaFiles. Verification from hop one never reaches the device.",
            "The failure mode looks like a vendor outage. The buyer's dashboard shows a sudden spike in unmeasured impressions on one supply path. The seller's fill and completion rates are unchanged. Support compares two VAST pastes from different days and finds verification on the trafficking export but not on the live resolved chain.",
            "Prevention is chain inspection, not a single-hop paste. Fetch the live tag URL with the same timeout and redirect policy as production, unwrap programmatically, and diff AdVerifications nodes across hops. If an intermediary strips them, fix the intermediary or move verification injection to the InLine that survives stitching."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "ExecutableResource versus JavaScriptResource on CTV",
          "paragraphs": [
            "Most web and hybrid CTV stacks use JavaScriptResource with apiFramework=\"omid\". Native-only integrations sometimes use ExecutableResource with a type attribute describing the binary interface. A Verification that lists only ExecutableResource on a player expecting JavaScript will not load measurement, even when vendor and URLs look valid for a different platform.",
            "browserOptional on JavaScriptResource tells native players they may skip the script when a native OM SDK integration exists. Omitting browserOptional on CTV webviews that cannot execute JS should lead to verificationNotExecuted, not silent success. Envelope checks cannot prove the player honored browserOptional; they can prove the attribute and resource types match the declared VAST version.",
            "When trafficking the same asset to web and CTV, duplicate Verification entries with different resource types are valid if vendor strings differ per integration. Duplicate vendor with conflicting resources is not."
          ]
        },
        {
          "type": "list",
          "heading": "A pre-launch AdVerifications checklist",
          "items": [
            "Declared VAST version is 4.1+ and AdVerifications is top-level under InLine or Wrapper, not only inside Extensions unless the player documents Extension support.",
            "Every Verification has a non-empty vendor in domain-omid form.",
            "Every Verification includes JavaScriptResource or ExecutableResource with required attributes for the target platform.",
            "OMID JavaScriptResource URLs are HTTPS, non-empty, and declare apiFramework=\"omid\".",
            "No duplicate vendor values inside one AdVerifications block.",
            "VerificationParameters present when the vendor script requires them.",
            "verificationNotExecuted tracking includes the [REASON] macro.",
            "Creative quartile tracking is on Linear, not miswired under Verification.",
            "The unwrapped live chain, including post-SSAI output, still contains the same Verification entries as the trafficking export."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when hollow verification should block launch",
          "language": "sh",
          "code": "vastlint check tag.xml --format json\n\nvastlint check tag.xml --fail-on-warning\n\nvastlint check \"https://ad.example.com/vast?cid=9001\" --unwrap"
        },
        {
          "type": "paragraphs",
          "heading": "What AdVerifications envelope validation cannot prove",
          "paragraphs": [
            "A valid envelope is necessary, not sufficient. XML checks do not download the script, verify the vendor signed it, or confirm OM SDK is integrated on the device. They do not prove verificationNotExecuted fires when execution fails. They will not catch a stitcher that removes the block after you validated the upstream chain.",
            "They also will not replace OMID session debugging. Session errors, access mode mismatches, and creative container geometry belong in player logs and vendor tooling after the envelope passes.",
            "If quartiles fire and the buyer still sees unmeasured impressions, compare the resolved InLine against the trafficking export. If the video never starts, fix Linear and MediaFiles first. If the video plays and verification is absent on the live chain, this checklist is the one."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate AdVerifications in your VAST tag",
          "paragraph": "Paste a tag or fetch a live URL. vastlint checks the Verification envelope, vendor format, resources, and wrapper chain before launch.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "What Is OMID",
              "href": "/docs/omid/",
              "description": "AdVerifications structure, Verification children, and how OM SDK uses the envelope at runtime.",
              "source": "Docs"
            },
            {
              "label": "VAST-4.1-verification-vendor",
              "href": "/docs/rules/VAST-4.1-verification-vendor/",
              "description": "Verification requires a non-empty vendor attribute.",
              "source": "Rules"
            },
            {
              "label": "VAST-4.1-verification-no-resource",
              "href": "/docs/rules/VAST-4.1-verification-no-resource/",
              "description": "Verification should include JavaScriptResource or ExecutableResource.",
              "source": "Rules"
            },
            {
              "label": "VAST-4.0-adverifications-unknown-child",
              "href": "/docs/rules/VAST-4.0-adverifications-unknown-child/",
              "description": "AdVerifications may only contain Verification elements.",
              "source": "Rules"
            },
            {
              "label": "How to validate OMID in VAST tags",
              "href": "/blog/how-to-validate-omid-in-vast-tags/",
              "description": "Runtime-oriented OMID checks after the envelope is valid.",
              "source": "Blog"
            },
            {
              "label": "How to validate VAST wrappers",
              "href": "/blog/how-to-validate-vast-wrappers/",
              "description": "Why verification on hop one is not proof it survives the chain.",
              "source": "Blog"
            },
            {
              "label": "IAB Tech Lab VAST",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "VAST 4.1 AdVerifications and Verification element definitions.",
              "source": "IAB Tech Lab"
            }
          ]
        }
      ]
    },
    {
      "slug": "how-to-validate-universaladid-in-vast-tags",
      "title": "How to Validate UniversalAdId in VAST Tags",
      "description": "UniversalAdId validation is version-specific: VAST 4.0 needs idRegistry plus idValue, VAST 4.1+ needs idRegistry plus text content. Catch a missing identity before SSAI strips it and frequency caps stop joining.",
      "publishedAt": "2026-09-07",
      "updatedAt": "2026-09-07",
      "author": "Alex Sekowski",
      "readingTime": "12 min read",
      "heroKicker": "Creative identity",
      "tags": [
        "UniversalAdId",
        "VAST 4.x",
        "How-to",
        "CTV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A VAST 4.x InLine can play a clean MP4 and still be useless for frequency capping. The creative identity that buyers, sellers, and verification vendors are supposed to share lives in UniversalAdId, not in Creative id, not in Ad id, and not in the filename on the CDN. If that element is missing, stored in the wrong place for the declared version, or rewritten on every stitch, three systems will log three different creatives for one spot.",
            "IAB Tech Lab made UniversalAdId required inside InLine Creative from VAST 4.0 onward. Wrappers do not carry it. SSAI packs that downgrade 4.x to 2.0 or 3.0 for an old player have no home for the element, so the identity is stripped even when media and duration survive. The session looks healthy in the player and broken in the frequency and competitive-separation reports.",
            "The usual production bug is not a missing MP4. It is a template that still emits the VAST 4.0 idValue attribute, sets version=\"4.2\", and leaves the element body empty. Parsers that only read text content see no identifier. This piece is the envelope check: where the ID has to live, which rule fires, and what XML validation cannot prove about Ad-ID itself."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why creative identity is a money problem",
          "paragraphs": [
            "Ad servers, DSPs, SSPs, and verification vendors each mint their own creative IDs. None of them match. UniversalAdId is the cross-system identifier, typically an Ad-ID registry code in the US or a Clearcast code in the UK. Frequency caps that are supposed to fire across two apps and a CTV channel need that one ID. Without it, a viewer who saw the same :15 three times looks like three unrelated exposures.",
            "Pod dedup is the same join with a tighter clock. Two DSPs can win adjacent slots in one break with the same asset under different internal IDs. Competitive separation (two car brands out of the same break) has the same requirement: the pod logic has to know what the creatives actually are, not what each seller labeled them in its private namespace.",
            "Audits and brand-safety reviews need a join key that survives a quarter of delivery logs from different vendors. At IAB Tech Lab's August 2026 Ad Ops workshop, buyer or advertiser demand and better frequency or separation controls each led at 33% when the room was asked what would make UniversalAdId worth enforcing. Trafficking will not put the element on every tag until those controls fail visibly.",
            "Version downgrades are the quiet kill. A 4.2 InLine that is re-rendered as VAST 3.0 for a device that \"does not support 4.x\" drops UniversalAdId because the older schema has no such child. MediaFile still plays. The identity does not. That is the same class of failure as a version mismatch the player already printed, except nobody looks at identity when the video started."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The identifier lives on the InLine, after the wrappers",
          "paragraphs": [
            "A Wrapper is allowed to be thin. Impression pixels on hop one are real. Duration is not on the wrapper. MediaFiles are not on the wrapper. UniversalAdId is not on the wrapper. Checking a pasted VASTAdTagURI document for Creative identity is a category error: the element you need is on the InLine at the bottom of the chain.",
            "SSAI makes that worse because the stitcher is a new publisher of VAST. It may fetch the chain, choose renditions, and emit a new InLine to the player. If that generated document copies Creative id from the ad server and omits UniversalAdId, or copies idValue into a 4.2 document with empty text, the player never sees the registry code. Frequency and verification vendors that read the stitched tag, not the pre-stitch InLine, join on nothing.",
            "The working split is the same as wrapper QA. File in git or a trafficking export you already unwrapped: validate the InLine. Partner URL: fetch it, then inspect hops until you see the InLine Creative. A green wrapper paste is compatible with a missing UniversalAdId three hops down."
          ]
        },
        {
          "type": "list",
          "heading": "What UniversalAdId XML validation can catch before playback",
          "items": [
            "Creative in a VAST 4.x InLine with no UniversalAdId.",
            "UniversalAdId missing idRegistry.",
            "VAST 4.0 document with no idValue attribute.",
            "VAST 4.1+ document with empty text content.",
            "VAST 4.1+ document that still uses idValue (warning; parsers that only read text content see an empty ID).",
            "idRegistry claiming Ad-ID while the value is an internal ad-server token."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "VAST 4.0 still uses the idValue attribute",
          "paragraphs": [
            "VAST 4.0 stores the identifier on idValue and keeps idRegistry as the required registry name. Text content may repeat the same code; when both are present they must agree. A 4.0 Creative with idRegistry and no idValue is a spec miss, not a style choice.",
            "Keep 4.0 templates on 4.0. Relabeling version=\"4.1\" without moving the value into text content is the migration bug IAB documented when 4.1 shipped. The schema removed idValue. A document that still has the attribute and an empty body is invalid as 4.1 even if it was valid as 4.0.",
            "If you still have to emit 4.0 for a specific player, emit 4.0 honestly. Do not declare 4.2 and internally serialize 4.0. Downstream XML parsers will pick one shape. They will not merge attribute and text for you."
          ]
        },
        {
          "type": "code",
          "heading": "VAST 4.0 shape that should pass",
          "language": "xml",
          "code": "<Creative id=\"5480\" sequence=\"1\">\n  <UniversalAdId idRegistry=\"Ad-ID\" idValue=\"CNPA0484000H\">CNPA0484000H</UniversalAdId>\n  <Linear>\n    <Duration>00:00:15</Duration>\n    <MediaFiles>\n      <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n        <![CDATA[https://cdn.example.com/video.mp4]]>\n      </MediaFile>\n    </MediaFiles>\n  </Linear>\n</Creative>"
        },
        {
          "type": "paragraphs",
          "heading": "VAST 4.1 moved the value into text. 4.2 allows more than one.",
          "paragraphs": [
            "From VAST 4.1 the identifier is the element's text content. idRegistry stays required. Leftover idValue is a warning because strict parsers ignore the attribute and then find an empty body. VAST 4.2 also allows multiple UniversalAdId children on one Creative so a spot can carry Ad-ID and Clearcast at once.",
            "That multiplicity is for registries, not for minting a new code per hop. Two UniversalAdId elements with the same registry and different values are a fight. Two elements with Ad-ID and clearcast.co.uk are the intended 4.2 case: one asset, two industry codes.",
            "SSAI output that sets version=\"4.2\", keeps idValue, and leaves the body empty is the document in the next block. It often still has a Creative id the ad server understands. The player plays. The join key is gone."
          ]
        },
        {
          "type": "code",
          "heading": "VAST 4.2+ shape that should pass",
          "language": "xml",
          "code": "<Creative id=\"5480\" sequence=\"1\">\n  <UniversalAdId idRegistry=\"Ad-ID\">CNPA0484000H</UniversalAdId>\n  <UniversalAdId idRegistry=\"clearcast.co.uk\">AAA/BBBB123/030</UniversalAdId>\n  <Linear>\n    <Duration>00:00:15</Duration>\n    <MediaFiles>\n      <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n        <![CDATA[https://cdn.example.com/video.mp4]]>\n      </MediaFile>\n    </MediaFiles>\n  </Linear>\n</Creative>"
        },
        {
          "type": "code",
          "heading": "A 4.2 creative that looks identified but should be flagged",
          "language": "xml",
          "code": "<VAST version=\"4.2\">\n  <Ad>\n    <InLine>\n      <Creatives>\n        <Creative id=\"5480\">\n          <UniversalAdId idRegistry=\"Ad-ID\" idValue=\"CNPA0484000H\"></UniversalAdId>\n          <Linear>\n            <Duration>00:00:15</Duration>\n            <MediaFiles>\n              <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">https://cdn.example.com/video.mp4</MediaFile>\n            </MediaFiles>\n          </Linear>\n        </Creative>\n      </Creatives>\n    </InLine>\n  </Ad>\n</VAST>"
        },
        {
          "type": "paragraphs",
          "heading": "What a player that only reads text content does with that 4.2 tag",
          "paragraphs": [
            "The element is present, so a shallow \"do we have UniversalAdId\" check can pass. idRegistry is present, so a registry check can pass. The identifier the 4.1+ schema actually carries is the text node, and that node is empty. Frequency systems that parse 4.2 correctly treat the creative as unidentified.",
            "Verification vendors that join on UniversalAdId will not match the pre-stitch InLine that still had idValue. Seller logs that key on Creative id will still show the campaign. The two reports disagree, and the disagreement looks like a measurement outage instead of a schema migration miss.",
            "Fix the template: copy idValue into the element body, drop the attribute on 4.1+, and keep version honest. Then re-run the stitched output, not only the pre-stitch package."
          ]
        },
        {
          "type": "list",
          "heading": "What the UniversalAdId rule set should complain about",
          "items": [
            "VAST-4.0-universaladid-present because the Creative has no UniversalAdId on a 4.x InLine.",
            "VAST-4.0-universaladid-idregistry because idRegistry is missing.",
            "VAST-4.0-universaladid-idvalue because a 4.0 document omitted the idValue attribute.",
            "VAST-4.1-universaladid-content because a 4.1+ document has no text content.",
            "VAST-4.1-universaladid-idvalue-removed because idValue is still present on 4.1+."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "UniversalAdId is not AdServingId, and not Creative id",
          "paragraphs": [
            "Creative id identifies the creative inside one ad server. Ad id identifies the buy wrapping it, also private. Those attributes are useful in that vendor's UI. They are not a cross-platform join key. Copying Creative id into UniversalAdId and setting idRegistry=\"Ad-ID\" claims a registry you do not have.",
            "AdServingId, added in VAST 4.1, identifies one serving transaction so player, verification, and ad-server logs can join a single impression. It should be unique per response, typically a GUID minted at serve time. Regenerating UniversalAdId on every response turns the asset ID into a session ID. Use AdServingId for the session. Keep UniversalAdId stable across campaigns and hops.",
            "If you do not have a registry code, idRegistry=\"unknown\" with your durable internal creative ID is honest. It will not join Ad-ID graphs. It also will not poison them. Unknown plus a stable value is still better than a new GUID per stitch."
          ]
        },
        {
          "type": "list",
          "heading": "A pre-launch identity checklist",
          "items": [
            "Declared VAST version matches the UniversalAdId shape: idValue on 4.0, text content on 4.1+.",
            "InLine Creative has at least one UniversalAdId with a non-empty idRegistry.",
            "If idRegistry is Ad-ID or Clearcast, the value is a real registry code, not the ad-server Creative id.",
            "The same identifier is on the stitched InLine the player will see, not only on the pre-SSAI package.",
            "Wrappers in the chain are not the place you look for identity; inspect until the InLine.",
            "AdServingId, if present, changes per impression. UniversalAdId does not."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when missing identity should block launch",
          "language": "sh",
          "code": "vastlint check creative.xml --format json\n\nvastlint check creative.xml --fail-on-warning"
        },
        {
          "type": "paragraphs",
          "heading": "What UniversalAdId XML validation cannot prove",
          "paragraphs": [
            "A well-formed element is necessary. It is not a certificate that Ad-ID issued the code, or that two vendors share a join table. XML checks will not call the registry. They will not tell you the buyer actually caps on UniversalAdId rather than on a private creative ID.",
            "They also will not tell you the stitcher preserved the element. Validate the document the player fetches, after SSAI, on the version the player declared. A clean package in the creative tool and a stripped InLine on the device are compatible.",
            "If the player already printed a version error, start from the version mismatch post. Identity is downstream of a document the player refused to parse. If the video played and the frequency report looks like a new creative every session, this checklist is the one."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "What Is UniversalAdId",
              "href": "/docs/universal-ad-id/",
              "description": "Why creative identity is a money problem, syntax by version, and common mistakes.",
              "source": "Docs"
            },
            {
              "label": "VAST-4.0-universaladid-present",
              "href": "/docs/rules/VAST-4.0-universaladid-present/",
              "description": "Creative must contain UniversalAdId on VAST 4.0+ InLine.",
              "source": "Rules"
            },
            {
              "label": "VAST-4.1-universaladid-content",
              "href": "/docs/rules/VAST-4.1-universaladid-content/",
              "description": "Text content is required in VAST 4.1+.",
              "source": "Rules"
            },
            {
              "label": "VAST 4.0 to 4.1",
              "href": "/docs/vast-4-to-4-1/",
              "description": "idValue removed, value moves to text content.",
              "source": "Docs"
            },
            {
              "label": "VAST 4.1 to 4.2",
              "href": "/docs/vast-4-1-to-4-2/",
              "description": "Migration notes, including multiple UniversalAdId elements.",
              "source": "Docs"
            },
            {
              "label": "A live VAST URL is not a paste",
              "href": "/blog/vast-tester-is-not-the-inspector/",
              "description": "Identity lives on the InLine. Fetch the chain before you declare the tag identified.",
              "source": "Blog"
            },
            {
              "label": "CTV Ad Ops Grows Up",
              "href": "https://iabtechlab.com/ctv-ad-ops-grows-upfrom-promising-capabilities-to-repeatable-operations/",
              "description": "August 2026 workshop recap: UniversalAdId demand and frequency or separation controls each at 33%.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Primary specification for UniversalAdId.",
              "source": "IAB"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Check the Creative identity",
          "paragraph": "Paste the InLine the player will see, not only the wrapper. Look for UniversalAdId presence and the version-correct identifier shape.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        }
      ]
    },
    {
      "slug": "how-to-validate-simid-in-vast-tags",
      "title": "How to Validate SIMID in VAST Tags",
      "description": "SIMID validation starts in the VAST XML: InteractiveCreativeFile type, apiFramework, HTTPS URL, and a MediaFile fallback. Catch envelope mistakes before you debug createSession in the player.",
      "publishedAt": "2026-08-29",
      "updatedAt": "2026-08-29",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "SIMID validation",
      "tags": [
        "SIMID",
        "VAST 4.x",
        "Interactive",
        "How-to"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "SIMID validation in VAST starts with the XML envelope. If InteractiveCreativeFile is missing type=text/html, apiFramework is not SIMID, the URL is HTTP or empty, or there is no MediaFile fallback, the interactive layer is already broken before the player loads the iframe.",
            "vastlint can catch those VAST-side SIMID mistakes in the web validator, CLI, and tester. What it cannot do is prove the SIMID handshake. createSession, postMessage, and X-Frame-Options only show up when you load the creative HTML. Validate the envelope first, then test the live tag."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What SIMID is doing in the tag",
          "paragraphs": [
            "IAB Tech Lab positions SIMID as the secure replacement for VPAID. The VAST side is InteractiveCreativeFile inside MediaFiles: type=text/html, apiFramework=SIMID, and a URL the player loads in a sandboxed iframe. The player keeps media playback. The creative talks over postMessage.",
            "Players that do not support SIMID skip the interactive file and play the MediaFile. That fallback is why a SIMID tag still needs a real video rendition. VPAID-era tags that only ship a JavaScript file fail as error 901 on CTV."
          ]
        },
        {
          "type": "list",
          "heading": "What SIMID XML validation can catch before playback",
          "items": [
            "InteractiveCreativeFile missing type, or type that is not text/html.",
            "apiFramework missing, misspelled, or still set to VPAID.",
            "Empty creative URL, HTTP URL on an HTTPS page, or a data: HTML blob the player will not fetch.",
            "No MediaFile fallback next to the interactive file.",
            "variableDuration set to a value other than true or false.",
            "Nonlinear SIMID that is missing the IFrameResource path used in SIMID 1.1."
          ]
        },
        {
          "type": "code",
          "heading": "A minimal SIMID block that should pass",
          "language": "xml",
          "code": "<MediaFiles>\n  <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1280\" height=\"720\">\n    <![CDATA[https://cdn.example.com/video.mp4]]>\n  </MediaFile>\n  <InteractiveCreativeFile type=\"text/html\" apiFramework=\"SIMID\">\n    <![CDATA[https://cdn.example.com/simid/creative.html]]>\n  </InteractiveCreativeFile>\n</MediaFiles>"
        },
        {
          "type": "code",
          "heading": "A block that looks interactive but should be flagged",
          "language": "xml",
          "code": "<MediaFiles>\n  <InteractiveCreativeFile type=\"application/javascript\" apiFramework=\"VPAID\">\n    <![CDATA[http://cdn.example.com/vpaid.js]]>\n  </InteractiveCreativeFile>\n</MediaFiles>"
        },
        {
          "type": "list",
          "heading": "What the SIMID rule set should complain about",
          "items": [
            "VAST-4.1-interactive-creative-type because the MIME type is not text/html.",
            "VAST-4.1-vpaid-apiframework or SIMID-1.0-simid-apiframework-case because apiFramework is still VPAID or the wrong case.",
            "SIMID-1.0-simid-url-https because the creative URL is HTTP.",
            "SIMID-1.0-simid-mediafile-required because there is no MediaFile fallback.",
            "Player error 901 if a VPAID unit still ships to CTV; error 902 if a SIMID file is present but fails at runtime."
          ]
        },
        {
          "type": "list",
          "heading": "Which channel to use",
          "items": [
            "The web validator at vastlint.org/validate is the fastest paste check for InteractiveCreativeFile attributes.",
            "The VAST tester at vastlint.org/tester fetches a live URL and is the right next step after the envelope is clean.",
            "The SIMID explainer at vastlint.org/docs/simid/ still titles What Is SIMID. Its paste CTA opens the tester.",
            "The CLI is the launch gate: vastlint check simid.xml. Use --fail-on-warning when SIMID hygiene should block traffic."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when SIMID should block launch",
          "language": "sh",
          "code": "vastlint check simid-example.xml --format json\n\nvastlint check simid-example.xml --fail-on-warning"
        },
        {
          "type": "paragraphs",
          "heading": "What SIMID XML validation cannot prove",
          "paragraphs": [
            "A valid InteractiveCreativeFile is necessary. It is not the same thing as a working SIMID session. The player still has to load the HTML, accept postMessage, and complete createSession. A JavaScript error, a missing iframe sandbox flag, or X-Frame-Options only shows up in a live host.",
            "Validate the XML first. Then paste the live tag into the tester. Use error 901 and 902 pages when the player already printed a code."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "What Is SIMID",
              "href": "/docs/simid/",
              "description": "Meaning, SIMID vs VPAID, and paste-into-tester CTA.",
              "source": "Docs"
            },
            {
              "label": "SIMID validation",
              "href": "/docs/simid-validation/",
              "description": "Envelope checks versus live fetch and handshake.",
              "source": "Docs"
            },
            {
              "label": "VAST tester",
              "href": "/tester/",
              "description": "Fetch a live SIMID tag and preview the creative.",
              "source": "Tool"
            },
            {
              "label": "VAST validator",
              "href": "/validate/",
              "description": "Paste XML for InteractiveCreativeFile rule checks.",
              "source": "Tool"
            },
            {
              "label": "Error 901",
              "href": "/docs/vast-error-codes/901/",
              "description": "General VPAID failure; migrate to SIMID.",
              "source": "Docs"
            },
            {
              "label": "Error 902",
              "href": "/docs/vast-error-codes/902/",
              "description": "InteractiveCreativeFile failed at runtime.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Test the live SIMID tag",
          "paragraph": "Paste a URL or XML into the tester after the envelope is clean. Use the validator when you already have resolved XML.",
          "href": "/tester/",
          "label": "Open the VAST tester"
        }
      ]
    },
    {
      "slug": "how-to-validate-companion-ads",
      "title": "How to Validate Companion Ads in VAST Tags",
      "description": "Companion validation starts in the XML: CompanionAds, width, height, and a renderable resource. Catch empty banners and unmatched IAB sizes before the page slot stays blank.",
      "publishedAt": "2026-08-29",
      "updatedAt": "2026-08-29",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Companion ads",
      "tags": [
        "Companion ads",
        "VAST",
        "Display",
        "How-to"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "Companion validation in VAST starts with the XML. If CompanionAds is missing, a Companion has no StaticResource, IFrameResource, or HTMLResource, or width and height are absent, the banner slot never fills even when the video plays.",
            "vastlint can catch empty companions and missing dimensions in the web validator and CLI. Slot matching still depends on the page. Ship 300x250 plus a large format, then paste the resolved tag. Most CTV players ignore companions."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What companion ads are doing in the tag",
          "paragraphs": [
            "Companions are display creatives served alongside linear video. The page or app, not the video decoder, renders them. VAST describes the assets in CompanionAds. Each Companion must declare width and height so the host can match a slot.",
            "required=all, any, or none on CompanionAds changes fill behavior. required=all can kill the video if no companion size matches. required=none keeps the video even when the banner misses."
          ]
        },
        {
          "type": "list",
          "heading": "What companion XML validation can catch before playback",
          "items": [
            "Companion with no renderable resource.",
            "Companion missing width or height.",
            "required set to a value other than all, any, or none.",
            "Unknown children under CompanionAds.",
            "Wrapper hops that drop CompanionAds when followCompanions is false."
          ]
        },
        {
          "type": "code",
          "heading": "A companion block that should pass",
          "language": "xml",
          "code": "<CompanionAds required=\"any\">\n  <Companion width=\"300\" height=\"250\">\n    <StaticResource creativeType=\"image/png\">\n      <![CDATA[https://cdn.example.com/300x250.png]]>\n    </StaticResource>\n    <CompanionClickThrough>\n      <![CDATA[https://advertiser.example.com/landing]]>\n    </CompanionClickThrough>\n  </Companion>\n  <Companion width=\"728\" height=\"90\">\n    <StaticResource creativeType=\"image/png\">\n      <![CDATA[https://cdn.example.com/728x90.png]]>\n    </StaticResource>\n  </Companion>\n</CompanionAds>"
        },
        {
          "type": "code",
          "heading": "A companion that looks present but should be flagged",
          "language": "xml",
          "code": "<CompanionAds required=\"all\">\n  <Companion>\n    <!-- no width, height, or resource -->\n  </Companion>\n</CompanionAds>"
        },
        {
          "type": "list",
          "heading": "What the companion rule set should complain about",
          "items": [
            "VAST-2.0-companion-resource because the Companion is empty.",
            "VAST-2.0-companion-dimensions because width or height is missing.",
            "VAST-3.0-companion-required-attr because required is not all, any, or none."
          ]
        },
        {
          "type": "list",
          "heading": "Which channel to use",
          "items": [
            "The validator at vastlint.org/validate is the paste check for Companion structure.",
            "The tester at vastlint.org/tester shows which companion assets survived a live fetch.",
            "The inspector at vastlint.org/inspect is the wrapper chain tester when companions vanish after a hop.",
            "Problem pages cover companion ads not showing and IAB sizes 300x250 and 728x90."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when companion XML should block launch",
          "language": "sh",
          "code": "vastlint check companion-example.xml --format json\n\nvastlint check companion-example.xml --fail-on-warning"
        },
        {
          "type": "paragraphs",
          "heading": "What companion XML validation cannot prove",
          "paragraphs": [
            "A valid CompanionAds block is necessary. It does not prove the publisher page has a matching slot, or that the image CDN returned 200. Size mismatch is a trafficking problem, not a schema problem.",
            "Validate the XML, ship more than one IAB size, then test the live URL. On CTV, treat a missing banner as expected unless the platform documents companion support."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "Companion ads format guide",
              "href": "/guides/vast-companion-ads/",
              "description": "CompanionAds, resource types, and tracking.",
              "source": "Guides"
            },
            {
              "label": "Companion ads not showing",
              "href": "/guides/vast-companion-ads-not-showing/",
              "description": "Empty Companion, required=all, wrappers, CTV ignore.",
              "source": "Guides"
            },
            {
              "label": "IAB companion sizes",
              "href": "/guides/vast-companion-sizes/",
              "description": "300x250, 728x90, 160x600, required width and height.",
              "source": "Guides"
            },
            {
              "label": "VAST validator",
              "href": "/validate/",
              "description": "Paste XML for companion rule checks.",
              "source": "Tool"
            },
            {
              "label": "VAST tester",
              "href": "/tester/",
              "description": "Fetch a live tag and review companion assets.",
              "source": "Tool"
            },
            {
              "label": "A Companion with no width is not a 300x250",
              "href": "https://dev.to/aleksuix/a-companion-with-no-width-is-not-a-300x250-the-player-cannot-match-it-45h7",
              "description": "Slot matching, required=all, and the warning that does not block until you fail on warning.",
              "source": "DEV"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the companion XML",
          "paragraph": "Paste resolved XML into the validator. Fetch a live URL in the tester when you need to see which companions survived the chain.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        }
      ]
    },
    {
      "slug": "how-to-validate-vast-wrappers",
      "title": "How to Validate VAST Wrappers",
      "description": "Wrapper validation starts with VASTAdTagURI, chain depth, and the last hop. Catch missing redirects in XML, then inspect live hops when the player prints 303 or 302.",
      "publishedAt": "2026-08-29",
      "updatedAt": "2026-08-29",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Wrapper chains",
      "tags": [
        "Wrappers",
        "VAST",
        "Inspector",
        "How-to"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "Wrapper validation in VAST starts with the XML. If VASTAdTagURI is missing or empty, the chain is a dead end. If the chain is too deep, players fire 302. If wrappers resolve but the last hop is empty, players fire 303.",
            "vastlint can catch missing VASTAdTagURI and wrapper depth in pasted XML. Live hops need the inspector, which is the wrapper chain tester. Validate the wrapper document, then inspect the URL."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What wrappers are doing in the tag",
          "paragraphs": [
            "A wrapper is not the ad. It is a redirect that must hand the player a next VAST URL. That URL is VASTAdTagURI. Each hop can add impressions, tracking, and companions. The player stops when it reaches InLine or hits a platform depth limit.",
            "FollowAdditionalWrappers, allowMultipleAds, and followCompanions change what later hops may add. Mis-set flags look like missing creatives. They are wrapper policy, not a broken MediaFile."
          ]
        },
        {
          "type": "list",
          "heading": "What wrapper XML validation can catch before playback",
          "items": [
            "Wrapper without VASTAdTagURI.",
            "Empty or non-HTTPS redirect target.",
            "Chain depth that already exceeds typical player limits (often 3 to 5 hops).",
            "Ad that is neither InLine nor Wrapper.",
            "Wrapper ClickThrough that some VAST 4.0/4.1 players ignore."
          ]
        },
        {
          "type": "code",
          "heading": "A wrapper that should pass",
          "language": "xml",
          "code": "<VAST version=\"4.2\">\n  <Ad>\n    <Wrapper>\n      <AdSystem>Example Ad Server</AdSystem>\n      <VASTAdTagURI><![CDATA[https://ads.example.com/next-vast.xml]]></VASTAdTagURI>\n      <Impression><![CDATA[https://tracker.example.com/wrapper-imp]]></Impression>\n      <Creatives />\n    </Wrapper>\n  </Ad>\n</VAST>"
        },
        {
          "type": "code",
          "heading": "A wrapper that looks valid but should be flagged",
          "language": "xml",
          "code": "<VAST version=\"4.2\">\n  <Ad>\n    <Wrapper>\n      <AdSystem>Example Ad Server</AdSystem>\n      <Impression><![CDATA[https://tracker.example.com/wrapper-imp]]></Impression>\n    </Wrapper>\n  </Ad>\n</VAST>"
        },
        {
          "type": "list",
          "heading": "What the wrapper rule set should complain about",
          "items": [
            "VAST-2.0-wrapper-vastadtaguri because the redirect target is missing.",
            "VAST-2.0-wrapper-depth when the declared chain is already too long.",
            "VAST-2.0-ad-has-inline-or-wrapper when the Ad has neither.",
            "Player error 303 when hops succeed but the last response is empty VAST.",
            "Player error 302 when the player refuses another redirect."
          ]
        },
        {
          "type": "list",
          "heading": "Which channel to use",
          "items": [
            "The validator at vastlint.org/validate is the paste check for VASTAdTagURI and wrapper structure.",
            "The inspector at vastlint.org/inspect is the wrapper chain tester: each hop, each response, the hop that went empty.",
            "The tester at vastlint.org/tester is for the resolved InLine: media, tracking, companions.",
            "Error pages 303, 302, and 301 map the player code to the XML cause."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when wrapper XML should block launch",
          "language": "sh",
          "code": "vastlint check wrapper-example.xml --format json\n\nvastlint check wrapper-example.xml --fail-on-warning"
        },
        {
          "type": "paragraphs",
          "heading": "What wrapper XML validation cannot prove",
          "paragraphs": [
            "A wrapper with a well-formed VASTAdTagURI is necessary. It does not prove the next hop returns InLine, or that the CDN is up. No-fill 303 is often legitimate demand, not a tag bug.",
            "Validate the wrapper document, then inspect the live URL hop by hop. Do not treat a green XML paste as a green chain."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "VAST inspector",
              "href": "/inspect/",
              "description": "Wrapper chain tester: hop-by-hop fetch and validation.",
              "source": "Tool"
            },
            {
              "label": "Wrapper chains guide",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Depth limits, follow* attributes, latency.",
              "source": "Guides"
            },
            {
              "label": "Error 303",
              "href": "/docs/vast-error-codes/303/",
              "description": "No ads after wrappers. Empty last hop.",
              "source": "Docs"
            },
            {
              "label": "Missing VASTAdTagURI",
              "href": "/docs/missing-vastadtaguri/",
              "description": "Wrapper with no redirect target.",
              "source": "Docs"
            },
            {
              "label": "VAST validator",
              "href": "/validate/",
              "description": "Paste wrapper XML for spec checks.",
              "source": "Tool"
            },
            {
              "label": "A spec-valid video bid can still fill with empty VAST",
              "href": "https://rtblint.org/blog/video-bid-is-not-vast-proof/",
              "description": "OpenRTB can pass while the VAST inside is an empty wrapper, leftover SIMID, or a companion with no size.",
              "source": "RTBlint"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Inspect the live wrapper chain",
          "paragraph": "Paste the live VAST URL into the inspector. Use the validator when you already have a single hop of XML.",
          "href": "/inspect/",
          "label": "Open the VAST inspector"
        }
      ]
    },
    {
      "slug": "ctv-vast-readiness-four-gates",
      "title": "Spec-Valid VAST Passes One Gate. CTV Ad Ops Now Runs Four Before Launch.",
      "description": "Workshop polling on a nearly $30 billion CTV market put live-event forecasting and liveness signals ahead of creative approval. The readiness bar is structurally valid, environment-compatible, successfully executed, and observable, not XSD alone.",
      "publishedAt": "2026-08-29",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Ad ops",
      "tags": [
        "CTV",
        "VAST",
        "Ad ops",
        "Live streaming",
        "CTV Ad Portfolio"
      ],
      "published": true,
      "featured": true,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "Connected TV is no longer an experiment channel. U.S. digital video advertising is projected to reach $81.9 billion in 2026, up 11% year over year, and CTV alone is projected at approximately $29.3 billion. Buyers still want television attention with digital accountability, but the operating question has shifted: not whether CTV can attract spend, but whether delivery, measurement, and creative can run repeatably at that scale.",
            "At IAB Tech Lab's August 2026 Ad Ops Workshop for Advanced TV, supply-chain leaders walked the full path from inventory definition through creative approval, live delivery, and outcome measurement. The through-line was a harder readiness test than most trafficking teams run today. A VAST tag can comply with the specification and still fail in its intended environment. Workshop attendees formalized what that means in practice."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What \"ready\" actually measures",
          "paragraphs": [
            "The workshop did not treat validation as a single XSD pass. For ad ops, readiness is four conditions chained together: structurally valid, environment-compatible, successfully executed, and observable.",
            "Structurally valid is the part most teams already know: XML that matches the declared VAST version, required children present, HTTPS where the spec expects it. Environment-compatible means the creative matches the player, device class, and format path you sold. Pause and overlay inventory in the CTV Ad Portfolio travels on VAST NonLinear Ads tied to OpenRTB video objects; menu and home-screen inventory uses the Native API with video creative embedded as VAST inside the native payload. A tag that parses on a laptop but declares the wrong linearity or omits a NonLinear fallback an unaware player can render fails here even when the schema is clean.",
            "Successfully executed is playback under real latency and wrapper depth, not a curl from a desk. Observable is whether tracking, verification, and identity survive that path so reconciliation and frequency controls work downstream. Validation should begin during creative intake and partner QA, the workshop argued, not after a delivery failure or makegood."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Portfolio formats are moving from pilots to roadmaps",
          "paragraphs": [
            "The session opened on finalized CTV Ad Portfolio signaling for Pause, Screensaver, Overlay, Squeezeback, In-Scene, and Menu or Home Screen ads. Many formats already existed as publisher products; the new work makes them recognizable and transactable across buyers, sellers, and platforms.",
            "Audience polling at the workshop was small and directional, not a broad industry benchmark, but the pattern was clear. Of attendees who responded, 58% said their organizations already support at least one portfolio format. Another 33% planned to add support to their roadmap or begin evaluating technical requirements. No respondents expected to monitor adoption without acting.",
            "When asked which format they were most likely to support first, 54% selected Pause Ads, followed by Menu or Home Screen Ads at 15%. That ordering matters for VAST QA because pause inventory now carries duration, MediaFiles, optional SIMID interactivity, and quartile tracking on hardware that has never rendered a portfolio extension. Silent failure is common: an extension a player does not recognize is not a parse error and may not fire an Error ping if no native NonLinear fallback was included."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Creative approval is moving off the bidstream",
          "paragraphs": [
            "Standardizing inventory does not help if creative is still awaiting approval when a campaign should start. The Ad Management API offers a non-bidstream path to submit creative to an exchange before it enters the auction, returning structured approval status and actionable rejection reasons instead of a stalled delivery ticket.",
            "When asked what would accelerate adoption, publisher-level approval support led at 27%. More participating counterparties and consistent rejection reasons each received 18%, reinforcing that adoption depends on network participation as much as feature availability.",
            "On validation tooling, 36% of respondents were most likely to add structured VAST checks to creative intake or pre-launch QA. Another 27% selected automated workflow integration, and 27% planned to evaluate before changing their workflow. No one chose to continue with existing tools unchanged. The implied workflow is upstream: catch environment mismatch and broken media before the tag enters a live pod or SSAI stitch."
          ]
        },
        {
          "type": "list",
          "heading": "Live events reorder the sequence",
          "items": [
            "93% of buyers in IAB's 2026 spend research consider live content more valuable than other digital video, yet one-third still question whether the premium produces sufficient return.",
            "Live delivery compresses forecasting, traffic planning, creative preparation, decisioning, and infrastructure scaling into a short window: overtime, audience spikes, or unscheduled breaks create supply without time for manual intervention.",
            "When asked which Live Event Ad Playbook capability they would implement first, 46% chose structured event and inventory forecasting, 38% selected standardized live-inventory signals, and creative readiness and approval checks followed at 15%.",
            "The suggested sequence: establish a shared view of what is scheduled, identify live inventory consistently, then coordinate the systems that deliver it. Creative QA comes after the inventory story is trustworthy."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Agents need bounded readiness, not a permanent flag",
          "paragraphs": [
            "A separate workshop thread on creative readiness for agentic workflows drew a boundary around automation. A creative may be policy-approved but incompatible with a destination. It may be technically valid but not cached for a live event. Readiness therefore needs evidence, scope, authority, version, and expiration, not a single permanent approved bit.",
            "Half of respondents supported allowing an agent to apply technical fixes with human approval. Another 21% would allow approved classes of fixes automatically, and 21% preferred agents to recommend corrections. No one supported allowing an agent to modify creative content within a defined policy. The room was more comfortable automating preparation than creative decision-making.",
            "For VAST teams, that maps cleanly onto linting and structural fixes (HTTPS normalization, missing Duration, wrapper depth) versus changing the creative narrative. Machine-readable policies, bounded permissions, actionable errors, and audit trails expand automation without surrendering control."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Identity and outcomes still wait on coordination",
          "paragraphs": [
            "Mature operations also require connecting what ran with what happened afterward. On ECAPI, the Events and Conversion API framework for server-to-server marketing events, 45% of workshop respondents selected access to advertiser event data as the biggest barrier, not technical integration.",
            "On UniversalAdID and the Ad Creative ID Framework, buyer or advertiser demand and better frequency and separation controls each led at 33%, with publisher or marketplace requirements at 17%. Creative identity has to solve visible business problems before trafficking will enforce it in every tag."
          ]
        },
        {
          "type": "quote",
          "quote": "Publishing a specification is not the finish line. A standard creates value when it becomes part of real products and workflows, and when partners can rely on one another to interpret it consistently.",
          "attribution": "IAB Tech Lab, CTV Ad Ops workshop recap"
        },
        {
          "type": "list",
          "heading": "A pre-launch checklist aligned to the four gates",
          "items": [
            "Structurally valid: run spec checks on the declared VAST version, portfolio extensions, and HTTPS across media, tracking, and verification URLs.",
            "Environment-compatible: confirm NonLinear versus Linear expectations, portfolio format path, and a native NonLinear fallback where extensions may be ignored.",
            "Successfully executed: resolve the full wrapper chain under CTV latency budgets; validate final MediaFiles and mezzanine on the device classes in the line item.",
            "Observable: verify AdVerifications, tracking events, and UniversalAdId survive SSAI or wrapper hops so measurement and frequency controls match the buy.",
            "For live inventory: confirm forecasting and liveness signals are in place before you traffic the creative package."
          ]
        },
        {
          "type": "cta",
          "heading": "Run the structural gate at intake",
          "paragraph": "Paste portfolio or live-event VAST at creative intake before it enters trafficking. Fix structural and environment mismatches while rejection is cheap, not after a makegood.",
          "href": "/validate/",
          "label": "Validate VAST XML"
        },
        {
          "type": "resources",
          "heading": "Sources",
          "items": [
            {
              "label": "CTV Ad Ops Grows Up: From Promising Capabilities to Repeatable Operations",
              "href": "https://iabtechlab.com/ctv-ad-ops-grows-upfrom-promising-capabilities-to-repeatable-operations/",
              "description": "Aug 2026 workshop recap: four-part readiness bar, portfolio adoption polls, Ad Management API, live-event LEAP priorities, agentic readiness boundaries.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB 2026 Digital Video Ad Spend and Strategy Report",
              "href": "https://www.iab.com/insights/2026-video-ad-spend-strategy/",
              "description": "$81.9B U.S. digital video and ~$29.3B CTV projections; live content value versus ROI skepticism cited in the workshop post.",
              "source": "IAB"
            },
            {
              "label": "CTV Ad Portfolio signaling guidance",
              "href": "https://iabtechlab.com/standards/ctv-ad-portfolio/",
              "description": "NonLinear VAST versus Native-with-embedded-VAST delivery paths for the six portfolio formats.",
              "source": "IAB Tech Lab"
            }
          ]
        }
      ]
    },
    {
      "slug": "vast-tester-is-not-the-inspector",
      "title": "A Live VAST URL Is Not a Paste. The Tester and the Inspector Do Different Jobs.",
      "description": "Paste XML checks the document you already have. A live tag URL is a fetch, a wrapper chain, and a different file on a different host. The tester previews that hop. The inspector walks every hop. Using the validator for both jobs is how the inline stays untested.",
      "publishedAt": "2026-08-26",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Tooling",
      "tags": [
        "VAST",
        "QA",
        "Wrappers",
        "CTV",
        "Ad ops"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "Three pages on vastlint.org get used as if they were one button. Validate pastes XML you already hold. The tester fetches a live tag URL, follows wrappers far enough to preview creative, tracking, and click URLs. The inspector walks the chain hop by hop and shows where it breaks. They share a rule catalog. They do not share a job.",
            "The mix-up is operational, not branding. A trafficker copies a VASTAdTagURI out of GAM, pastes it into a box labeled validator, and gets a green wrapper. The inline on hop three still has no Duration, an HTTP MediaFile, or an InteractiveCreativeFile the player will never load. The document they pasted was never the document that plays."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What each page actually measures",
          "paragraphs": [
            "Validate is a document check. You paste or upload XML. The catalog runs on that tree. No network. No player. No second host. If the file in git is the file that will play, this is the right tool. CI belongs here.",
            "The tester is a live-tag check. You paste a URL. It fetches, resolves wrappers enough to show you the creative, the tracking pixels, and the click-through. That is the path when a partner says the tag works in our tool and you only have their URL.",
            "The inspector is a chain check. Same live URL, different output: every hop, every redirect, wrapper depth, and the InLine at the bottom. When fill dies as VAST error 302 or 303, this is the page. Validate will not tell you hop four 404s. The tester will show a preview if something eventually plays. The inspector names the hop that did not."
          ]
        },
        {
          "type": "code",
          "heading": "The URL you start with is often only hop one",
          "language": "xml",
          "code": "<VAST version=\"4.2\">\n  <Ad>\n    <Wrapper>\n      <VASTAdTagURI>https://ssp.example/vast?id=abc</VASTAdTagURI>\n      <Impression>https://adserver.example/imp</Impression>\n    </Wrapper>\n  </Ad>\n</VAST>"
        },
        {
          "type": "paragraphs",
          "heading": "Why hop one looks fine",
          "paragraphs": [
            "A Wrapper is allowed to be thin. Impression pixels on the wrapper are real. Duration is not on the wrapper. MediaFiles are not on the wrapper. SIMID lives on the inline InteractiveCreativeFile. OMID AdVerifications often appear only after the last redirect. Checking the wrapper against linear-creative rules is a category error.",
            "IAB recommends keeping wrapper depth bounded. The number is a chain property. You cannot observe it on a pasted wrapper document that never fetched the next URI. That is why a green paste and a dead device are compatible."
          ]
        },
        {
          "type": "list",
          "heading": "A working split",
          "items": [
            "File in the repo, CI, or a trafficking export you already unwrapped: validate.",
            "Partner sent a URL, you need to see creative, clicks, and trackers: tester.",
            "VAST 301, 302, 303, timeout, or allowMultipleAds dying mid-chain: inspector.",
            "Do not substitute /ad-tag-tester/ for either. That path is an alias, not a third job."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Run the live hop",
          "paragraphs": [
            "vastlint is independent of IAB Tech Lab. The pages cite the VAST spec because that is where Duration, wrappers, and error codes live. A green wrapper paste is not a green session. Fetch the URL. Then walk the hops."
          ]
        },
        {
          "type": "cta",
          "heading": "Test the live tag",
          "paragraph": "Paste the VAST URL the player will call. Preview creative, tracking, and clicks on the tester. If the chain is the question, open the same URL on the inspector and read every hop.",
          "href": "/tester/",
          "label": "Open the VAST tag tester"
        },
        {
          "type": "resources",
          "heading": "Next",
          "items": [
            {
              "label": "VAST inspector",
              "href": "/inspect/",
              "description": "Hop-by-hop wrapper chain. Depth, redirects, InLine handoff."
            },
            {
              "label": "Validate VAST XML",
              "href": "/validate/",
              "description": "Paste a document you already have. No fetch."
            },
            {
              "label": "How to validate VAST XML",
              "href": "/docs/validate-vast-xml/",
              "description": "Which tool for which artifact."
            }
          ]
        }
      ]
    },
    {
      "slug": "the-inline-is-a-different-host",
      "title": "The Wrapper You QA Is Not the Creative That Plays. The Inline Lives on Another Host.",
      "description": "A VAST wrapper can be spec-valid and still terminate on a different CDN, a different AdSystem, and a different MediaFile than the URL you tested. The session fails on the inline. Hop-one QA never sees that file.",
      "publishedAt": "2026-08-26",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Wrappers",
      "tags": [
        "VAST",
        "Wrappers",
        "SSAI",
        "CTV",
        "Ad ops"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "Most VAST tags in the wild are not InLine documents. They are a URI that returns a Wrapper, which returns another URI, which eventually returns the creative. The player follows that chain at playback. Your QA laptop often does not.",
            "The failure mode is stable. Someone validates the first response, files a green screenshot, and ships. The device then requests hop three, gets an HTTP MediaFile on HTTPS inventory, a missing Duration, or a 404 mezzanine, and reports a VAST error the trafficking ticket cannot reproduce from the original URL."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the wrapper is allowed to omit",
          "paragraphs": [
            "A Wrapper carries VASTAdTagURI, optional Impression and tracking, and flags such as allowMultipleAds and fallbackOnNoAd. It does not have to carry Linear Duration. It does not have to carry MediaFiles. UniversalAdId, AdVerifications, and SIMID InteractiveCreativeFile typically sit on the InLine. Treating the wrapper as a complete creative is reading a cover letter as the contract.",
            "allowMultipleAds is a chain property. A wrapper that sets it false can kill a pod that looked fine on hop one. You will not see that in a paste of hop one unless you also fetch what it points at."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The host changes",
          "paragraphs": [
            "Hop one is often the ad server you traffic. Hop two is an SSP wrapper. Hop three is a CDN or a creative host you do not control. HTTPS on hop one does not imply HTTPS on hop three. Geo, user-agent, and app bundle on the device request are not the same as curl from your desk. A 200 in the office and a 403 on Fire TV are both real.",
            "SSAI stitchers add another hop: they fetch the chain, transcode, and emit a new document. Validating the pre-stitch wrapper and never the stitched output is how a living-room player sees a different MediaFile than the one in the ticket."
          ]
        },
        {
          "type": "list",
          "heading": "What to do before you call it QA",
          "items": [
            "Follow VASTAdTagURI until you have an InLine or you hit a fetch error. Count the hops.",
            "Check Duration, MediaFiles, mezzanine, and AdVerifications on the InLine, not on the first wrapper.",
            "Use the inspector when the question is which hop died. Use the tester when you need to see whether anything playable came back.",
            "Re-run the same URL from a CTV user-agent if the buy is CTV. Desk curl is not a Roku."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Walk the chain",
          "paragraphs": [
            "vastlint is independent of IAB Tech Lab and of the SSPs that mint these wrappers. The inspector fetches each hop and runs the same spec-derived catalog on every response. A green hop one is a statement about hop one."
          ]
        },
        {
          "type": "cta",
          "heading": "Inspect the wrapper chain",
          "paragraph": "Paste the live VAST URL. Read every hop, not only the first document. If you need a preview of what came back, use the tester on the same URL.",
          "href": "/inspect/",
          "label": "Open the VAST inspector"
        },
        {
          "type": "resources",
          "heading": "Next",
          "items": [
            {
              "label": "VAST tag tester",
              "href": "/tester/",
              "description": "Live URL, creative preview, tracking, click URLs."
            },
            {
              "label": "Wrapper depth",
              "href": "/docs/wrapper-depth-exceeded/",
              "description": "When the chain itself is the error."
            },
            {
              "label": "Missing VASTAdTagURI",
              "href": "/docs/missing-vastadtaguri/",
              "description": "A wrapper that cannot name the next hop."
            }
          ]
        }
      ]
    },
    {
      "slug": "acr-hdmi-measurement-without-vast",
      "title": "CTV measurement can run with no VAST tag. ACR still fingerprints HDMI when the set is a dumb display.",
      "description": "Samsung and LG automatic content recognition peaked on linear TV and HDMI in a 2024 living-room audit, including when a laptop or console used the set as a monitor. A green VAST tag does not prove the session was only measured by the creative.",
      "publishedAt": "2026-08-21",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Measurement",
      "tags": [
        "CTV",
        "ACR",
        "Measurement",
        "HDMI",
        "Smart TV"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "Connected TV QA is built around the tag. Resolve the wrappers, confirm a MediaFile, watch impression and quartile beacons. That workflow measures the creative path. It does not measure the operating system. Automatic content recognition sits in the TV firmware, hashes what is on the panel, and sends that fingerprint to a platform endpoint. No VAST document has to exist for that hop to fire.",
            "An IMC 2024 living-room audit ran that check on Samsung and LG sets in the UK and the US, two platforms the authors cite at about 23 percent and 18 percent market share. They compared linear antenna TV, the manufacturer's FAST app, third-party OTT apps, HDMI from a laptop or console, screen casting, and an idle homepage. The result that matters to anyone shipping video ads is not a fraud score. It is that the loudest ACR traffic was linear TV and HDMI, including when the set was a dumb external display."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the metric actually measures",
          "paragraphs": [
            "The audit is black-box network traffic between the TV and known ACR domains. It does not decrypt payloads. It does not prove which programme was identified. It does prove when the ACR client was talking. Highest volume was linear and HDMI. Other scenarios were much quieter; peaks dropped by up to 12 times, which the authors read as the client often not sending fingerprints. Third-party OTT apps such as Netflix and YouTube did not produce the ACR traffic that linear and HDMI did.",
            "LG's documentation says the client captures frames every 10 milliseconds. Observed network traffic was about every 15 seconds, which they treat as batching. Samsung talked to several of its own ACR hosts; LG talked to a single Alphonso domain that rotates a numeric label. UK hosts used EU in the name. US hosts used US, and those IPs geolocated in the United States.",
            "This is second-party measurement by the platform, not a tracker inside the creative. It is also not the hidden-webview IVT pattern, where a concealed browser forges attention metrics. ACR is the TV looking at its own framebuffer. A valid VAST impression and an ACR match can describe different objects: the ad that played, versus whatever was on the glass, including a game or a laptop window."
          ]
        },
        {
          "type": "quote",
          "quote": "Linear TV and HDMI produced the most ACR traffic. A clean VAST tag never sees that hop.",
          "attribution": "delivery triage note"
        },
        {
          "type": "paragraphs",
          "heading": "HDMI, FAST, and the two countries",
          "paragraphs": [
            "HDMI is the case buyers forget. A console or a laptop on the HDMI input still generated ACR in the audit. The user is not in a publisher app. There is no SSAI stitcher and no VAST wrapper. The panel is still a Samsung or LG, and the firmware still samples the screen. If your brand-safety or incremental-reach story assumes measurement only happens when an ad tag plays, HDMI passthrough is outside that story and still inside the platform's graph.",
            "FAST is not one behavior. In the UK, manufacturer FAST apps (Samsung TV+, LG Channels) sat with the quieter scenarios. In the US, those same apps produced ACR traffic comparable to linear. The paper's working explanation is different content agreements, not a different TV. Login status did not matter in either country: logged-in and logged-out traces looked the same. Turning off viewing information services stopped all traffic to the ACR domains they had identified. No new ACR hosts appeared after that opt-out.",
            "HbbTV overlays on broadcast are a cousin, not this mechanism. They are still not a VAST tag. Do not fold them into ACR, and do not fold ACR into a pixel-fraud post."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Two pipes, one living room",
          "paragraphs": [
            "The creative pipe is VAST, VMAP, SSAI, OMID, impression and quartile URLs. vastlint reads that pipe. The platform pipe is ACR: framebuffer, fingerprint, vendor endpoint, audience segment on the TV OS ad system. Buyers who reconcile complete rates against Samsung or LG ACR audiences as if they were the same impression will argue with both vendors and still be looking at two clocks.",
            "Pod and stitch failures hide in the creative pipe. HDMI and linear ACR hide in the platform pipe. A tag that 403s on Fire TV never reaches a quartile; ACR can still have hashed the programme that ran in that hour. A tag that plays cleanly on a phone app in the same open CTV line item never touches the Samsung ACR client in the living room. Open programmatic CTV already splits spend across TV OS and mobile. ACR is an extra split on the TV OS half: tagged playback versus screen hashing."
          ]
        },
        {
          "type": "list",
          "heading": "What to do",
          "items": [
            "Treat platform ACR as a measurement surface with its own opt-out, geography, and input path. Do not file it under VAST QA.",
            "When the buy includes Samsung or LG large screens, assume HDMI and linear can be hashed even if your tag never loaded.",
            "Do not copy a UK FAST assumption onto a US FAST line item. The audit saw ACR on US manufacturer FAST at linear-like volume.",
            "Account login is not the ACR switch in this audit. Viewing information services off was.",
            "Split reporting: tag-based completes versus platform ACR audiences. If they move together, that is a coincidence until proven.",
            "Still validate the trafficked VAST. A broken MediaFile is a different loss. The linter catching it does not census ACR."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The tag still has to play",
          "paragraphs": [
            "Paste production tags into the validator before they hit the stitcher or the exchange. vastlint checks structural consistency, MediaFile and mezzanine presence, HTTPS, wrapper depth, and spec-derived rules from VAST 2.0 through 4.4. It does not detect ACR, fraud, bots, or whether a TV hashed the programme. Independent of Samsung, LG, and of the IMC paper. A green tag means the creative document is consistent. It does not mean the living room was unmeasured."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the creative pipe",
          "paragraph": "Run VAST tags through specification-derived rules so MediaFile, tracker, and wrapper consistency are visible. ACR on HDMI is a different hop; it will not appear in this paste.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources",
          "items": [
            {
              "label": "Watching TV with the Second-Party: A First Look at Automatic Content Recognition Tracking in Smart TVs",
              "href": "https://arxiv.org/abs/2409.06203",
              "description": "Anselmi, Vekaria, D'Souza, Callejo, Mandalari, Shafiq. IMC 2024. Black-box ACR traffic on Samsung and LG in the UK and US: linear and HDMI peaks, 12 times quieter other scenarios, 10 ms capture versus 15 s batching on LG, opt-out stops ACR domains, login does not, US FAST unlike UK.",
              "source": "arXiv:2409.06203"
            },
            {
              "label": "IMC 2024 ACM record",
              "href": "https://doi.org/10.1145/3646547.3689013",
              "description": "Published proceedings version of the same measurement.",
              "source": "ACM"
            },
            {
              "label": "Audit code and data",
              "href": "https://github.com/SafeNetIoT/ACR",
              "description": "Authors' reproduction package for the ACR traffic experiments.",
              "source": "GitHub"
            }
          ]
        }
      ]
    },
    {
      "slug": "open-programmatic-ctv-two-playback-surfaces",
      "title": "Open Programmatic CTV Runs on TV Sets and Phone Apps in Nearly Equal Measure. One VAST Tag Still Has to Play on Both.",
      "description": "Pixalate's June 2026 report puts 57% of U.S. open programmatic CTV spend on large-screen devices and 43% on phones and tablets. Buyers who QA a tag on one surface are blind to the playback failures waiting on the other half of the same inventory class.",
      "publishedAt": "2026-08-20",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "CTV delivery",
      "tags": [
        "CTV",
        "VAST",
        "Programmatic",
        "SSAI",
        "Video measurement"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "MediaPost reported in August on a June 2026 Pixalate study of U.S. open programmatic connected TV: large-screen devices, smart TV sets, account for 57% of that spend, and 43% runs on small-screen devices, phones, tablets, and other iOS and Android surfaces. The headline is a device split, not a fraud score or a fill-rate chart. It still matters to anyone shipping VAST, because open exchange CTV is not one player environment. It is two, traded under one label.",
            "The same article cites Pixalate on scope: open programmatic streaming buys, public RTB auctions open to any demand-side platform buyer, are roughly 18% to 19% of overall U.S. CTV ad spend, about $6 billion to $7.5 billion against industry estimates of $33.1 billion to $40.4 billion total. That is a minority of CTV dollars, but it is the slice where a generic tag meets the widest device mix without a curated deal wrapper to narrow the path."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the metric actually measures",
          "paragraphs": [
            "Pixalate's figures describe where open programmatic CTV money lands by screen class and, within large screens, by TV operating system. On large screens, Amazon Fire TV accounts for 30% of open TV programmatic ad spend, Roku for 18%, Samsung Smart TV for 5%, and Apple TV for 4%. Warner Bros. Discovery properties show up heavily in network-level open deal concentration: Food Network at 34%, CNN at 20%, Investigation Discovery at 7%, TLC at 4%, and Animal Planet at 2% among the top ten by spend.",
            "Genre and daypart skew differently by surface. Reality-unscripted and news programming pull in 41% and 23% of open programmatic ad deals respectively. New programming dominates small-screen spend at 64%. Morning hours, 6 a.m. to noon, hold a 30% share of large-screen open programmatic spend; overnight, 11 p.m. to 6 a.m., holds a 31% share on small screens.",
            "None of that is a statement about whether a given impression rendered. It is a spend and deal-composition map. The population is U.S. open programmatic CTV as Pixalate measured it in June 2026, not all CTV (private marketplace and programmatic guaranteed are excluded from the open slice, though MediaPost notes that programmatic transactions overall, including PMP and PG, represent around 84% to 88% of all U.S. CTV ad spending). The takeaway for delivery teams is simpler: when you buy open CTV programmatic, you are not buying a living-room-only path. You are buying a portfolio that is almost evenly split between TV OS players and mobile apps."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why one tag fails on two surfaces",
          "paragraphs": [
            "Operations teams often treat CTV QA as a single checklist: resolve the wrapper chain, confirm HTTPS, spot-check one MP4. That workflow assumes one dominant player class. The 57/43 split breaks the assumption. A tag that plays in a mobile app WebView or native player may still die on a Fire TV or Roku with VAST error 403, could not find a MediaFile supported by this player, because the codec, container, bitrate cap, or absence of a mezzanine file matters on the TV side and not on the phone side.",
            "The IAB VAST CTV addendum exists because web-sized renditions are not interchangeable with living-room playback. Mezzanine files, higher-resolution masters for SSAI transcoding, and explicit MediaFile typing are written for large-screen delivery paths. Mobile inventory in the same open bucket may accept a lighter progressive MP4 and never touch a stitcher. SSAI on FAST and broadcaster apps on the large-screen half expects something to transcode; a single 800 kbps web rendition that clears mobile QA gives the stitcher nothing useful and the TV player nothing better to select.",
            "Platform share compounds the problem. Fire at 30% and Roku at 18% of large-screen open spend means the TV half of your open CTV line item is concentrated on two player stacks with different manifest, codec, and interactivity histories. A tag tested only on Samsung's player or only in an Android tablet app does not prove compatibility on either dominant TV OS. Genre skew adds a planning mistake: reality and news lean large screen; new programming leans small. A creative cut for one genre mix can under-serve the other if MediaFiles are not duplicated or if mezzanine coverage is missing where SSAI sits in the path."
          ]
        },
        {
          "type": "quote",
          "quote": "Open CTV is traded as one category and delivered as two player regimes. The spend data says so in almost equal percentages.",
          "attribution": "delivery triage note"
        },
        {
          "type": "paragraphs",
          "heading": "The mechanism in the document",
          "paragraphs": [
            "The failure shows up in the VAST payload, not in the bid request headline. Wrapper depth and timeout behavior hit both surfaces, but MediaFile selection is where the split bites. A Linear creative with one progressive MP4 may validate in a browser-based tool and still omit Mezzanine, which vastlint flags at info severity with the note that ad-stitching servers may reject the tag in CTV and SSAI contexts. Interactive assumptions diverge too: SIMID and native controls on TV, lighter non-linear or static fallbacks on mobile, and legacy VPAID dependencies that TV platforms dropped years ago but mobile wrappers still tolerate.",
            "Measurement follows playback. Quartile and complete events only mean something if the player chose a MediaFile and started decoding. An impression pixel that fires on ad load while the TV player rejects every rendition is the same silent loss as a stitch timeout, except the campaign report shows delivery until someone reconciles player logs. Daypart skew makes that harder to catch in QA: morning-heavy large-screen spend and overnight-heavy mobile spend mean a tag checked at noon in a desktop inspector never sees the traffic mix that will actually run."
          ]
        },
        {
          "type": "list",
          "heading": "Checks worth running before launch",
          "items": [
            "Resolve the full wrapper chain on both a TV OS test device and a mobile app path, not only in a desktop VAST inspector.",
            "Confirm at least one TV-safe MP4 rendition plus mezzanine or stitcher-approved master when the supply path includes SSAI or broadcaster FAST apps.",
            "Match MediaFile type, width, height, and bitrate claims to the platforms in the Pixalate large-screen mix you actually buy (Fire and Roku first).",
            "Require HTTPS on every tracker and media URL; mixed content blocks TV players more aggressively than mobile WebViews.",
            "Split reporting by app surface where your ad server allows it; aggregate CTV line items hide the 403 rate on the TV half.",
            "Re-run validation on the trafficked tag after any transcode or dynamic creative step that replaces MediaFiles downstream."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What to do",
          "paragraphs": [
            "Treat open programmatic CTV as a dual-environment launch. The buy-side label says CTV; the spend map says 57% TV OS and 43% mobile. Your QA plan should mirror that ratio instead of assuming the living room is the whole story.",
            "Paste production tags into the validator before they reach the exchange or the stitcher. vastlint checks structural consistency, MediaFile and mezzanine presence, HTTPS, wrapper depth, and spec-derived rules from VAST 2.0 through 4.4. It does not detect fraud, bots, or whether an impression was valid. It catches malformed or inconsistent payloads that fail on one surface while appearing to pass on another."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the tag against both playback regimes",
          "paragraph": "Run VAST tags through specification-derived rules so MediaFile, mezzanine, and tracker consistency are visible before the tag hits open CTV paths split across TV and mobile.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources",
          "items": [
            {
              "label": "Study Finds More Than Half Of CTV Programmatic Served On Large Screens",
              "href": "https://www.mediapost.com/publications/article/416951/study-finds-more-than-half-of-ctv-programmatic-ser.html",
              "description": "MediaPost coverage of Pixalate's June 2026 U.S. open programmatic CTV spend split (57% large screen, 43% small screen), platform shares, genre and daypart concentration, and open vs total CTV spend context.",
              "source": "MediaPost"
            },
            {
              "label": "VAST CTV Addendum 2024",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "IAB guidance on mezzanine files, high-resolution MediaFiles, and large-screen delivery expectations in VAST.",
              "source": "IAB Tech Lab"
            }
          ]
        }
      ]
    },
    {
      "slug": "hidden-webview-fraud-manipulates-attention-metrics",
      "title": "Hidden Webview Fraud Can Make Invalid Traffic Look More Valuable Than the Real Thing",
      "description": "IAS Threat Lab's August 2026 Papyrus report documents novel-reading apps that load concealed browser windows, automate clicks and scrolls, and produce roughly 25 times the click success rate, 4 times the eCPM, and 13 percent higher attention scores than clean traffic. Buyers optimizing on engagement metrics will bid up the worst supply unless measurement separates synthetic interaction from intent.",
      "publishedAt": "2026-08-16",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Measurement",
      "tags": [
        "IVT",
        "Attention",
        "Mobile fraud",
        "Viewability",
        "Video measurement"
      ],
      "published": true,
      "featured": false,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "On August 6, IAS Threat Lab published research on a mobile scheme it calls Papyrus: novel-reading apps that keep a legitimate interface on screen while hidden webviews load monetized destinations, register clicks from user taps routed into the background, and scroll pages on remote instruction. The traffic is not only invalid. In IAS analysis it looked more valuable than clean supply: nearly 25 times the click success rate, roughly 4 times the eCPM, and about 13 percent higher attention scores than non-Papyrus traffic. IAS estimates the operation may have generated close to $1 million per month in monetization impact at its peak, spanning more than 800 domains and nearly 8,000 unique host values.",
            "That inversion is the argument. Fraud that inflates the metrics buyers optimize on does not read as fraud in a dashboard. It reads as performance."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the metrics actually measure",
          "paragraphs": [
            "Click success rate, eCPM, and attention scores are downstream of events: page loads, pointer events, scroll depth, time in view. Papyrus separates the user-visible session (reading inside the app) from the monetized session (hidden webviews driven by BootNova command-and-control infrastructure). User taps on the reading UI can be passed into concealed webviews through click modules. Separate scroll modules inflate engagement on pages the user never saw.",
            "IAS is explicit that the scheme goes beyond hidden traffic generation and actively manipulates the metrics buyers rely on. A hidden page load alone creates invalid traffic. Hidden loads plus automated clicks and scrolling distort performance and attention-based evaluation, which pushes optimizers toward the fraudulent path because the signals look like high-intent inventory.",
            "The population behind the headline numbers is Papyrus-associated supply compared with non-Papyrus traffic in IAS observation. That is not all mobile fraud and not all defended campaigns. It is a named cluster IAS filtered after identification. The magnitude still matters: if synthetic interaction lifts attention 13 percent and eCPM 4x, any bidder using those signals as quality proxies will overweight the scheme until something breaks the feedback loop."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The mechanism",
          "paragraphs": [
            "Papyrus is built around long reading sessions. Utility apps open briefly; reading apps stay foreground for minutes. That window feeds background webview activity while the visible app looks normal. BootNova workers (WebViewOut) attach webviews behind the UI through native layering (CWebViewPlugin, cover views). Embedded and server-delivered JavaScript instruments pages, captures coordinates, mutes media, auto-clicks consent dialogs, and executes scroll logic the operator can change without shipping a new app build.",
            "Destinations skew toward gaming, blog, news-style, and generative-AI content domains: synthetic web properties built for monetization rather than audience. The operation is consumer-powered rather than classic datacenter bots: real devices, real installs, real taps, but the path from tap to ad engagement is hijacked.",
            "For video and display measurement, the lesson generalizes beyond mobile webviews. Any stack that treats interaction events as proof of value without binding them to the surface the user actually watched is vulnerable to the same inflation. SSAI with client-side tracking, wrapped VAST with third-party verification pixels, OMID sessions where the creative container is not the surface receiving input: each has a version of this gap if engagement beacons fire on synthetic activity."
          ]
        },
        {
          "type": "quote",
          "quote": "Invalid traffic that looks worse than clean traffic gets filtered. Invalid traffic that looks better gets bid up. The fraud operator's job is to cross that line.",
          "attribution": "measurement triage note"
        },
        {
          "type": "paragraphs",
          "heading": "What to do",
          "paragraphs": [
            "Pre-bid IVT lists and domain blocklists catch known Papyrus destinations after someone else labels them. They do not explain why attention and click metrics lied. Structural checks still earn their place:",
            "Separate volume metrics from quality metrics in reporting. If attention and CTR move while viewability and completion stay flat, you are measuring interaction inflation, not audience gain.",
            "Audit whether verification and viewability tags are bound to the player surface that received the user's attention, not a sibling webview or invisible layer.",
            "On the tag side, validate that tracking events in VAST and VPAID successors reference consistent creative IDs and that wrapper chains do not drop AdVerifications or OMID companions that would expose the mismatch.",
            "Paste production tags into the validator before launch. vastlint checks structural consistency (required elements, tracker URLs, verification placement). It does not detect fraud or bots. It catches malformed payloads that break measurement before you can even ask whether the clicks were real."
          ]
        },
        {
          "type": "list",
          "heading": "Signals worth splitting in QA",
          "items": [
            "High click or engagement rates with flat or falling viewability/completion on the same line item",
            "Large gaps between client-reported time and verification-reported time on the same impression ID",
            "Creative loads that succeed while OMID or verification companions fail schema or URL checks",
            "Wrapper chains where Impression fires but AdVerifications never appear in the parsed document"
          ]
        },
        {
          "type": "cta",
          "heading": "Validate tracking and verification before you trust the metrics",
          "paragraph": "Run VAST 2.0 through 4.4 tags against specification-derived rules so verification companions and impression events are present and consistent. Nothing is stored.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources",
          "items": [
            {
              "label": "Papyrus: Inside a Mobile Scheme Built to Fake Clicks, Scrolls, and Attention",
              "href": "https://integralads.com/insider/papyrus-inside-a-mobile-scheme-built-to-fake-clicks-scrolls-and-attention/",
              "description": "IAS Threat Lab research published August 6, 2026. Primary for click, eCPM, attention, domain, and revenue estimates.",
              "source": "Integral Ad Science"
            },
            {
              "label": "How to validate OMID in VAST tags",
              "href": "/docs/omid/",
              "description": "Verification placement and OMID companion checks.",
              "source": "vastlint"
            },
            {
              "label": "How to validate VAST trackers before launch",
              "href": "/blog/how-to-validate-vast-trackers-before-launch/",
              "description": "Tracker URL and event consistency before traffic hits measurement.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "vast-4-4-empty-wrapper-schema-valid",
      "title": "An Empty VAST Wrapper Is Schema-Valid in 4.4. It Was Not in 2.0.",
      "description": "One compositor change in the VAST 4.4 draft schema makes AdSystem, Impression and VASTAdTagURI optional on every wrapper, lets singular elements repeat, and drops element ordering. Here is the reproduction and what it means if you gate on the XSD.",
      "publishedAt": "2026-08-09",
      "author": "Alex Sekowski",
      "readingTime": "6 min read",
      "heroKicker": "Standards",
      "tags": [
        "VAST 4.4",
        "XSD",
        "Wrapper",
        "Validation",
        "IAB Tech Lab"
      ],
      "published": true,
      "featured": true,
      "body": [
        {
          "type": "paragraphs",
          "paragraphs": [
            "A VAST wrapper with no AdSystem, no VASTAdTagURI and no Impression validates against the VAST 4.4 draft schema. The same document has been invalid in every version from 2.0 through 4.2. It is one line of XSD, and it is almost certainly a side effect of the CTV Ad Portfolio restructure rather than a decision anyone made on purpose.",
            "I have filed it with IAB Tech Lab. This post is the working, because the reproduction is short enough that anyone can check it in about a minute."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The change",
          "paragraphs": [
            "In vast_4.4.xsd on master, both vastInLine_type and vastWrapper_type wrap their children in a single compositor: an xs:choice with minOccurs zero and maxOccurs unbounded.",
            "That looks harmless. It is the idiom people reach for when they want to say \"these children may appear in any order\". What it actually says is stronger than that. In XSD, the cardinality on the compositor governs the content model, and the minOccurs on the individual child elements only describes a single selection from the choice. Set the choice itself to zero-or-more and every constraint underneath it stops binding.",
            "So the children still declare minOccurs=\"1\". They are still, in effect, optional."
          ]
        },
        {
          "type": "code",
          "heading": "The compositor in question",
          "language": "xml",
          "code": "<!-- vast_4.4.xsd, vastWrapper_type and vastInLine_type -->\n<xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n  <xs:element name=\"AdSystem\"     type=\"vastAdSystem_type\"/>\n  <xs:element name=\"VASTAdTagURI\" type=\"vastURIElement_type\"/>\n  <xs:element name=\"Impression\"   type=\"vastImpression_type\"/>\n  <xs:element name=\"Creatives\"    type=\"vastCreatives_type\"/>\n  <!-- ... -->\n</xs:choice>"
        },
        {
          "type": "paragraphs",
          "heading": "Three consequences, not one",
          "paragraphs": [
            "The empty wrapper is the headline, but the compositor gives up three separate guarantees at once. Each is reproducible with xmllint against the published schema."
          ]
        },
        {
          "type": "list",
          "heading": "What now validates in 4.4",
          "items": [
            "Everything is optional. An empty <Wrapper/> validates. So does an empty <InLine/>, with no AdSystem, no AdTitle, no Impression and no Creatives.",
            "Everything repeats. maxOccurs=\"unbounded\" on the choice means any branch can be selected repeatedly, so three <AdSystem> elements in one InLine validate, even though AdSystem has always been exactly one.",
            "Order stops mattering. 4.2 used xs:sequence, so the order was fixed. A choice imposes none, so <Impression> before <AdSystem> validates."
          ]
        },
        {
          "type": "code",
          "heading": "Reproduction: all three validate against the published 4.4 schema",
          "language": "xml",
          "code": "<!-- 1. empty wrapper -->\n<VAST version=\"4.4\" xmlns=\"http://www.iab.com/VAST\">\n  <Ad id=\"a\"><Wrapper/></Ad>\n</VAST>\n\n<!-- 2. empty inline -->\n<VAST version=\"4.4\" xmlns=\"http://www.iab.com/VAST\">\n  <Ad id=\"a\"><InLine/></Ad>\n</VAST>\n\n<!-- 3. AdSystem three times -->\n<VAST version=\"4.4\" xmlns=\"http://www.iab.com/VAST\">\n  <Ad id=\"a\">\n    <InLine>\n      <AdSystem>A</AdSystem>\n      <AdSystem>B</AdSystem>\n      <AdSystem>C</AdSystem>\n    </InLine>\n  </Ad>\n</VAST>"
        },
        {
          "type": "code",
          "heading": "Check it yourself",
          "language": "bash",
          "code": "curl -sO https://raw.githubusercontent.com/InteractiveAdvertisingBureau/vast/master/vast_4.4.xsd\nxmllint --noout --schema vast_4.4.xsd empty-wrapper.xml\n# empty-wrapper.xml validates\n\n# the same shape against 4.2\nxmllint --noout --schema vast_4.2.xsd empty-wrapper-42.xml\n# Element 'Wrapper': Missing child element(s). Expected is ( AdSystem )."
        },
        {
          "type": "paragraphs",
          "heading": "What 4.2 actually required",
          "paragraphs": [
            "The contrast is worth being precise about, because the requirement did not live where you might expect. In 4.2, Wrapper_type extends AdDefinitionBase_type, and it is the base type that carries the required fields: AdSystem exactly once, Impression once or more. Wrapper_type then adds VASTAdTagURI as required and Creatives as optional. Both use xs:sequence.",
            "Impression in particular has been required on wrappers since 2.0. That is a twenty-year-old constraint, and the wrapper is exactly where it matters most, because a wrapper that fires no impression is a measurement hole in the middle of a chain."
          ]
        },
        {
          "type": "quote",
          "quote": "The schema went from expressing a content model to enumerating a vocabulary. Those are different jobs, and only one of them can gate anything.",
          "attribution": "vastlint standards note"
        },
        {
          "type": "paragraphs",
          "heading": "Why this matters if you gate on the XSD",
          "paragraphs": [
            "Plenty of teams treat the published XSD as an acceptance gate: ad server ingest checks, partner certification, QA rigs that reject anything the schema will not accept. For those, 4.4 currently passes wrapper responses that cannot deliver an ad and cannot record an impression.",
            "It also sharpens a question the working group was already asking in a separate thread about whether the XSD is meant to be usable as a validator at all. My answer has not changed: it is not, and it never fully was. The prose has always carried requirements the schema does not express, which is the reason a rule-based validator exists in the first place. But there is a difference between a schema that is incomplete and a schema that is more permissive than the version it supersedes.",
            "The practical takeaway for anyone shipping 4.4 today: do not loosen your own checks to match the draft. Keep requiring AdSystem, Impression and VASTAdTagURI on wrappers, because the prose still does and every prior version did."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The likely fix",
          "paragraphs": [
            "If the intent was order-independence, xs:all expresses that while keeping per-element cardinality intact. XSD 1.0 limits xs:all particles to maxOccurs one, so repeating elements like Impression need handling, but the required ones stay required.",
            "If the intent really was a fully open content model, then the schema and the prose have diverged and the annotation should say so out loud, so that nobody builds a gate on top of it expecting otherwise.",
            "Either way it is a small patch. I have offered to write it."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate a 4.4 tag against the prose, not just the schema",
          "paragraph": "vastlint checks VAST 2.0 through the 4.4 draft against rules derived from the specification text, not only the XSD, so a wrapper missing AdSystem or Impression still fails. Paste a tag and see. Nothing is stored.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "IAB Tech Lab VAST issue #58",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast/issues/58",
              "description": "The filed report, with the full reproduction and the 4.2 comparison table.",
              "source": "GitHub"
            },
            {
              "label": "vast_4.4.xsd on master",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast/blob/master/vast_4.4.xsd",
              "description": "The published draft schema. See vastInLine_type and vastWrapper_type.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST 4.4: what actually shipped",
              "href": "/docs/vast-4-4/",
              "description": "The full technical breakdown of the 4.4 draft, content model by content model.",
              "source": "vastlint"
            },
            {
              "label": "VAST 4.3 to 4.4 migration guide",
              "href": "/docs/vast-4-3-to-4-4/",
              "description": "Element-by-element changes with a migration checklist.",
              "source": "vastlint"
            },
            {
              "label": "Wrapper chains and where they break",
              "href": "/guides/vast-wrapper-chains/",
              "description": "What a wrapper has to carry for a chain to resolve and measure correctly.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "podcast-measurement-2-3-vast-audio-tracking",
      "title": "Podcast Measurement Counts Downloads. VAST Counts Events. Version 2.3 Sharpens One and Leaves the Other Alone.",
      "description": "The Podcast Technical Measurement Guidelines v2.3 went out for public comment on 21 July and close on 19 August. They stay anchored to server side log analysis because most podcast apps never confirm playback. An audio ad tag is a VAST document, VAST counts from the client, and the two systems have been describing the same ad break with different arithmetic since DAAST folded into VAST 4.1. The video podcast clause is where they finally collide.",
      "publishedAt": "2026-08-08",
      "author": "Alex Sekowski",
      "readingTime": "10 min read",
      "heroKicker": "Audio and podcast",
      "tags": [
        "Audio",
        "DAAST",
        "Measurement",
        "VAST tracking",
        "Standards"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Two counting systems, one ad break",
          "paragraphs": [
            "IAB Tech Lab released version 2.3 of the Podcast Technical Measurement Guidelines on 21 July 2026, with a 30 day public comment window that closes on 19 August. The guidelines are the reason podcast numbers from different measurement vendors can be compared at all, and the reason they exist in their current form is a constraint that has not moved in a decade: most podcast applications never tell the server whether anyone played the file. There is no client to ask. So the industry counts what the server can see, which is a request for bytes.",
            "That approach is stated plainly in the release. Server side log analysis remains the backbone, because client side playback confirmation is not available across the open RSS ecosystem. Everything downstream follows from it. A download is inferred from a byte threshold rather than observed from a player, duplicates are collapsed inside a time window, and known invalid traffic is filtered by list rather than by behaviour.",
            "Now look at the ad inside that episode. If it was trafficked programmatically, it arrived as a VAST document, because DAAST was deprecated and folded into VAST 4.1 in 2018 and audio has been a first class media type in VAST ever since. VAST counts differently. It counts an impression when a client fires a pixel, a start when playback begins, quartiles as the ad progresses, and a complete when it ends. Every one of those numbers comes from a player that decided to make an HTTP request.",
            "So the same ad break is measured twice, by two systems, with two definitions of the event, and nothing in either specification reconciles them. None of that is new. Version 2.3 adds a clause that makes the gap visible to people who had never had to think about it."
          ]
        },
        {
          "type": "list",
          "heading": "What version 2.3 actually changes",
          "items": [
            "Listener is replaced with podcast consumer throughout, which is terminology cleanup with a real consequence: the metric was never a person, and calling it one invited comparisons to audience measurement that the method does not support.",
            "New guidance on measuring streaming video podcasts, the distribution path where a real player exists and the download model stops describing what happened.",
            "Updated guidance for URL prefix measurement and for changes to RSS enclosure URLs, the two places where a measurement vendor sits between the feed and the file.",
            "Expanded invalid traffic considerations, which in a log based system means better heuristics rather than better observation.",
            "Clearer application of the different measurement window approaches, so two vendors counting the same episode over different windows can at least say so.",
            "Improved handling of duplicate downloads and platform driven anomalies, the category that covers prefetching, retries and aggressive caching by large podcast apps.",
            "Version 3.0 is already in development and is aimed at streaming video podcasts, targeted for 2027."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The video podcast clause is the one that touches VAST",
          "paragraphs": [
            "An audio podcast delivered over open RSS has no player to instrument, which is why the download model exists. A video podcast on a streaming platform, a CTV app or a video service has one. It has a player, a playback timeline, and in most cases an ad serving stack that already speaks VAST. The same show, the same episode, sometimes the same ad, is measured as a download on one path and as a VAST impression with quartiles on the other.",
            "That divergence has a predictable outcome for anyone selling across both. The numbers will not match, and the mismatch will be attributed to measurement methodology, because measurement methodology is the visible difference. Some of it genuinely is methodology. A download counted at a byte threshold and an impression counted at a fired pixel are different events and will never produce the same number, no matter how clean the plumbing.",
            "A meaningful share of the gap comes from somewhere else entirely: tags that do not fire. The download side cannot detect that, because the download was counted before the ad ever ran. The VAST side can, and can do it before the campaign starts rather than after the discrepancy report lands."
          ]
        },
        {
          "type": "code",
          "heading": "An audio ad as VAST sees it",
          "language": "xml",
          "code": "<VAST version=\"4.2\" xmlns=\"http://www.iab.com/VAST\">\n  <Ad id=\"audio-spot-1\">\n    <InLine>\n      <AdSystem version=\"1.0\">example-audio-adserver</AdSystem>\n      <AdTitle>30s host read replacement</AdTitle>\n      <AdServingId>c8d2-hostread-0031</AdServingId>\n      <Impression><![CDATA[https://track.example/imp?cb=[CACHEBUSTING]]]></Impression>\n      <Creatives>\n        <Creative id=\"1\" sequence=\"1\">\n          <UniversalAdId idRegistry=\"Ad-ID\">HOSTREAD01</UniversalAdId>\n          <Linear>\n            <Duration>00:00:30</Duration>\n            <TrackingEvents>\n              <Tracking event=\"start\"><![CDATA[https://track.example/start]]></Tracking>\n              <Tracking event=\"firstQuartile\"><![CDATA[https://track.example/q1]]></Tracking>\n              <Tracking event=\"midpoint\"><![CDATA[https://track.example/mid]]></Tracking>\n              <Tracking event=\"thirdQuartile\"><![CDATA[https://track.example/q3]]></Tracking>\n              <Tracking event=\"complete\"><![CDATA[https://track.example/complete]]></Tracking>\n            </TrackingEvents>\n            <MediaFiles>\n              <MediaFile delivery=\"progressive\" type=\"audio/mpeg\" bitrate=\"128\" width=\"0\" height=\"0\">\n                <![CDATA[https://cdn.example/spot-128.mp3]]>\n              </MediaFile>\n            </MediaFiles>\n          </Linear>\n        </Creative>\n      </Creatives>\n    </InLine>\n  </Ad>\n</VAST>"
        },
        {
          "type": "paragraphs",
          "heading": "What that document gets wrong in practice",
          "paragraphs": [
            "Audio ad tags accumulate a specific set of defects, and they persist longer than video defects do because nobody is watching a screen when they happen. A broken video ad produces a black frame somebody notices. A broken audio ad produces silence, or the previous segment continuing, and the listener assumes the episode simply had no ad.",
            "The MediaFile element is the usual site. VAST requires a media type on it, and an audio creative served with a video mime type, or with no type at all, will be skipped by a player that filters on type before it downloads anything. Dynamic insertion platforms that transcode on the fly are particularly good at emitting the wrong one, because the transcode target and the declared type are set in different parts of the pipeline.",
            "Duration is the second. It is a required element on a Linear creative, it has a fixed HH:MM:SS format, and an ad server that emits a bare number of seconds produces a document that fails to parse in strict players and silently rounds in permissive ones. In audio that error is invisible until a reconciliation two weeks later shows a completion rate that cannot be right.",
            "Then the trackers themselves. Mixed content, HTTP tracking URLs on an HTTPS delivery path, unencoded macros, and wrapper chains that resolve to an endpoint returning an HTML error page with a 200 status. All of those are ordinary VAST failures. None of them are audio specific. All of them are more expensive in audio because the feedback loop that would surface them does not exist."
          ]
        },
        {
          "type": "list",
          "heading": "What a parser settles on an audio tag, before anything plays",
          "items": [
            "Whether the response is well formed XML at all, or an error page with a success status, which remains the single most common thing a working looking ad tag endpoint returns.",
            "Whether the declared VAST version on the root element matches the elements actually used, including DAAST era markup that survived a migration and now sits in a document claiming 4.x.",
            "Whether every Linear creative carries a Duration in HH:MM:SS form rather than a bare integer or an empty element.",
            "Whether MediaFile carries a type attribute, and whether that type is an audio type consistent with what the CDN actually serves.",
            "Whether the tracking event set is complete enough to support the reporting the buyer was sold, which is the check that matters when the download side of the ledger cannot corroborate anything.",
            "Whether every tracking and impression URL is HTTPS and macro correct, and whether wrapper chains terminate within a sane depth rather than looping.",
            "Whether an ad pod or VMAP structure declares breaks that a dynamic insertion platform can actually fill at the offsets it names."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The reconciliation you can actually do",
          "paragraphs": [
            "You cannot make a download equal an impression. The two definitions are not convertible, and version 2.3 does not pretend otherwise: the guidance is that everyone counts the same way, not that the counts converge across methods. Anthony Katsur put the goal as measurement only working at scale if everyone is counting the same way, which is a statement about consistency inside a method rather than agreement across methods.",
            "What you can do is remove the variable that is not methodology. If the VAST tag is valid, the discrepancy between the log count and the event count is explained by the difference in definitions, and that is a conversation both sides can have with numbers. If the VAST tag is broken, the discrepancy is explained by the tag, and no amount of methodology discussion will find it, because the log side has no visibility into whether the ad played and the event side is reporting the absence of events as if it were the absence of listeners.",
            "So the case for validating audio tags has nothing to do with audio being complicated. It is the simplest surface VAST supports. It is also the only one where no other part of the stack will raise its hand."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Before 19 August",
          "paragraphs": [
            "The comment window closes on 19 August 2026, and the constituency most likely to skip it is the one that traffics the ads rather than the one that counts the episodes. That is a shame, because the video podcast section is where a technical comment would land best. A guideline that describes how to measure a streaming video podcast is describing an environment with a player in it, and once there is a player there is a VAST document, and once there is a VAST document the question of whether it fired is answerable rather than inferred.",
            "If you run audio inventory, the useful thing to do this month is smaller than a comment letter. Take the tags you are already serving, run them through a parser, and find out how many of them would have been caught by a check nobody was running."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate an audio tag the same way you validate video",
          "paragraph": "Paste an audio VAST tag into the validator for structural, media file, macro and tracking findings, including the DAAST era markup that survives migrations. It runs locally in the browser and nothing is stored.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "IAB Tech Lab releases Podcast Technical Measurement Guidelines v2.3 for public comment",
              "href": "https://www.prnewswire.com/news-releases/iab-tech-lab-releases-podcast-technical-measurement-guidelines-v2-3-for-public-comment-302830182.html",
              "description": "The 21 July 2026 announcement, the 19 August comment deadline, the terminology and video podcast changes, and the note that version 3.0 targets streaming video podcasts in 2027.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Podcast measurement guidelines coverage",
              "href": "https://podnews.net/press-release/iab-tech-lab-v23-public",
              "description": "Trade coverage of the same release, with the server side log analysis rationale stated in full.",
              "source": "Podnews"
            },
            {
              "label": "Digital Audio Ad Serving Template",
              "href": "https://iabtechlab.com/standards/digital-audio-ad-serving-template-daast/",
              "description": "The DAAST standard page, including its deprecation and the merge of audio support into VAST 4.1.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VMAP and DAAST validation in vastlint core",
              "href": "/blog/vmap-and-daast-validation-in-vastlint-core",
              "description": "What the validator checks on ad break structures and legacy audio markup, and why DAAST era documents still turn up in production.",
              "source": "vastlint"
            },
            {
              "label": "How to validate VAST trackers before launch",
              "href": "/blog/how-to-validate-vast-trackers-before-launch",
              "description": "The tracker level checks that apply identically to audio: HTTPS, macro encoding, wrapper depth and endpoints that return a 200 with the wrong body.",
              "source": "vastlint"
            },
            {
              "label": "VAST rule catalog",
              "href": "/docs/rules/",
              "description": "Every rule vastlint checks, including the media file, duration and tracking rules that apply to audio creatives.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "adcp-3-1-format-capabilities-vast-duration",
      "title": "AdCP 3.1 Turns Creative Formats Into Declared Capabilities. The Duration Is Still a Number in a JSON File.",
      "description": "The 3.1 release gives creative agents a canonical way to advertise what they can build: stable capability ids, format kinds, and duration bounds that can be open ended on one side. Under specified selectors now fail closed instead of matching by loose overlap, which is a real improvement. None of it opens the VAST document, so the one field both sides think they agreed on is the one nobody has read.",
      "publishedAt": "2026-08-08",
      "author": "Alex Sekowski",
      "readingTime": "10 min read",
      "heroKicker": "Agentic creative",
      "tags": [
        "AdCP",
        "Agentic",
        "Creative formats",
        "VAST validator",
        "Standards"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The format layer got a vocabulary",
          "paragraphs": [
            "AdCP 3.1 is described in its own release notes as production hardening for real agent operations, which is what a specification says when the gaps were found by running buys against real publishers rather than by reading the schema. It is additive over 3.0, and the patch line has not slowed down: four releases landed between 3 and 8 August alone. The creative half of it is the part worth reading if you ship video.",
            "The change is that a creative agent now declares what it can produce, in a machine readable way, instead of a buyer guessing from prose. Capabilities carry a supported formats array, each entry has a stable capability id that is local to the agent but durable over time, and a buyer targets that id directly when it asks for a creative to be built. Format selection stopped being string matching against a name somebody typed.",
            "Duration got a proper model at the same time. Hosted audio and video formats can express a range with one side open, so a bound of up to sixty seconds is expressible without inventing a lower bound nobody meant, and inventory with a fixed slot uses an exact duration instead of a range collapsed to a single point. That distinction sounds pedantic until you have argued with a partner about whether a thirty second slot means exactly thirty or at most thirty.",
            "And selectors that do not fully specify a format now fail closed rather than matching by loose overlap. Of everything in the release, that is the change most likely to save someone a campaign. A protocol that silently picks something plausible when the request was ambiguous produces a creative nobody asked for, and nobody finds out until delivery."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What that gets you, precisely",
          "paragraphs": [
            "Everything above is negotiation. It fixes what the two agents believe they agreed to build, before anything is built, which is the right moment to fix it. A buyer agent that targets a capability id and receives a manifest back holds a record of the agreement that a human can audit later.",
            "What none of it establishes is the creative itself. For video the creative is a VAST document, and AdCP carries it as an asset with a delivery type of either a URL that returns VAST XML or an inline string containing it. In the first case the bytes have not been fetched. In the second they are sitting in the manifest and still nobody has parsed them.",
            "So the format layer and the asset layer make claims at two different altitudes, and the two can disagree without either side noticing. The capability says the agent produces spots of at most sixty seconds. The asset says the duration is a certain number of milliseconds, qualified in the schema with if known. The tag says something in an element called Duration. Three assertions, one of which is the actual instruction to the player."
          ]
        },
        {
          "type": "code",
          "heading": "Three numbers that are allowed to disagree",
          "language": "json",
          "code": "// capability, declared by the creative agent\n{\n  \"capability_id\": \"video_hosted_16x9\",\n  \"format_kind\": \"hosted_video\",\n  \"duration_ms_range\": [null, 60000]\n}\n\n// asset, declared in the creative manifest\n{\n  \"asset_type\": \"vast\",\n  \"delivery_type\": \"url\",\n  \"url\": \"https://adserver.example/vast?pl=[PLACEMENT]\",\n  \"vast_version\": \"4.2\",\n  \"duration_ms\": 30000\n}\n\n// the document the player actually reads\n<Linear>\n  <Duration>00:01:05</Duration>\n</Linear>"
        },
        {
          "type": "paragraphs",
          "heading": "Nothing in that exchange raises an error",
          "paragraphs": [
            "The capability is satisfied by the asset, because thirty thousand milliseconds is under the sixty second bound. The asset validates against the JSON Schema, because thirty thousand is an integer and the field is optional anyway. The manifest is accepted, the buy is confirmed, and the tag returns a sixty five second creative into a slot that will cut it off at thirty, or reject it outright depending on the player.",
            "Nothing has gone wrong in the protocol. AdCP exchanges creative metadata, which is what it says it does, and a metadata protocol has no business becoming a video ad parser. The gap is that the loop never closes. Something has to open the document and compare it against the claims, and until 3.1 there was no clean statement of which claims to compare it against. Now there is, which makes the absent check easier to notice.",
            "This matters more than it did two years ago because of who is writing the document. A generative creative agent produces VAST the same way it produces text: by generating something shaped like what it has seen. Shape is not correctness. A document can carry a plausible Duration, a plausible tracking set, a MediaFile URL that resolves to nothing, and a version attribute that contradicts the elements underneath it, and a schema check on the manifest that references it sees none of that."
          ]
        },
        {
          "type": "list",
          "heading": "The mismatches a parser settles in one pass",
          "items": [
            "Declared duration against the Duration element, which is the check the format layer now makes meaningful because there is finally an authoritative bound to compare against.",
            "Declared VAST version against the version attribute on the root element, and against the elements actually used, since a document claiming 4.2 while using 3.0 era markup parses differently depending on who reads it.",
            "Declared tracking events against the TrackingEvents actually present, so a manifest promising quartile reporting cannot be fulfilled by a tag that only carries an impression.",
            "A VPAID claim of false against a document that still ships an application/javascript media file, which is the deprecation everyone declared complete and nobody finished.",
            "Whether the endpoint behind a URL delivery asset returns VAST XML at all, rather than an HTML error page with a success status.",
            "Whether wrapper chains terminate, and within what depth, since a manifest asset is one URL and the tag behind it can be four redirects deep before anything renders.",
            "Whether media file renditions exist that satisfy the placement the format kind describes, rather than a single rendition that happens to be first in the list."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The wire rules that will break an existing integration",
          "paragraphs": [
            "Separately from formats, 3.1 changed how the envelope works, and two of those changes will break implementations that were written carefully.",
            "The first is idempotency. An idempotency key is now required on every task request, reads included, with staged enforcement: sellers on 3.1 should reject reads that omit it, and 3.2 will require rejection. Reads are the requests nobody thought needed a replay guard, which is exactly why the enforcement is staged rather than immediate.",
            "The second is envelope flattening, and it inverts an instinct. The protocol envelope no longer nests the body under a payload key. Envelope fields and body fields are siblings at the root, and servers are required to tolerate envelope fields they do not recognise. Strict validation is called out as non conformant, with the mechanisms named directly: strict MCP framework modes, strict model validation, and generated schemas that set additional properties to false. If you turned strictness on because that is what careful engineers do, you built a client that fails against a conformant server.",
            "Version negotiation landed in the same release. Every request and response carries a version at release precision, sellers advertise the releases they support, and a buyer pinning something unsupported gets a typed error naming what would have worked. That is a mechanism the bid stream still lacks entirely, which is a separate argument we made on the OpenRTB side."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where a validator sits in this",
          "paragraphs": [
            "The vastlint MCP server answers capability discovery as an AdCP agent on the governance protocol, with a content standards specialism, idempotency support and a replay window. That is a deliberately narrow declaration. It does not plan media, it does not build creatives, and it does not negotiate. It answers one question, which is whether a document does what somebody said it does.",
            "The reason to expose that as a protocol surface rather than a dashboard is the same reason 3.1 exists at all. In an agentic pipeline there is no human between the manifest and the delivery. A broken tag that a trafficker would have caught in an afternoon runs for a flight, and the report that eventually surfaces it describes it as underdelivery rather than as a parse failure. A check the agent can call is a check that happens. A check on a screen is a check that happens when someone remembers.",
            "The formal verification programme AdCP has planned for 3.1, where implementations publish verifiable conformance output against a shared test corpus, is the same idea applied to the protocol itself. It is a good instinct and it stops at the protocol boundary. Conformance to AdCP proves the manifest is well formed. It proves nothing about the creative the manifest points at, and it was never meant to."
          ]
        },
        {
          "type": "cta",
          "heading": "Close the loop on a manifest you already accepted",
          "paragraph": "Paste a VAST tag or a tag URL into the validator and compare what the document does against what the creative manifest claimed. Structural, media file, macro and tracking findings, running locally in the browser with nothing stored.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "AdCP release notes",
              "href": "https://docs.adcontextprotocol.org/docs/reference/release-notes",
              "description": "The 3.1.0 entry covering canonical format capabilities, capability ids, duration ranges, fail closed selectors, the idempotency requirement, envelope flattening and version negotiation.",
              "source": "Ad Context Protocol"
            },
            {
              "label": "adcontextprotocol/adcp releases",
              "href": "https://github.com/adcontextprotocol/adcp/releases",
              "description": "The 3.1.x patch line, including the four releases between 3 and 8 August 2026.",
              "source": "GitHub"
            },
            {
              "label": "AdCP can declare a VAST tag. It cannot check one.",
              "href": "/blog/adcp-vast-asset-declared-vs-verified",
              "description": "The asset level version of the same argument: every field on a VAST asset is a claim about a document nobody has parsed.",
              "source": "vastlint"
            },
            {
              "label": "Agentic buying needs a harness",
              "href": "/blog/agentic-buying-needs-a-harness",
              "description": "Why creative validation has to be a tool an agent can call rather than a dashboard a human checks.",
              "source": "vastlint"
            },
            {
              "label": "The agentic protocols shipped a version handshake. A bid request still has nowhere to say which OpenRTB it is.",
              "href": "https://rtblint.org/blog/agentic-version-negotiation-openrtb-gap/",
              "description": "The bid stream half of the version negotiation argument, and what AdCP 3.1 built that OpenRTB still lacks.",
              "source": "rtblint"
            },
            {
              "label": "VAST rule catalog",
              "href": "/docs/rules/",
              "description": "Every rule vastlint checks, including the duration, version, VPAID and tracking rules referenced here.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "ctv-capacity-headroom-new-formats-delivery",
      "title": "CTV Sells 65 Percent of Its Ad Capacity. The Headroom Sits in the Formats With the Shortest Delivery Track Record.",
      "description": "Omdia published a $0.21 per viewing hour monetisation benchmark for ad-supported CTV on 29 July. The two utilisation figures behind it point at different problems, and the larger half of the upside can only come from pause, screensaver, overlay, squeezeback and in-scene inventory. Those are the formats whose VAST payload shipped two weeks ago.",
      "publishedAt": "2026-07-31",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "CTV economics",
      "tags": [
        "CTV",
        "Ad load",
        "CTV Ad Portfolio",
        "VAST errors",
        "Monetisation"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "A benchmark, and what it is measuring",
          "paragraphs": [
            "Omdia published Video Advertising KPI Benchmarks: Monetization on 29 July 2026. The headline number is that ad-supported connected TV services could average $0.21 per hour of viewing if every available advertising slot were sold, measured across hybrid VoD, AVoD, FAST and broadcaster VoD, and derived from 2025 advertising loads in the UK, the US, Australia, Brazil, Canada, France, Germany and Mexico.",
            "Hour of viewing is a better unit than the industry usually gets. Ad load per hour differs by a factor of several between a FAST channel that runs near broadcast density and an ad-light subscription tier that runs four minutes, so revenue per user or revenue per impression compares almost nothing when you put those two services in the same table. Normalising on viewing time makes the comparison mean something.",
            "The report carries two utilisation figures alongside the benchmark. Services are running at roughly 65 percent of their commercial capacity, and at 32 percent of the maximum regulatory advertising capacity that applies to broadcast linear television. Omdia puts the resulting upside at two to three times."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Those two percentages are not the same gap",
          "paragraphs": [
            "Most of the trade coverage ran them together. They describe different problems and they have different fixes.",
            "Sixty-five percent of commercial capacity is a fill problem. The slots exist, the service is willing to sell them, and they go unsold. Closing that gap alone is worth roughly one and a half times, not two to three.",
            "Thirty-two percent of linear's regulatory ceiling is a load problem. It says streaming shows far fewer ad minutes per hour than a broadcaster is legally permitted to show, which is a decision about the product rather than a failure of the sales team. Getting from 32 percent toward that ceiling is where the rest of the two to three times lives.",
            "So the larger half of the upside requires more advertising minutes per viewing hour, not just better fill on the minutes already there. That is the part worth thinking about carefully if you ship tags for a living."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "You cannot get there with more mid-rolls",
          "paragraphs": [
            "Streaming runs at a third of linear's permitted load for a reason, and the reason is not that anyone forgot. Ad-supported tiers compete on tolerability against an ad-free tier of the same service, one click away in the same account settings. Tripling mid-roll minutes is a churn experiment that most of these services have already run at smaller increments and stopped running.",
            "If the minutes cannot come from interrupting content, they have to come from advertising time that sits outside the content: the pause screen, the idle screensaver, an overlay during play, a squeezeback around the frame, an in-scene placement, and QR codes attached to any of them.",
            "That is the same list IAB Tech Lab standardised in the CTV Ad Portfolio. The signaling guidance was finalised on 22 July 2026 and the creative payloads landed in the VAST repository on 17 July, in one pull request carrying both a VAST 4.4 draft schema and a set of VAST 2.0 extension documents.",
            "The answer to where the two to three times comes from and the answer to what the standards body shipped two weeks ago are the same list. That is not a coincidence, it is the industry routing around a constraint it already understands. It does mean the revenue headroom is concentrated in exactly the formats with the least delivery history."
          ]
        },
        {
          "type": "quote",
          "quote": "Unsold capacity is recoverable. The break comes round again next hour. A slot that filled and then failed is gone, and in the seller's own reporting it looks identical to a slot nobody bid on.",
          "attribution": "vastlint"
        },
        {
          "type": "paragraphs",
          "heading": "Sold is not played, and hour of viewing is measured after the fact",
          "paragraphs": [
            "The $0.21 ceiling is explicitly defined as every available slot being sold. The realised figure is booked revenue divided by viewing hours, and revenue books against a tracked impression, not against a win notice.",
            "Everything between those two events is the VAST path. Fetch the tag, resolve however many wrappers are in the chain, pick a MediaFile the device can actually decode, render it, fire the impression and the quartiles. A failure anywhere in that sequence produces an Error ping with a code in it and nothing else that anyone downstream counts.",
            "The slot still consumed its position in the break. The viewing hour still elapsed. No impression was booked. In a monetisation-per-hour view that slot is non-revenue viewing time, which is the same thing the report is calling unsold capacity.",
            "Which is the point. The 35 percentage points Omdia measures as unfilled commercial capacity contain an unknown quantity of slots that were sold and did not deliver, and the prescribed remedy of growing the advertiser base does nothing whatsoever for that portion. More demand on a path that drops one in fifty responses produces more revenue and the same drop rate."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Which failures scale with ad load, and which scale worse",
          "paragraphs": [
            "Some VAST failures are per-impression and grow linearly as you add slots. A creative with no playable MediaFile fails at the same rate whether it is the first ad of the hour or the ninth.",
            "Pod-level failures do not behave that way. A pod has one deadline, set by the break length or by the stitching window, and every slot in it draws down the same budget. A wrapper chain that resolves comfortably in a two-slot pre-roll starts colliding with that deadline at six slots, because the chains resolve in sequence against a fixed wall clock.",
            "That is the failure mode to watch as load rises: the same tags, the same partners, the same chain depth, and a timeout rate that climbs because you changed the pod and not the tag."
          ]
        },
        {
          "type": "code",
          "heading": "VAST error codes, and how each behaves as slots per hour go up",
          "language": "text",
          "code": "102  VAST version not supported\n     New formats push responses onto 4.x paths. Device fleets that\n     parse 2.0 fine will reject them. Scales with format mix, not slots.\n\n301  Timeout of VAST URI provided in Wrapper\n302  Wrapper limit reached\n     Superlinear in pod depth. One shared deadline, sequential chains.\n     Adding slots shortens the budget available to every chain in the pod.\n\n403  Could not find a MediaFile supported by this player\n     A pause ad now carries video, image and sometimes an interactive\n     SIMID file. A player that ignores the extension it arrived in has\n     no renditions at all, not a degraded one.\n\n201  Player expecting different linearity\n     A portfolio format delivered as NonLinearAds into a slot the\n     player opened expecting Linear. Rises with format mix.\n\n501  NonLinear dimensions do not align with the display area\n     Rare while NonLinear meant a small overlay banner. Squeezeback,\n     in-scene and QR all resolve a rectangle against the ad view.\n     This becomes a common code, not an exotic one.\n\n900  Undefined error\n     What most players report when they meet a payload shape they were\n     not built for. Rises first, and tells you least."
        },
        {
          "type": "paragraphs",
          "heading": "The new formats have two delivery paths and neither has a track record",
          "paragraphs": [
            "The 17 July pull request shipped the portfolio twice. The VAST 4.4 draft schema carries the formats natively, one AdCOM signal per Extension element. The VAST 2.0 extension documents carry the same six formats and the same QR metadata inside a single named container, alongside the media, because VAST 2.0 is what parses on the long tail of devices that will still be in living rooms when 4.4 is final.",
            "Both are current. They are not interchangeable, and a validator built for one reports nothing at all on the other. We wrote that up separately.",
            "The delivery consequence is easy to underestimate. A pause ad used to be a JPEG in a NonLinear StaticResource. It is now a creative with a duration, a MediaFiles list, optional interactive content and quartile tracking. Every failure mode that has ever applied to a linear creative now applies to a pause screen, on hardware that has never rendered one, through an extension mechanism whose whole design property is that unaware players ignore it silently.",
            "Silent is the operative word. An extension a player does not recognise is not a parse error and does not fire an Error ping. It renders the native NonLinear fallback if the ad server included one, and nothing if it did not."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the first year of a format is the expensive one to get wrong",
          "paragraphs": [
            "A mid-roll that fails costs one impression against a baseline that is years deep and well understood. Nobody reprices mid-roll inventory because of it.",
            "A new format that fails in its first year costs the renewal. Buyers have no baseline to average against, so early delivery evidence is the entire evidence base, and a pause ad that did not render is not read as an integration bug. It is read as a fact about pause ads.",
            "Omdia's own recommendation names the dependency. Reaching the benchmark, the report says, requires growing the advertiser base to maximise fill rates and improving advertising context protocols. The first half is a sales problem. The second half is a specification and conformance problem, and it is the one that determines whether the inventory the sales team sells actually arrives."
          ]
        },
        {
          "type": "list",
          "heading": "What to verify before you raise ad load",
          "items": [
            "Test the pod, not the tag. Chain depth that resolves inside a two-slot break can miss the deadline at six. Measure wrapper resolution time against the actual pod duration you are moving to, not against a single-impression timeout.",
            "Decide which portfolio encoding each partner expects, and ask rather than assume. The 4.x per-signal pattern and the VAST 2.0 container pattern are both live and a parser built for one sees nothing in the other.",
            "Always send a native NonLinear fallback resource alongside a 2.0 portfolio extension. Without it, a player that ignores the extension renders nothing and reports nothing.",
            "Treat error 501 as a launch blocker for squeezeback, in-scene and QR. Those formats resolve a rectangle against the ad view, and a rectangle that does not fit is the failure mode the code was written for.",
            "Split your error reporting by format before you scale the format. An aggregate error rate that looks fine because mid-rolls dominate the denominator will hide a pause-ad path that is failing most of the time.",
            "Watch code 900 specifically during the first weeks of a new format. Undefined error is what a player reports when it meets a payload shape it was not built for, so it rises first and explains least.",
            "Reconcile unfilled against sold-and-errored on the same report. If those two numbers live in different systems, the gap the benchmark describes is not measurable in your own data either."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The part that is in your control",
          "paragraphs": [
            "Fill rate depends on demand, on floors, on how many buyers have your inventory whitelisted, and on macroeconomic conditions nobody in ad ops sets. It is worth pursuing and it is largely someone else's job.",
            "Whether a tag that wins renders correctly is entirely an engineering property of the tag, the chain and the player, and it is knowable before launch rather than after. That asymmetry is why the delivery half of this deserves attention out of proportion to how often it gets discussed. It is the half you can fix on a Tuesday.",
            "The benchmark is genuinely useful and the headroom is genuinely there. Just be clear that the industry is about to push its growth through the newest, least tested formats in the catalogue, on the most fragmented device population in digital advertising, and that the metric everyone will use to score it cannot see the difference between an empty slot and a broken one."
          ]
        },
        {
          "type": "cta",
          "heading": "Check a CTV Ad Portfolio tag before you scale the format",
          "paragraph": "Paste a tag into the validator for structural, media file, macro and tracking findings, plus the CTV Ad Portfolio and VAST 4.4 rules on the 4.x signaling path. It runs locally in the browser and nothing is stored.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "Omdia: $0.21 per viewing hour sets monetization benchmark for ad-supported CTV",
              "href": "https://omdia.tech.informa.com/pr/2026/july/0point21-dollar-per-viewing-hour-sets-monetization-benchmark-for-ad-supported-ctv",
              "description": "The 29 July 2026 announcement of Video Advertising KPI Benchmarks: Monetization, including the $0.21 HOV benchmark, the 65 percent commercial capacity and 32 percent regulatory capacity figures, and the markets covered.",
              "source": "Omdia"
            },
            {
              "label": "Report: Ad-supported CTV missing monetisation potential",
              "href": "https://www.advanced-television.com/2026/07/29/reports-0-21-per-viewing-hour-benchmark-for-ad-supported-ctv/",
              "description": "Trade coverage of the same report, with the two to three times revenue framing.",
              "source": "Advanced Television"
            },
            {
              "label": "CTV Ad Portfolio",
              "href": "https://iabtechlab.com/standards/ctv-ad-portfolio/",
              "description": "The standard defining Pause, Screensaver, Overlay, Squeezeback, In-Scene and QR formats. Signaling guidance finalised 22 July 2026.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "The CTV Ad Portfolio also shipped a VAST 2.0 path. It is a different payload.",
              "href": "/blog/ctv-ad-portfolio-vast-2-0-extensions",
              "description": "The two encodings that landed in the same pull request, why a validator built for one reports nothing on the other, and the CreativeId binding rule.",
              "source": "vastlint"
            },
            {
              "label": "A pause ad used to be a JPEG. VAST 4.4 changes that.",
              "href": "/blog/vast-4-4-draft-schema-ctv-ad-portfolio",
              "description": "The draft schema behind the native 4.x delivery path for the portfolio formats.",
              "source": "vastlint"
            },
            {
              "label": "The revenue math of broken VAST",
              "href": "/blog/vast-failures-revenue-math",
              "description": "The per-impression version of the same argument: what a one percent silent failure rate costs at CTV prices, failure by failure.",
              "source": "vastlint"
            },
            {
              "label": "The 65 percent is a bid request problem before it is a demand problem",
              "href": "https://rtblint.org/blog/ctv-capacity-gap-bid-request-quality/",
              "description": "The buy-side half of the same report: why unsold and unparseable land in the same bucket in a seller's fill rate.",
              "source": "rtblint"
            },
            {
              "label": "VAST rule catalog",
              "href": "/docs/rules/",
              "description": "Every rule vastlint checks, including the CTV Ad Portfolio and VAST 4.4 rules.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "ctv-ad-portfolio-vast-2-0-extensions",
      "title": "The CTV Ad Portfolio Also Shipped a VAST 2.0 Path. It Is a Different Payload.",
      "description": "The pull request that landed the VAST 4.4 draft schema on 17 July contained two other files nobody has written about: standardised extension documents that deliver Pause, Screensaver, Overlay, Squeezeback, In-Scene and QR code metadata through VAST 2.0. The payload does not match the 4.x pattern, and validators built for one will not see the other.",
      "publishedAt": "2026-07-30",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Standards",
      "tags": [
        "CTV Ad Portfolio",
        "VAST 2.0",
        "Extensions",
        "AdCOM",
        "Validation"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Three files, not one",
          "paragraphs": [
            "The VAST repository merged pull request 57 on 17 July 2026, from a branch called 4.4Development, titled CTV Ad Portfolio Updates. The file everyone looked at was vast_4.4.xsd, the draft schema we wrote about here five days later.",
            "It was not the only file in that pull request. Two others landed alongside it: extensions/ctv_ad_portfolio.md and extensions/ctv_qrcode.md. Neither is a draft. Both define standardised extension payloads for VAST 2.0, and between them they cover the same six formats and the same QR code metadata as the draft schema, through a completely different mechanism.",
            "That is not a redundancy. It is a reach decision, and it is probably the more consequential half of the release."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the standards body targeted a spec from 2008",
          "paragraphs": [
            "VAST 4.4 is a working draft under discussion. VAST 4.2 and 4.3 are final but unevenly supported. VAST 2.0 is the version that parses essentially everywhere, including on the long tail of CTV devices that will still be in living rooms when 4.4 is finalised.",
            "The problem is that VAST 2.0's NonLinear element has almost nothing in it. Its whole vocabulary is StaticResource, IFrameResource, HTMLResource, TrackingEvents, NonLinearClickThrough and AdParameters. A pause ad delivered through native VAST 2.0 is a JPEG, with no video, no duration, no interactive creative file and therefore no quartile tracking.",
            "The CTV Ad Portfolio extension solves that without touching the schema. It adds an Extension element under InLine/Extensions with type=\"ctv_ad_portfolio\", and puts a MediaFiles container inside it. Video files, image files, SIMID interactive creative files, a Duration, tracking events, icons, click tracking. The delivery model that 4.4 adds natively, back-ported into the version that already ships.",
            "Players that do not recognise the extension ignore it, which is exactly what VAST extensions are for. The document also asks ad servers to include a native NonLinear StaticResource as a fallback where practical, so an unaware player still renders something rather than firing an error."
          ]
        },
        {
          "type": "quote",
          "quote": "One release, two encodings of the same signals. Tooling that recognises the 4.x pattern treats the 2.0 pattern as unstructured extension data, and reports nothing at all.",
          "attribution": "vastlint standards note"
        },
        {
          "type": "paragraphs",
          "heading": "The payload is not the 4.x payload",
          "paragraphs": [
            "This is the part that matters for anyone who has already built against the signaling guidance. The 4.x pattern described in the finalised guidance carries one AdCOM signal per Extension element, each marked ext=\"adcom\". The VAST 2.0 extension carries all of them inside a single named container, as plain child elements, alongside the media.",
            "Same four signals, same AdCOM lists, same integers, different XML. A parser looking for Extension@type=\"plcmt\" finds nothing in a 2.0 document, and a parser looking for Extension@type=\"ctv_ad_portfolio\" finds nothing in a 4.x one."
          ]
        },
        {
          "type": "code",
          "heading": "The same pause ad, signalled two ways",
          "language": "xml",
          "code": "<!-- 4.x pattern: one Extension per AdCOM signal -->\n<Extensions>\n  <Extension type=\"plcmt\" ext=\"adcom\"><plcmt>5</plcmt></Extension>\n  <Extension type=\"pos\" ext=\"adcom\"><pos>7</pos></Extension>\n  <Extension type=\"playbackmethod\" ext=\"adcom\"><playbackmethod>9</playbackmethod></Extension>\n  <Extension type=\"attr\" ext=\"adcom\"><attr>19</attr></Extension>\n</Extensions>\n\n<!-- VAST 2.0 extension: one container, signals plus media -->\n<Extensions>\n  <Extension type=\"ctv_ad_portfolio\">\n    <CreativeId>creative-pause-qr-001</CreativeId>\n    <plcmt>5</plcmt>\n    <pos>7</pos>\n    <playbackmethod>9</playbackmethod>\n    <attr>19</attr>\n    <attr>21</attr>\n    <Duration>00:00:15</Duration>\n    <MediaFiles>\n      <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\" bitrate=\"8000\" codec=\"H.264\">\n        <![CDATA[https://cdn.example.com/pause/brand_cine_1080p.mp4]]>\n      </MediaFile>\n    </MediaFiles>\n  </Extension>\n</Extensions>"
        },
        {
          "type": "paragraphs",
          "heading": "CreativeId is doing load-bearing work",
          "paragraphs": [
            "There is a structural problem the extension has to solve and it is worth understanding before you generate one. In VAST 2.0 the Extensions container hangs off InLine, not off Creative. So an extension that describes a specific creative has no inherent binding to it.",
            "The document's answer is a CreativeId child element whose value matches the Creative@id attribute, required whenever the response contains more than one Creative. If it is omitted, the extension applies to the only NonLinearAds creative in the response.",
            "Which means a multi-creative response that omits CreativeId is not a parse error. It is a silent misattribution: the media files, the duration, the format signal and the creative attributes all get applied to whichever creative the receiving platform decides to apply them to. Nothing in the XML is malformed. The wrong ad renders in the wrong slot, or the right ad renders with the wrong declared format, and the tag validates.",
            "The QR extension takes the opposite approach and avoids the problem: it goes under Creative/CreativeExtensions, so it is already scoped to its creative. The document notes that if you do put QR metadata in an InLine-level Extension instead, it should carry a creative identifier, and that Creative/CreativeExtensions is the preferred placement."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The QR extension, and the coordinate system people will get wrong",
          "paragraphs": [
            "CreativeExtension type=\"tl_qrcode\" carries four things: QrCodeScanUrl, an optional QrCodeImageUrl, a QrCodePosition with xPosition and yPosition, and a QrCodeSize with size. Positions and size are percentages, and the QR code is assumed square.",
            "The percentages are relative to the ad view, not the screen. The document works the example: an overlay lower third occupying a 1920 by 324 ad view at the bottom of a 1920 by 1080 screen resolves xPosition=\"10.0%\" to 192 pixels within the ad view and yPosition=\"10.0%\" to 32.4 pixels within it, while size=\"15.0%\" resolves to a 288 by 288 square because it is measured against the ad view width. Anyone who assumes screen coordinates puts the code somewhere else entirely, and on a lower third the vertical error is the difference between inside the ad and outside it.",
            "The other thing to internalise is that QrCodeScanUrl is not a clickthrough. The document is explicit that it does not replace ClickThrough or NonLinearClickThrough, that the two may differ, and that a scan destination is often a CTV-specific coupon or attribution endpoint while the clickthrough points at a general landing page. It also asks that measurement distinguish four separate things: the impression, the QR code rendering, the scan, and downstream advertiser-site activity. Presence of a QR code is not exposure, and exposure is not a scan."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What vastlint did with these, and what we changed",
          "paragraphs": [
            "We shipped seventeen rules for the CTV Ad Portfolio and the 4.4 draft on 25 July, including value checks for plcmt, pos, playbackmethod and the motion attributes, and structural checks for the QR block. Every one of them was written against the 4.x pattern, and the 2.0 path had no coverage at all.",
            "Running the extension documents own examples through that build was not a good look. None of the AdCOM value checks fired, because the integers were not where the rules looked for them. None of the QR checks fired, because the block sits in Creative/CreativeExtensions on a 2.0 document. What did fire was the generic extension check, reporting that a MediaFiles element inside an Extension is in an unusual place, which is true in general and wrong here: in this extension that is precisely where it belongs.",
            "The squeezeback example collected one more, a version mismatch, because it declares version 2.0 while carrying a SIMID interactive creative file. Strictly that is correct, SIMID is a 4.x capability. In context it is the entire point of the extension, which exists to deliver 4.x capability inside a 2.0 document. A rule that is right in general was wrong on this path.",
            "That was a gap and it was ours, so we closed it. The value and QR checks now reach the 2.0 container, the generic extension and version rules skip standardised IAB containers, and six new rules cover the failure modes the container introduces on its own. The catalog goes from 212 rules to 218. All five VAST 2.0 examples published in the two extension documents now validate clean.",
            "One of those six is worth more than the others. VAST 2.0 hangs Extensions off InLine rather than Creative, so a multi-creative response with no CreativeId binds the media and the format signals to whichever creative the receiving platform happens to pick. Nothing else in the document is malformed, which is why it needs a rule of its own rather than a schema check.",
            "While fixing it we found a second defect of our own making. Our attr check accepted only 21, 22 and 23, the three motion attributes. AdCOM 1.0-202607 added 19 Contains advertiser QR Code and 20 Support alpha channel transparency in the same family, and IAB declares 19 in its examples, so we were reporting the reference implementation as wrong. The accepted set is now 19 through 23."
          ]
        },
        {
          "type": "code",
          "heading": "Before and after on the IAB's own VAST 2.0 examples",
          "language": "text",
          "code": "Before                                    After\n\nStatic Screensaver Ad     2 warnings      0 findings\n  extension-misplaced-element (x2)\n\nVideo Pause Ad            1 info          0 findings\n  adcom-attr-not-motion on attr 19\n\nSIMID Squeezeback Ad      4 warnings      0 findings\n  extension-misplaced-element (x3)\n  version-mismatch\n\nPause Ad with QR Code     0 findings      0 findings\n  (no checks were reachable)              (signals and QR both validated)"
        },
        {
          "type": "paragraphs",
          "heading": "The values are a live binding to a document that moves",
          "paragraphs": [
            "Both extension documents make the same deliberate choice: they do not reproduce the AdCOM enumeration tables. They link to them, and they say that if a referenced AdCOM list is updated, implementations should follow the updated list without requiring a change to the extension document.",
            "As a spec-maintenance decision that is clearly right. It stops four copies of the same table drifting apart. As an operational fact it means the meaning of an integer inside your VAST response is defined by a separate repository on a separate release cadence, and you are expected to track it.",
            "Worth knowing what that repository did this month. AdCOM 1.0-202607 was tagged on 16 July, the day before this pull request merged, and it is the release that actually adds plcmt 5 through 9, pos 8 through 17, playbackmethod 8 through 11, and creative attributes 19 through 23. It also rewords five playback methods that already existed, and it carries a Content object with seven field names that were renamed by accident in March and corrected on the main branch on 22 July without the tag being re-cut.",
            "So the honest summary of the binding is: follow the current list, and be aware that the current list and the current release are not always the same document."
          ]
        },
        {
          "type": "list",
          "heading": "If you are shipping CTV Ad Portfolio formats through VAST 2.0",
          "items": [
            "Decide which encoding each partner expects, and ask rather than assume. The 4.x per-signal pattern and the 2.0 container pattern are both current and they are not interchangeable.",
            "Always send CreativeId when the response has more than one Creative. It is the only thing binding the extension to its creative, and omitting it fails silently rather than loudly.",
            "Include a native NonLinear fallback resource wherever practical, so a player that ignores the extension still has something to render instead of firing an error.",
            "Treat QR position and size as ad-view relative, and check that the resolved rectangle fits inside the ad view and does not cover an AdChoices icon or a player control.",
            "Keep QrCodeScanUrl and the clickthrough separate in your reporting, and do not let a rendered QR code be counted as a scan.",
            "Pin the AdCOM release you validate enum values against, and diff it when a new one is tagged. The integers in your VAST response are defined somewhere you do not control."
          ]
        },
        {
          "type": "cta",
          "heading": "Check a CTV Ad Portfolio tag",
          "paragraph": "Paste a tag into the validator for the structural, media file, macro and tracking findings, plus the CTV Ad Portfolio and 4.4 rules on the 4.x signaling path. It runs locally in the browser and nothing is stored.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "CTV Ad Portfolio for VAST 2.0",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast/blob/master/extensions/ctv_ad_portfolio.md",
              "description": "The extension document defining Extension type=\"ctv_ad_portfolio\", its CreativeId binding rule, the MediaFiles delivery model and the AdCOM signal elements. Merged 17 July 2026.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "CTV QR Code Creative Extension for VAST 2.0",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast/blob/master/extensions/ctv_qrcode.md",
              "description": "The tl_qrcode CreativeExtension: scan URL, image URL, ad-view-relative position and size, and the measurement guidance separating rendering from scanning.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "A pause ad used to be a JPEG. VAST 4.4 changes that.",
              "href": "/blog/vast-4-4-draft-schema-ctv-ad-portfolio",
              "description": "The third file in the same pull request, and the rules we shipped for it.",
              "source": "vastlint"
            },
            {
              "label": "CTV Ad Portfolio signaling and VAST validation",
              "href": "/blog/ctv-ad-portfolio-signaling-vast-validation",
              "description": "The finalised signaling guidance and what it asks a VAST response to declare.",
              "source": "vastlint"
            },
            {
              "label": "AdCOM 1.0-202607: new enums, five redefined playback methods, and two releases carrying the wrong field names",
              "href": "https://rtblint.org/blog/adcom-1-0-202607-enums-and-content-rename/",
              "description": "What the integers in these extensions actually mean, what changed on 16 July, and why the tagged release and the current document disagree.",
              "source": "rtblint"
            },
            {
              "label": "VAST rule catalog",
              "href": "/docs/rules/",
              "description": "Every rule vastlint checks, including the CTV Ad Portfolio and VAST 4.4 rules shipped on 25 July.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "adcp-vast-asset-declared-vs-verified",
      "title": "AdCP Can Declare a VAST Tag. It Cannot Check One.",
      "description": "The AdCP creative protocol has a first-class VAST asset: delivery type, version, tracking events, VPAID support, captions. Every one of those fields is a claim about a document nobody has parsed, and a generative creative agent produces documents that look right for the same reason it produces text that reads right. Which claims a parser settles, and why a validator is the feedback signal that closes the loop.",
      "publishedAt": "2026-07-29",
      "author": "Alex Sekowski",
      "readingTime": "10 min read",
      "heroKicker": "Agentic creative",
      "tags": [
        "AdCP",
        "Agentic",
        "AI creative",
        "VAST validator",
        "Standards"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The manifest has a VAST asset type now",
          "paragraphs": [
            "Most coverage of agentic advertising stops at the deal. An agent discovers inventory, negotiates terms, confirms a media buy, and the story ends there. It does not end there. Something has to ship a creative, and for video that something is a VAST tag, which is why the AdCP creative protocol carries a VAST asset as a first-class type alongside hosted video, images, and trackers.",
            "The asset is deliberately thin. Only the discriminator is required. Everything else is optional metadata, and the schema is explicit about why there is no width or height on it: a VAST response can return several renditions at different dimensions, and the player picks one per device at serve time, so dimensional and codec constraints live on the format and requirements layer rather than on the asset.",
            "Two delivery types are defined, and the distinction matters for validation. A url asset points at an endpoint that returns VAST XML. An inline asset carries the XML in a content string. In the first case nobody knows what the tag says until someone fetches it. In the second the bytes are right there in the manifest and still nobody has parsed them."
          ]
        },
        {
          "type": "code",
          "heading": "A VAST asset as it appears in a creative manifest",
          "language": "json",
          "code": "{\n  \"assets\": {\n    \"video_main\": {\n      \"asset_type\": \"vast\",\n      \"delivery_type\": \"url\",\n      \"url\": \"https://adserver.example/vast?pl=[PLACEMENT]&cb=${CACHEBUSTER}\",\n      \"vast_version\": \"4.2\",\n      \"vpaid_enabled\": false,\n      \"duration_ms\": 30000,\n      \"tracking_events\": [\"impression\", \"start\", \"firstQuartile\", \"midpoint\", \"thirdQuartile\", \"complete\"],\n      \"captions_url\": \"https://cdn.example/spot.vtt\"\n    }\n  }\n}"
        },
        {
          "type": "paragraphs",
          "heading": "Every field there is a claim, not a fact",
          "paragraphs": [
            "Read that asset as a set of assertions about a document nobody has opened. The version is asserted. The duration is asserted, and the schema even qualifies it with if known. The tracking event list is asserted. VPAID support is asserted. The captions URL is asserted to exist and to be a captions file.",
            "None of those assertions are checked by accepting the manifest. A seller agent that validates the manifest against the JSON Schema has confirmed the shape of the claim and nothing about the tag. The gap is not a flaw in AdCP: a protocol for exchanging creative metadata is not a video ad parser, and it should not try to be. But it does mean the interesting failures all land outside the schema."
          ]
        },
        {
          "type": "list",
          "heading": "What only fetching and parsing the tag can settle",
          "items": [
            "Whether the document is well-formed XML at all, or an HTML error page with a 200 status, which is the single most common thing a supposedly working ad tag endpoint returns.",
            "Whether the declared vast_version matches the VAST attribute on the root element, and whether the tag uses elements from a version it does not declare.",
            "Whether the tracking_events the manifest promised actually exist in the tag. A declared complete event with no Tracking node for it is a measurement gap the buyer will discover in reporting.",
            "Whether Impression is present and non-empty. It is required by the specification and routinely omitted by templates that assume something downstream will inject it.",
            "Whether Duration is formatted as HH:MM:SS rather than bare seconds, and whether it agrees with the duration_ms in the manifest.",
            "Whether every media file and tracking URL is https. Players block mixed content outright, and this is invisible in a manifest that only carries the tag endpoint.",
            "Whether a wrapper chain terminates in an InLine ad inside the depth the player allows, and whether each wrapper carries a VASTAdTagURI at all.",
            "Whether the macros in the endpoint survive substitution. The schema accepts VAST-style square-bracket and dollar-brace placeholders as-is and tells buyers not to pre-encode the delimiters, because players match the literal token. A pipeline that percent-encodes them helpfully produces a tag that never resolves."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The version enum stops at 4.2",
          "paragraphs": [
            "One detail is worth flagging for anyone building against the creative protocol today. The VAST asset requirements schema enumerates acceptable versions as 2.0, 3.0, 4.0, 4.1, and 4.2. VAST 4.3 has been final for years and is the version CTV signaling guidance assumes, and a 4.4 draft schema is already circulating.",
            "The practical consequence is a mismatch that no side is wrong about. A seller declaring requirements through AdCP cannot express 4.3 today, so a buyer shipping a 4.3 tag either downgrades the declaration to 4.2 or leaves the field off entirely. Both options put a true statement about the creative outside the protocol, and both are indistinguishable from a genuine 4.2 tag when the manifest is all you have.",
            "This is exactly the class of drift a parser resolves in one call. Read the root element, report the real version, compare it to what was declared, and stop guessing."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Trackers get decomposed, which is useful and lossy",
          "paragraphs": [
            "AdCP does not stop at the tag. It also models individual trackers as their own asset types: a VAST tracker asset for a single Tracking event URL, a DAAST tracker for the audio equivalent, and a pixel tracker for renderer-fired beacons whose event enum mirrors the OpenRTB Native event registry. That decomposition is genuinely useful, because it lets a measurement vendor be attached per event rather than per creative.",
            "It is also lossy in one direction. A decomposed tracker declares that a URL should fire on an event. It says nothing about whether the assembled VAST document places that URL in a node the player will actually read, whether the URL is duplicated across a wrapper chain so the event fires twice, or whether the event name survives the mapping between the flattened AdCP enum and the real VAST elements. Impression, Error, VideoClicks, and ViewableImpression live in dedicated VAST elements rather than under TrackingEvents, and the AdCP enum flattens them into one list by design.",
            "Reassembly is where measurement breaks, and reassembly happens after the manifest is accepted."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "A model that writes a VAST tag writes a plausible VAST tag",
          "paragraphs": [
            "The reason this matters more in an agentic pipeline than it did in a human one is the failure mode of the thing now producing the tag. A creative agent generating VAST XML is doing pattern completion over documents it has seen. Pattern completion is very good at shape and indifferent to constraint, so what comes out looks right in the way a forged signature looks right.",
            "The specific defects are predictable once you know that. Correct element names in the wrong nesting. Duration written as 30 because most numbers in most documents are bare numbers. A tracking event list copied from a different creative, so the manifest promises six events and the document contains four. Attributes that do not exist in any version of the specification but read like they should. Elements from 4.2 inside a document declaring 3.0, because the training data does not separate versions the way a parser does. A UniversalAdId left at the placeholder value that appears in every example tag ever published. http URLs, for the same reason.",
            "None of those are stupid mistakes. They are exactly the mistakes a system optimising for plausibility makes, and they are invisible to every check that operates above the document: the JSON Schema validates the manifest, the manifest declares the tag is 4.2, and the tag says whatever it says.",
            "Asking a second model to review the first one does not fix it either. A reviewing model has the same relationship to the specification as the writing model, which is that it has read a lot of tags and holds no ground truth. Two plausibility engines agreeing is not verification."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "A validator is the feedback signal that closes the loop",
          "paragraphs": [
            "What a parser gives an agent is the one thing the agent cannot produce for itself: a verdict that does not depend on how convincing the output looks. A VAST document either parses or it does not. The required elements are either present or absent. The declared version either matches the root element or it does not. Those are decidable questions with no interpretation in them, which makes them cheap to answer and impossible to argue with.",
            "That turns generation into a loop instead of a gamble. The agent writes a tag, calls the validator, and gets back a list of rule ids with the line and the element each one fired on. It repairs those specific defects and calls again. Because the errors are structural rather than stylistic, the loop usually converges in one or two passes: a missing Impression node is not a matter of taste, and neither is a Duration format.",
            "This is the same property that makes VAST validity usable as a verifiable reward when training a model, which we have written about separately. The argument here is the inference-time half of it. At training time a rule-based checker can score an output without a human in the loop; at generation time that same checker is the grounding signal that stops a plausible tag from shipping as a correct one. One verifier, two uses.",
            "The asymmetry is what makes it worth wiring up. Generating creative is expensive and confident. Checking it is cheap and correct. Putting the cheap correct thing in front of the expensive confident thing is the whole design, and it is the same reason coding agents run tests instead of asking a model whether the code compiles."
          ]
        },
        {
          "type": "list",
          "heading": "Where the check belongs in the creative task loop",
          "ordered": true,
          "items": [
            "build_creative or any generative step: validate what the creative agent produced before it becomes a manifest. A generated tag is a template output, and template outputs fail structurally in the same handful of ways every time.",
            "sync_creatives: this is the natural gate. The seller is already deciding whether to accept the creative, and it is the last point where a rejection costs nothing but a retry. Fetch the tag, parse it, and reject on structural failure rather than on schema shape alone.",
            "preview_creative: a preview that renders is weak evidence, because one player tolerating a tag says little about the next. A parse result is stronger evidence and cheaper to produce.",
            "get_creative_delivery: when delivery numbers look wrong, re-validate the tag as it is being served rather than the tag as it was submitted. Endpoints change behaviour without anyone editing a manifest."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why this is the seller agent's problem",
          "paragraphs": [
            "In a human workflow a broken tag gets caught by an ad ops person who has seen it before and knows what a missing Impression node does to a report. In an agentic workflow that person is not in the loop, and the agent on the other side has no memory of last quarter.",
            "So the gate has to be somewhere in the protocol path, and sync_creatives is the obvious place: the seller is already deciding whether to accept the creative, and a rejection there costs a retry rather than a campaign. A seller that rejects on parse failure closes the loop even when the buyer's agent never opened it.",
            "Both agentic stacks land in the same position on this. IAB Tech Lab's AAMP extends the existing rails and keeps VAST as the video envelope. AdCP defines new agent-native tasks and still ends at a VAST tag. Neither specification validates the creative payload, and neither claims to. That work belongs to whoever wants the impression to render."
          ]
        },
        {
          "type": "cta",
          "heading": "Put the parse step in the agent loop",
          "paragraph": "The agentic integration guide covers wiring the vastlint MCP server into AdCP creative pipelines, AAMP buyer agents, A2A orchestrators, and plain MCP clients, with working configuration for each.",
          "href": "/docs/agentic/",
          "label": "Read the agentic integration guide"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "AdCP VAST asset schema",
              "href": "https://github.com/adcontextprotocol/adcp/blob/main/static/schemas/source/core/assets/vast-asset.json",
              "description": "The vast asset type: delivery_type url or inline, vast_version, tracking_events, vpaid_enabled, accessibility URLs, provenance.",
              "source": "AdCP"
            },
            {
              "label": "AdCP creative protocol documentation",
              "href": "https://docs.adcontextprotocol.org/docs/creative/creative-manifests",
              "description": "Creative manifests, asset types, formats, and the task reference for build_creative, sync_creatives, and preview_creative.",
              "source": "AdCP"
            },
            {
              "label": "AAMP: Agentic Advertising Management Protocols",
              "href": "https://iabtechlab.com/standards/aamp-agentic-advertising-management-protocols/",
              "description": "The IAB Tech Lab stack, which keeps VAST as the video delivery envelope under its agentic layers.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "How AdCP connects to VAST",
              "href": "/docs/adcp/",
              "description": "The layer map: what AdCP automates, and why the VAST tag is still the last mile."
            },
            {
              "label": "VAST version support and error 102",
              "href": "/docs/vast-versions/",
              "description": "What a version mismatch does in a real player, and why declared version and actual version drift apart."
            },
            {
              "label": "VPAID is deprecated",
              "href": "/docs/vpaid-deprecated/",
              "description": "Why a vpaid_enabled claim of true deserves a second look in 2026."
            },
            {
              "label": "VAST validity is a verifiable reward",
              "href": "/blog/vast-validity-is-a-verifiable-reward/",
              "description": "The training-time half of the same argument: why ad-tag validity is one of the few adtech signals a rule-based checker can score without a human or a learned judge."
            },
            {
              "label": "VAST as a reward signal for ML and agents",
              "href": "/docs/vast-reward-signal/",
              "description": "What a verifier has to return to be usable in a training or repair loop: stable rule ids, positions, and dense partial credit."
            }
          ]
        }
      ]
    },
    {
      "slug": "ai-creative-provenance-vast-c2pa",
      "title": "Provenance Is a Claim. The Tag Is the Only Thing That Ships.",
      "description": "AdCP now carries structured provenance for AI-generated creative: IPTC-aligned source types, the model that made it, how much human oversight there was, and C2PA watermark state. None of it travels inside the VAST document the player receives. What survives the handoff, and what to validate so the claim can still be reconciled.",
      "publishedAt": "2026-07-29",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Provenance",
      "tags": [
        "Provenance",
        "AdCP",
        "C2PA",
        "AI creative",
        "Compliance"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The manifest learned to describe how the ad was made",
          "paragraphs": [
            "Generative video went from demo to production inventory faster than the delivery stack adapted, and the agentic protocols are the first place the industry has written down what an AI-made creative should disclose about itself. AdCP has a provenance object that attaches to a creative manifest, to an individual asset, or to a content-standards artifact.",
            "It is more specific than a boolean. A digital source type classifies AI involvement along IPTC-aligned lines. An ai_tool object names the model, its version, and the provider. A human_oversight enum grades involvement from none, through prompt_only, selected, and edited, to directed. A declared_by object records who made the claim and in what role: creator, advertiser, agency, platform, or tool. Timestamps separate when the content was produced from when the claim was attached, which exists because claims get added retroactively for compliance.",
            "The schema also refuses to do something it easily could have done, and the refusal is the most honest sentence in it. Asserting human oversight does not by itself relieve a disclosure obligation, because the carve-outs in regulation have factual prerequisites a schema cannot evaluate. There is a separate C2PA watermark classification distinguishing a watermark cryptographically bound to a manifest from one that exists independently of any manifest."
          ]
        },
        {
          "type": "quote",
          "quote": "Provenance is a claim by the declaring party. Receiving parties should verify claims independently via their own detection tools.",
          "attribution": "AdCP provenance schema"
        },
        {
          "type": "paragraphs",
          "heading": "Now follow the claim into delivery",
          "paragraphs": [
            "A provenance object lives in the creative manifest, which is an agent-to-agent artifact. The thing a player receives is a VAST document, and VAST has no provenance element. There is no field for a model name, no field for an oversight level, no field for a C2PA manifest reference, and no field for the disclosure obligation the manifest was tracking.",
            "So the claim stops at the boundary. Downstream, three things carry identity instead: the creative identifier in Creative id and adId, the Universal Ad ID, and whatever a verification vendor sees through AdVerifications. Everything the provenance object said about how the video was produced is, from the player's point of view, unavailable.",
            "That is survivable, but only if the identifiers that would let anyone reconnect the two halves are actually present and stable. In practice they often are not. A Universal Ad ID left as the placeholder value, a creative id that changes between wrapper hops, an AdVerifications block that no player can parse: each one breaks the link between the served impression and the manifest that described it."
          ]
        },
        {
          "type": "list",
          "heading": "What has to hold for a provenance claim to mean anything at delivery",
          "items": [
            "A real Universal Ad ID, with a registry and a value that is not the unknown placeholder, consistent across every hop of the wrapper chain.",
            "Stable creative identifiers. If the id differs between the manifest, the wrapper, and the inline ad, reconciliation becomes a manual exercise.",
            "A parseable AdVerifications block with a JavaScript resource and verification parameters that survive whatever the ad server did to the tag, since this is the only channel a third party can use to observe anything at render time.",
            "Extensions that are well-formed, because vendor-specific provenance metadata, if anyone carries it, will ride there and a malformed Extensions node can take the surrounding parse with it.",
            "Media files that match what was described. A manifest asserting a generated video of a given duration and a tag serving something else is a provenance failure even if nobody used the word.",
            "Disclosure assets that actually render, when a disclosure is required. An overlay, a companion, or burned-in text is a creative element with its own failure modes, not a metadata field."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The regulatory clock is the reason this stops being theoretical",
          "paragraphs": [
            "The EU AI Act's transparency obligations under Article 50 apply from 2 August 2026. Two of its requirements bear directly on advertising creative. Providers of systems generating synthetic audio, image, video, or text must mark outputs in a machine-readable format that makes them detectable as artificially generated. Deployers of systems producing deepfake content must disclose that the content is artificially generated or manipulated, and advertising using synthetic depictions of real or realistic-looking people, places, or events is squarely in scope.",
            "Note the shape of the first obligation: machine-readable and detectable. A human-visible label alone does not satisfy it. That is precisely what C2PA-style signing and watermarking are for, and precisely what a VAST document does not currently carry.",
            "This is engineering commentary rather than legal advice, and the compliance analysis for any specific campaign depends on facts that are not in the payload. But the direction is not ambiguous. Something machine-readable will have to travel with synthetic creative, and the delivery envelope for video advertising has no slot for it yet."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What to do before the standards catch up",
          "paragraphs": [
            "The useful posture is to treat the manifest claim and the served tag as two records that must be reconcilable, and to make reconciliation cheap on purpose.",
            "Keep the provenance object with the creative in your own systems, keyed on the identifier that survives delivery, which in practice means the Universal Ad ID. Validate the tag at acceptance so the identifiers you are keying on are present and well-formed before anything serves. Re-validate what is actually being served rather than what was submitted, because endpoints change without manifests changing. And when a disclosure is required, verify it as a rendered creative element, not as a field that was set to true somewhere upstream.",
            "None of that requires a new standard. It requires the same discipline the rest of the creative stack already needs, applied to a claim that currently has nowhere to live."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What would actually close the gap",
          "paragraphs": [
            "Two additions would make provenance survive delivery. A defined place in VAST for a content credentials reference, so a player or verification vendor could locate a C2PA manifest for the media it is about to render. And a normative binding between the creative identifier in the manifest and the identifier in the served document, so the two records are joinable without a spreadsheet.",
            "Both are small, and both are the kind of thing that gets specified after enough people hit the problem. In the meantime the checkable part is the tag, which is the one artifact in this chain that every party receives and every party can parse."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the tag that carries the claim",
          "paragraph": "vastlint parses a VAST document against the version it declares and reports Universal Ad ID, verification, wrapper, and identifier problems by rule id, in the browser, from the CLI, or as an MCP tool call inside an agent loop.",
          "href": "/docs/agentic/",
          "label": "Read the agentic integration guide"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "AdCP provenance schema",
              "href": "https://github.com/adcontextprotocol/adcp/blob/main/static/schemas/source/core/provenance.json",
              "description": "digital_source_type, ai_tool, human_oversight, declared_by, declared_at, and the caveat that provenance is a claim to be verified independently.",
              "source": "AdCP"
            },
            {
              "label": "AdCP generative creative documentation",
              "href": "https://docs.adcontextprotocol.org/docs/creative/generative-creative",
              "description": "How generative assets are produced and described inside the creative protocol.",
              "source": "AdCP"
            },
            {
              "label": "EU AI Act Article 50",
              "href": "https://artificialintelligenceact.eu/article/50/",
              "description": "Transparency obligations for providers and deployers, including machine-readable marking of synthetic content and deepfake disclosure. Applies from 2 August 2026.",
              "source": "EU"
            },
            {
              "label": "C2PA specification",
              "href": "https://c2pa.org/specifications/",
              "description": "Content Credentials: signed manifests and the watermark action taxonomy AdCP references.",
              "source": "C2PA"
            },
            {
              "label": "Universal Ad ID validation",
              "href": "/docs/universal-ad-id/",
              "description": "Why the identifier that would anchor a provenance claim is so often a placeholder."
            },
            {
              "label": "OMID and AdVerifications",
              "href": "/docs/omid/",
              "description": "The one channel in VAST a third party can use to observe a creative at render time."
            }
          ]
        }
      ]
    },
    {
      "slug": "live-event-ad-insertion-vast-vmap",
      "title": "A Live Ad Break Opens on a Cue. VMAP Was Designed for a Schedule.",
      "description": "Live sports and event streaming break most of the assumptions VAST and VMAP were built on: the break is announced seconds before it starts, its length is fixed by the transport stream, every viewer hits it at once, and nothing can be retried. Where the creative side actually fails, and what to check before the next event window.",
      "publishedAt": "2026-07-29",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Live events",
      "tags": [
        "Live",
        "VMAP",
        "SSAI",
        "Ad pods",
        "CTV"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The break you cannot reschedule",
          "paragraphs": [
            "Ad insertion for a live event is the same protocol stack as ad insertion for an on-demand episode, running under conditions it was not designed for. Three of those conditions do most of the damage.",
            "The break is not on a timetable. It is announced by an SCTE-35 cue message inserted into the transport stream by the broadcast operation, usually with a short pre-roll interval before the splice point. Everything downstream, ad request, auction, VAST resolution, creative selection, transcode check and manifest manipulation, has to finish inside that interval.",
            "The break has a fixed length that the stream is going to honour whether or not you fill it. Underfill is slate or dead air on a live feed with an audience watching. Overfill means a truncated ad or a late return to content, which on a sports feed means missing the restart.",
            "And every viewer on the feed arrives at the same instant. On demand, a million viewers spread their mid-rolls across the day. Live, a million viewers hit the same cue inside the same second, so anything that is a slow leak in VOD becomes a spike with no recovery window.",
            "None of that is a VAST problem in the sense of a spec defect. VAST and VMAP do their job. But several defaults that are harmless on demand become expensive live, and they are all checkable in advance."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "VMAP describes a schedule. A live break has none.",
          "paragraphs": [
            "VMAP exists to describe where ad breaks sit inside a piece of content: a preroll, a midroll at eleven minutes, a postroll. Every AdBreak carries a required timeOffset attribute telling the player when to insert. That model assumes the breaks are known before playback starts.",
            "For a live feed they are not. The producer decides. The cue arrives. So the working pattern is not a static VMAP served once at stream start, it is a VMAP document generated per cue, or the stitcher calling the ad server directly on cue receipt with the break parameters attached to the request. The static-playlist mental model is where a lot of live integrations go wrong, because it is the one every VMAP tutorial teaches.",
            "This is what a per-cue break looks like. The timeOffset is the real presentation timestamp of the splice point, computed from the cue, and the break identity travels in breakId so the tracking can be reconciled against the broadcast log afterwards."
          ]
        },
        {
          "type": "code",
          "heading": "One AdBreak, generated when the cue arrives",
          "language": "xml",
          "code": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vmap:VMAP xmlns:vmap=\"http://www.iab.net/videosuite/vmap\" version=\"1.0\">\n  <vmap:AdBreak timeOffset=\"00:41:12.480\" breakType=\"linear\" breakId=\"cue-88421\">\n    <vmap:AdSource id=\"q3-break-2\" allowMultipleAds=\"true\" followRedirects=\"true\">\n      <vmap:AdTagURI templateType=\"vast4\">\n        <![CDATA[https://ads.example.com/live?pod=q3-break-2&dur=120&cb=[CACHEBUSTING]]]>\n      </vmap:AdTagURI>\n    </vmap:AdSource>\n    <vmap:TrackingEvents>\n      <vmap:Tracking event=\"breakStart\"><![CDATA[https://t.example.com/break?e=start&id=cue-88421]]></vmap:Tracking>\n      <vmap:Tracking event=\"breakEnd\"><![CDATA[https://t.example.com/break?e=end&id=cue-88421]]></vmap:Tracking>\n    </vmap:TrackingEvents>\n  </vmap:AdBreak>\n</vmap:VMAP>"
        },
        {
          "type": "paragraphs",
          "heading": "timeOffset has five legal forms, and none of them mean \"now\"",
          "paragraphs": [
            "The legal values are a timecode of the form hh:mm:ss or hh:mm:ss.mmm, a percentage, the keyword start, the keyword end, and a position marker of the form #m. That is the whole vocabulary. There is no value that means \"whenever the cue fires,\" which is exactly why the document has to be generated with a real timecode in it rather than templated once with a placeholder.",
            "Two things go wrong here often enough to be worth naming. The first is a placeholder that never got substituted, which produces a value the player cannot parse and a break that never opens. The second is repeatAfter on a break whose timeOffset is start or end, which is a copy-paste from a VOD template: those positions occur exactly once per playback, so the repeat has no effect and the mid-stream breaks the author thought they had scheduled do not exist.",
            "vastlint reports the first as VMAP-1.0-adbreak-timeoffset-format at error severity and the second as VMAP-1.0-repeatafter-conflict at warning severity. Both are static checks. Neither requires the event to be running."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The wrapper chain is spending a budget it did not set",
          "paragraphs": [
            "A VAST wrapper is a redirect. Each hop in the chain is a full network round trip from the resolving party to another ad server, and only after the last hop returns an InLine response does anyone have a media file to fetch.",
            "In on-demand playback that latency is absorbed. The player has buffer, the viewer is not going anywhere, and a chain of four or five hops resolves in time that nobody notices. In a live break the same chain is spending the cue pre-roll interval, which was not allocated for it and is shared with the transcode and manifest work that has to happen after the creative is chosen.",
            "vastlint's default maximum chain depth is five, which reflects what players and SSPs commonly enforce. That default is a spec-compliance ceiling, not a live-operations target. A chain that resolves reliably in a VOD test harness can exhaust a live decisioning window entirely, and the outcome is not a slow ad, it is no ad, because the stitcher has to splice something at the cue point whether or not the auction finished.",
            "The practical move before an event is to measure the chain depth and resolution time of every tag in the rotation, not to assume the number is small. Wrapper chains grow through intermediaries without anyone editing a tag."
          ]
        },
        {
          "type": "list",
          "heading": "The error codes that describe a live failure after the fact",
          "items": [
            "301: wrapper timeout or wrapper resolution failure. In live this is the signature failure. The chain did not return before the window closed.",
            "302: wrapper limit reached. The chain was longer than the resolver's configured maximum, which is often lower on a live path than on a VOD path.",
            "303: no ads after wrappers. Often a legitimate no-fill, but on a live break it still costs you a filled slot, so it belongs in the same report as the errors.",
            "401 and 402: media file not found, and media file timeout. On a live splice the CDN is being asked for the same asset by every stitcher session at once, which is precisely when a cold object is expensive.",
            "403 and 405: unsupported media, and a problem displaying a supported media file. These are the codec and container mismatches that a stitcher discovers at splice time rather than at trafficking time."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Duration is a contract with the transport stream",
          "paragraphs": [
            "The Duration element inside Linear is required, and in VOD it functions mostly as a hint: the player uses it for the countdown, the skip timer and companion scheduling, and if the media file runs a second longer than declared nothing catastrophic happens.",
            "In a live break it is a contract. The stitcher is assembling a fixed-length segment of stream from the durations it was told, and it is doing that before it has watched the file. If the declared Duration and the actual media length disagree, the assembled break does not line up with the splice point. Short means dead air at the end of the pod. Long means the return to content is late, or the last ad is cut off, which also means its complete event never fires and it is not billable.",
            "On the buy side this is why OpenRTB grew a field for exact acceptable durations rather than a range. The rqddurs array in the bid request says the seller will take a 15 or a 30 and nothing in between, and the spec text names the reason directly: the live TV use case, where non-exact durations produce dead air. A creative whose VAST declares 30 and whose file runs 28 satisfies the auction and breaks the stream.",
            "Which makes the declared Duration one of the few VAST values worth verifying against the actual asset rather than trusting, particularly for creatives that were trafficked for on-demand campaigns and later swept into a live rotation."
          ]
        },
        {
          "type": "quote",
          "quote": "On demand, a bad tag is a slow leak you can investigate tomorrow. On a live break it is one hundred percent of two minutes of inventory, and there is no tomorrow for that audience.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "There is no second request",
          "paragraphs": [
            "A live pod is a sequence of ads delivered against one break with a hard end time. If the ad in slot two fails to resolve, there is no realistic path to requesting a replacement, because the time that would take is time the break does not have. The pod either has a fallback already in hand or it plays slate.",
            "That raises the cost of ordering ambiguity. When some Ad elements in a response carry a sequence attribute and others do not, playback order is undefined, and the player or stitcher resolves it however it resolves it. In VOD that produces an occasional out-of-order pod that nobody notices. In a live break with per-slot pricing and competitive separation rules, an undefined order can put two competing advertisers back to back on a national feed.",
            "vastlint reports mixed sequencing as VAST-2.0-ad-sequence at warning severity. It is a warning because the tag still serves. Treat it as an error in a live rotation.",
            "Running a pod with a typo'd macro and mixed sequencing through the validator produces the findings below. Every one of these is static, and every one of these would be a live failure discovered during the event."
          ]
        },
        {
          "type": "code",
          "heading": "vastlint findings on a two-slot live pod",
          "language": "text",
          "code": "error    VAST-4.1-adservingid-present       InLine is missing AdServingId (x2)\nerror    VAST-4.0-universaladid-present     Creative is missing UniversalAdId (x2)\nwarning  VAST-2.0-ad-sequence               ordering across the pod is ambiguous\nwarning  VAST-2.0-linear-tracking-quartiles no quartile tracking events (x2)\nwarning  VAST-2.0-macro-unknown             [CACHEBUSTNG] is not an IAB macro\ninfo     VAST-4.1-mezzanine-recommended     no Mezzanine; stitchers may reject (x2)\ninfo     VAST-2.0-adsystem-no-version       AdSystem has no version attribute (x2)"
        },
        {
          "type": "paragraphs",
          "heading": "Every viewer arrives in the same second",
          "paragraphs": [
            "The macro finding in that list is the one whose cost scales with the audience. A cachebusting macro with a typo in it is never substituted, so the literal token stays in the URL and every request from every device is byte-identical.",
            "On demand, identical tracking URLs arriving over hours mostly still get counted, because they are separated in time and by IP. On a live break they arrive as one burst of identical requests to the same endpoint, which is the exact traffic shape that caches, proxies and dedupe logic are built to collapse. The impressions do not fail loudly. They are absorbed, and the discrepancy surfaces days later as a reconciliation argument with no evidence trail.",
            "The same reasoning applies to any macro the pipeline is supposed to expand and does not. vastlint reports unrecognised tokens as VAST-2.0-macro-unknown, lowercase macro names as VAST-2.0-macro-lowercase, and unencoded macros inside a URI parameter as VAST-2.0-macro-uri-unencoded. In a live context these stop being hygiene findings and become measurement findings.",
            "Worth noting that server-side insertion changes who expands the macro in the first place. In a fully server-side path the beacons fire from the stitcher's data centre, so the IP and user agent on the tracker belong to the stitcher rather than the viewer, and any macro the player would normally have filled has to be filled by the stitcher instead."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The mezzanine finding is not decoration",
          "paragraphs": [
            "The Mezzanine element carries a high-quality source file intended for transcoding rather than direct playback, and vastlint reports its absence at info severity with the note that ad-stitching servers may reject the tag in CTV and SSAI contexts.",
            "For client-side VOD that severity is right. For a live stitched break it understates the risk. A stitcher needs a rendition that matches the encoding profile of the content stream so the splice is seamless, and if the tag offers only renditions that do not match, the platform either transcodes at insertion time, which costs part of the window, or declines the creative. Neither outcome shows up as a VAST error. It shows up as a slot that filled with something else.",
            "Live is the case where trafficking a mezzanine is worth the storage, and where the info-level finding deserves to be promoted to a gate in whatever check runs before a rotation goes live."
          ]
        },
        {
          "type": "list",
          "heading": "Before the next live window",
          "items": [
            "Validate the generated VMAP, not the template. The bug is almost always an unsubstituted timeOffset or a repeatAfter inherited from a VOD playlist, and both are invisible in the template.",
            "Measure wrapper chain depth and resolution time for every tag in the live rotation. The compliance ceiling is five hops; the live budget is whatever the cue pre-roll interval leaves after transcode and manifest work.",
            "Verify declared Duration against the actual media length for any creative entering a live pod, especially creatives promoted from an on-demand campaign.",
            "Require a Mezzanine, or confirm with the stitching platform that your renditions match its encoding profile. Do this before the event, not from the incident channel during it.",
            "Treat mixed sequencing across the pod as a blocking error rather than a warning, because undefined ordering plus competitive separation rules is a client conversation.",
            "Sweep every URL in the rotation for unknown, lowercase and unencoded macros. Burst traffic is where deduplication eats identical requests.",
            "Validate what the stitcher emits, not only what you author. The tag that runs during the break has been rewritten at least once on its way there."
          ]
        },
        {
          "type": "cta",
          "heading": "Check a live rotation before the cue fires",
          "paragraph": "Paste a VAST tag or a generated VMAP document into the validator and it reports the wrapper, duration, macro, sequencing and mezzanine findings with the spec reference and fix guidance for each. It runs locally in the browser and nothing is stored.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "VMAP 1.0.1 specification",
              "href": "https://www.iab.com/guidelines/digital-video-multiple-ad-playlist-vmap/",
              "description": "The AdBreak, AdSource and TrackingEvents definitions quoted here, including the legal timeOffset forms.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "SCTE 35: Digital Program Insertion Cueing Message",
              "href": "https://www.scte.org/standards/library/catalog/scte-35-digital-program-insertion-cueing-message/",
              "description": "The cue message that opens a live break, and the source of the pre-roll interval the whole ad decisioning path has to fit inside.",
              "source": "SCTE"
            },
            {
              "label": "SSAI rewrites your VAST. Validate what comes out, not what went in.",
              "href": "/blog/ssai-vast-stitch-time-failures",
              "description": "The companion piece on what a stitcher does to a tag between authoring and playback, and where to validate in that pipeline.",
              "source": "vastlint"
            },
            {
              "label": "VMAP validation rules",
              "href": "/docs/vmap/",
              "description": "Every VMAP rule vastlint checks, with severities and examples.",
              "source": "vastlint"
            },
            {
              "label": "Wrapper chains and depth limits",
              "href": "/guides/vast-wrapper-chains/",
              "description": "How chains grow, what enforces the ceiling, and how to measure resolution time.",
              "source": "vastlint"
            },
            {
              "label": "VAST error codes",
              "href": "/docs/vast-error-codes/",
              "description": "The 301, 302, 303, 401, 402, 403 and 405 codes referenced above, with the causes behind each.",
              "source": "vastlint"
            },
            {
              "label": "Live event ad insertion is a burst, not a stream",
              "href": "https://rtblint.org/blog/live-event-ad-insertion-openrtb/",
              "description": "The buy-side half of the same break: which OpenRTB fields describe live content, why rqddurs exists, and the field that changed meaning in June 2026.",
              "source": "rtblint"
            }
          ]
        }
      ]
    },
    {
      "slug": "ad-format-guidelines-v2-mediafile-claims",
      "title": "The Video Encoding Guidelines Got Their First Rewrite Since 2022. VAST Only Carries the Claim.",
      "description": "Two documents were finalized on 22 July 2026. The signaling one got the coverage. The other, Ad Format Guidelines for Digital Video and CTV v2.0, sets the bitrate ladder, the codec floor, the loudness target and the mezzanine rules, and VAST declares conformance to all of it without proving any of it. What the XML can settle, and what needs the file.",
      "publishedAt": "2026-07-26",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Standards",
      "tags": [
        "Ad Format Guidelines",
        "MediaFile",
        "Mezzanine",
        "CTV",
        "Validation"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The other document that shipped on 22 July",
          "paragraphs": [
            "Two documents came out of the CTV Ad Portfolio process on the same day. The signaling guidance is the one that got written about, including here: it defines how a pause ad or a squeezeback gets traded, and the VAST 4.4 draft schema landed alongside it. The second document is Ad Format Guidelines for Digital Video and CTV v2.0, and it is the first substantial revision of that guidance since June 2022.",
            "It is a different kind of document. Signaling describes the transaction. The guidelines describe the bytes: which codec, which bitrate at which resolution, how loud, what the mezzanine has to be. Produced by the Ad Format Hero Taskforce with contributions from Disney, Google, NBCUniversal and Magnite, it is the closest thing the industry has to a delivery contract for a video ad file.",
            "VAST sits between the two and carries neither. What VAST carries is a set of attributes that assert what the file is. The player reads those attributes, picks a rendition, and starts playback. Nothing between the transcode and the screen checks whether the assertion is true."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What v2.0 actually specifies",
          "paragraphs": [
            "Worth reading in full if you own an encoding pipeline, because most of the numbers moved. The ready-to-serve ladder expanded from three options to four, with a dedicated CTV and HD column, and the ranges are now split by environment rather than given as single values."
          ]
        },
        {
          "type": "list",
          "heading": "The numbers to pin to your transcode config",
          "items": [
            "Ready-to-serve H.264 ladder: 640x360 at 1.5 to 3 Mbps, 854x480 and 960x540 at 2 to 4 Mbps, 1280x720 at 2 to 5 Mbps, 1920x1080 at 4 to 10 Mbps, 3840x2160 at 15 to 30 Mbps. The lower end of each range is for online video, web and mobile. The upper end is for CTV.",
            "Video codec: H.264 (AVC) High Profile is required. H.265/HEVC, VP9 and AV1 are optional and primarily CTV.",
            "Audio: AAC-LC required at 128 to 192 kbps stereo, 48 kHz preferred and 44.1 kHz acceptable. Dolby Digital Plus 5.1 is optional for CTV at 256 to 384 kbps.",
            "Loudness: -24 LKFS plus or minus 2 under ATSC A/85 in the US, -23 LUFS plus or minus 1 under EBU R128 in the EU, true peak at or below -6 dBTP.",
            "Mezzanine: .mov preferred over .mp4, Apple ProRes preferred with DNxHD and DNxHR accepted, native resolution with no upscaling, 8-bit minimum and 10-bit preferred, PCM audio, and no leaders or slate.",
            "Frame rates 23.976, 24, 25, 29.97, 30, 50, 59.94 and 60. Aspect ratios 16:9, 1:1, 9:16 and 2.39:1.",
            "Companion creative around 200 kB for most ads, static display under 350 kB."
          ]
        },
        {
          "type": "quote",
          "quote": "In version 4.x, a single VAST tag identifies all four file versions outlined in this document necessary for smooth ad playback experience.",
          "attribution": "Ad Format Guidelines for Digital Video and CTV, v2.0"
        },
        {
          "type": "paragraphs",
          "heading": "That sentence is the whole problem",
          "paragraphs": [
            "The guidelines nominate VAST as the place where conformance to all four renditions is expressed. So the XML is where an ad server, an SSAI stitcher and a player each learn what they are about to fetch. And every one of those attributes is an unverified claim.",
            "A MediaFile declares delivery, type, width, height, either bitrate or a minBitrate and maxBitrate pair, and in 4.1 and later a codec and a fileSize. Player selection logic is built directly on those numbers: pick the rendition closest to the display, under the bandwidth ceiling, in a supported container. If the numbers are wrong, the player does not fail, it selects wrong. A file declared at 1920x1080 and 800 kbps will be chosen for a living-room screen and will look like it was chosen for a phone.",
            "The failure mode is the one that makes CTV expensive: nothing errors. The impression bills. The discrepancy shows up weeks later in a quality conversation with no evidence attached, because the only shared record of what the file was supposed to be is a PDF and an XML attribute nobody checked."
          ]
        },
        {
          "type": "code",
          "heading": "A declaration that no player will reject and no guideline would pass",
          "language": "xml",
          "code": "<MediaFiles>\n  <MediaFile delivery=\"progressive\" type=\"video/mp4\"\n             width=\"1920\" height=\"1080\" bitrate=\"800\" codec=\"avc1.640028\">\n    <![CDATA[https://cdn.example.com/spot-1080p.mp4]]>\n  </MediaFile>\n</MediaFiles>"
        },
        {
          "type": "paragraphs",
          "paragraphs": [
            "That fragment is structurally valid VAST. It passes an XSD. It will play. It is also 800 kbps at 1080p, against a guideline range of 4 to 10 Mbps for that resolution, and it is the only rendition offered, so a CTV player has nothing better to fall back to and a mobile player has nothing lighter. There is no Mezzanine, so an SSAI platform has nothing to transcode from and will either reject the ad or re-encode the already-compressed rendition.",
            "Three separate guideline violations, all of them legible from the XML alone, none of them a VAST spec error."
          ]
        },
        {
          "type": "list",
          "heading": "What the XML can settle on its own",
          "items": [
            "Declared bitrate against declared dimensions. A 1080p rendition claiming 800 kbps, or a 360p rendition claiming 12 Mbps, is either a bad transcode or a bad declaration, and both are worth failing a build over.",
            "Whether a ladder exists at all. One rendition means no adaptive choice for any player on any connection. The guidelines expect four ready-to-serve versions.",
            "Mezzanine presence and completeness. vastlint raises VAST-4.1-mezzanine-recommended when MediaFiles has no Mezzanine, which ad-stitching servers reject in CTV and SSAI contexts, and VAST-4.1-mezzanine-delivery, -type, -width and -height when the element is there but underspecified.",
            "Bitrate declaration coherence. VAST-3.0-minmaxbitrate-pair catches a minBitrate without its maxBitrate, and VAST-3.0-bitrate-conflict catches a file declaring both a fixed bitrate and a range, which leaves the player to guess which one is real.",
            "The structural floor. VAST-2.0-mediafile-delivery, -type and -dimensions cover the attributes a selection algorithm cannot work without, and VAST-2.0-mediafile-delivery-enum catches a delivery value that is neither progressive nor streaming.",
            "Transport. VAST-2.0-mediafile-https flags a media file on plaintext HTTP, which mixed-content policy blocks outright on secure inventory regardless of how good the encode is.",
            "Aspect ratio sanity. Declared width and height that reduce to none of 16:9, 1:1, 9:16 or 2.39:1 will be letterboxed or cropped by somebody downstream, and which one you get is not specified anywhere."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the XML cannot settle, and pretending otherwise helps nobody",
          "paragraphs": [
            "A VAST validator reads XML. It does not open the mp4. Four of the requirements in v2.0 are invisible to it, and they are not minor ones.",
            "Loudness is the obvious case. The -24 LKFS target exists because viewers reach for the remote when an ad is louder than the programme, and nothing in a VAST document says how loud the file is. Codec profile is the second: codec=\"avc1.640028\" claims High Profile at Level 4.0, and an encoder that actually emitted Main Profile produces the same attribute string with a different reality. Bit depth and the no-slate rule for mezzanines are the other two.",
            "Those need the asset. The honest split is to run declaration checks in CI, where they are free and catch the majority of what actually breaks, and probe the file once at creative ingest, where it is cheap because it happens per creative rather than per impression."
          ]
        },
        {
          "type": "code",
          "heading": "The ingest-time probe the XML cannot replace",
          "language": "bash",
          "code": "# what the file actually is\nffprobe -v error -select_streams v:0 \\\n  -show_entries stream=codec_name,profile,width,height,bit_rate,r_frame_rate \\\n  -of json spot-1080p.mp4\n\n# integrated loudness and true peak, against -24 LKFS / -6 dBTP\nffmpeg -i spot-1080p.mp4 -af ebur128=peak=true -f null - 2>&1 | tail -20"
        },
        {
          "type": "paragraphs",
          "heading": "Why this lands now rather than in a quarter",
          "paragraphs": [
            "The six CTV Ad Portfolio formats change the shape of the creative. A pause ad can now carry video rather than a JPEG, an overlay occupies a corner rather than the frame, a squeezeback shares the screen with resized content. Each of those has different encoding implications, and the guidelines were rewritten in the same cycle for exactly that reason.",
            "At the same time the buying side is being automated. An agentic buyer negotiating a pause ad will not open the tag and eyeball the renditions, and the format signal it trades on says which format was bought, not whether the file behind it conforms to the guideline that governs that format. The gap between the signal and the asset is the gap a validator exists to close.",
            "None of this requires waiting for VAST 4.4 to be published. Every check above works against 4.0 through 4.3 tags in production today."
          ]
        },
        {
          "type": "list",
          "heading": "The audit worth running this week",
          "items": [
            "Pull a sample of live tags and list every declared bitrate against its declared resolution. Anything outside the v2.0 range for its tier is a finding, in either the encode or the declaration.",
            "Count renditions per creative. Anything shipping one MediaFile to CTV inventory is shipping no fallback.",
            "Check for Mezzanine on every tag that reaches an SSAI path, and confirm delivery, type, width and height are all present when it is.",
            "Grep for http:// in media file URLs. It is still there more often than anyone expects.",
            "Add an ffprobe and ebur128 pass to creative ingest for the four things the XML cannot see, and record the result next to the tag so a discrepancy conversation has evidence in it."
          ]
        },
        {
          "type": "cta",
          "heading": "Check what your tag declares",
          "paragraph": "Paste a tag into the validator to see the MediaFile and Mezzanine findings with the spec reference and fix guidance for each. It runs locally in the browser and nothing is stored.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "Ad Format Guidelines for Digital Video and CTV",
              "href": "https://github.com/InteractiveAdvertisingBureau/Ad-Format-Guidelines-for-Digital-Video-CTV",
              "description": "The v2.0 document with the ready-to-serve ladder, codec, audio, loudness and mezzanine specifications quoted above. Finalized 22 July 2026 after a second comment round closed 16 July.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "CTV Ad Portfolio",
              "href": "https://iabtechlab.com/standards/ctv-ad-portfolio/",
              "description": "The programme both documents came out of, including the signaling guidance finalized the same day.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Mezzanine files in VAST",
              "href": "/docs/mezzanine/",
              "description": "What the element requires, why SSAI platforms reject tags without one, and the rules that cover it.",
              "source": "vastlint"
            },
            {
              "label": "A pause ad used to be a JPEG. VAST 4.4 changes that.",
              "href": "/blog/vast-4-4-draft-schema-ctv-ad-portfolio",
              "description": "The signaling half of the 22 July release, and the draft schema that landed with it.",
              "source": "vastlint"
            },
            {
              "label": "SSAI rewrites your VAST",
              "href": "/blog/ssai-vast-stitch-time-failures",
              "description": "Why the mezzanine requirement matters at stitch time, and what to validate on the way out.",
              "source": "vastlint"
            },
            {
              "label": "The revenue math of broken VAST",
              "href": "/blog/vast-failures-revenue-math",
              "description": "What silent delivery failures cost at CTV scale, which is the case for gating on any of this.",
              "source": "vastlint"
            },
            {
              "label": "ATSC A/85 and EBU R128",
              "href": "https://tech.ebu.ch/docs/r/r128.pdf",
              "description": "The loudness standards the guidelines defer to for the US and EU targets.",
              "source": "EBU"
            }
          ]
        }
      ]
    },
    {
      "slug": "vast-4-4-draft-schema-ctv-ad-portfolio",
      "title": "A Pause Ad Used to Be a JPEG. VAST 4.4 Changes That.",
      "description": "The IAB CTV Ad Portfolio signaling guidance was finalised on 22 July 2026, and the VAST 4.4 draft schema alongside it rewrites a part of the spec that had barely moved since 2008. What changed, what it does to pause ad economics at $25 to $40 CPM, and how to treat each source.",
      "publishedAt": "2026-07-25",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Standards",
      "tags": [
        "VAST 4.4",
        "CTV Ad Portfolio",
        "AdCOM",
        "SIMID",
        "Validation"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Two documents, one process",
          "paragraphs": [
            "On 17 July a file called vast_4.4.xsd landed in the IAB Tech Lab VAST repository, from a branch called 4.4Development, in a pull request titled \"CTV Ad Portfolio Updates.\" Five days later, on 22 July, the CTV Ad Portfolio signaling guidance was finalised, after a comment period that closed 5 June.",
            "Both matter, and they sit at different points in the same process. The signaling guidance is a finished standard you can build against today. The schema is explicitly labelled a working draft, in its own annotation: \"IAB VAST (Video Ad Serving Template), Version 4.4 - DRAFT for working group discussion.\"",
            "That is a normal and healthy state for a spec still being worked through, and it is the right label. It also means tooling should treat the two sources differently, which is the decision this post is about."
          ]
        },
        {
          "type": "image",
          "src": "/blog/img/vast-4-4-changes.png",
          "alt": "Diagram of the VAST 4.4 changes. The top two thirds show the six CTV Ad Portfolio formats as screen layouts with their signal values: Pause, Screensaver, Overlay, Squeezeback and In-Scene carry AdCOM plcmt 5 to 9 with their pos and playbackmethod values, and Menu is drawn separately because it transacts through the OpenRTB Native object and does not use the NonLinear model, carrying its video as a VAST tag inside video.vasttag. Below that, the NonLinear content model before and after: 4.3 carried resource children, AdParameters and click tracking, while 4.4 adds MediaFiles, Duration, NonLinearCustomClick and Icons on top of those. A closing note covers the typed AdCOM children on Extension and the four QR children on CreativeExtension. The footer states that the signaling guidance is final while the 4.4 XSD is a working-group draft, and that the guidance's own examples still declare version 4.2.",
          "width": 1440,
          "height": 1800,
          "caption": "The six CTV Ad Portfolio formats and the signals that address them, the NonLinear content model before and after, and the typed Extension children that carry bid-request context into the creative.",
          "credit": "Source: IAB Tech Lab CTV Ad Portfolio signaling implementation guidelines, VAST 4.4 draft XSD and AdCOM 1.0. The specification is IAB Tech Lab's. Diagram by vastlint.org, an independent open-source project, not affiliated with or endorsed by IAB Tech Lab."
        },
        {
          "type": "paragraphs",
          "heading": "Why a pause ad schema is worth two days of anyone's time",
          "paragraphs": [
            "US CTV ad spend is heading for roughly $38 billion in 2026, up from about $33 billion last year. This is also the year the CTV upfront, at $17.73 billion, passes primetime linear TV upfront at $16.98 billion for the first time. The pivot everyone forecast is arriving on schedule.",
            "Almost all of that spend is pre-roll and mid-roll. Interruptive inventory. And ad load is the one lever streamers cannot keep pulling, because subscribers notice and subscribers leave.",
            "The six formats in the CTV Ad Portfolio are the alternative. Pause, Screensaver, Overlay, Squeezeback, In-Scene and Menu monetise moments that were previously worth nothing: the viewer hitting pause, the idle home screen, the lower third during play. New inventory that adds no interruption at all.",
            "The pricing backs that up. Hulu pause ads reportedly clear in the $25 to $40 CPM range, which puts them alongside standard programmatic premium AVOD at $25 to $45. A pause ad clears at roughly what a mid-roll clears at, on inventory that costs the publisher nothing in viewer tolerance.",
            "Until now, every one of these formats ran on a bespoke integration. Publisher by publisher, custom fields, custom creative specs, no programmatic scale. That is the problem the Ad Format Hero initiative set out to fix, and it is a genuinely good piece of standards work: hundreds of format submissions from dozens of companies, sorted down to six that cover most of the market. The stated design goal tells you a lot about the care that went in: \"no one should be able to accidentally purchase a pause ad.\" Buyers opt in deliberately."
          ]
        },
        {
          "type": "quote",
          "quote": "The signaling guidance is a finished standard. The schema is still in working-group discussion. Good tooling gives each of those a different amount of weight.",
          "attribution": "vastlint standards note"
        },
        {
          "type": "paragraphs",
          "heading": "The XML change that makes it possible",
          "paragraphs": [
            "Going through the diff, the thing that stands out is how long NonLinearAds sat untouched. Seventeen years, essentially unchanged since VAST 2.0.",
            "Before this, a pause ad was a JPEG. That was the whole vocabulary: one StaticResource, an iframe, or an HTML blob. No video, no duration, and therefore no quartile tracking.",
            "The 4.4 draft gives NonLinear the same MediaFiles container Linear has always had, holding MediaFile, Mezzanine, InteractiveCreativeFile and ClosedCaptionFiles. Video and cinemagraph assets in a pause slot. Duration, so quartiles actually fire. Icons under NonLinearAds for an AdChoices disclosure. And NonLinearCustomClick, missing from every published XSD since 3.0.",
            "The Duration change matters more than it looks. Without it there is no quartile tracking and no overlayViewDuration, which means a buyer cannot verify how long the ad was on screen. Selling a $35 CPM against a format with no duration measurement is a hard conversation."
          ]
        },
        {
          "type": "code",
          "heading": "The new NonLinear, with the fallback that keeps it renderable",
          "language": "xml",
          "code": "<NonLinear width=\"1920\" height=\"1080\">\n  <Duration>00:00:15</Duration>\n  <MediaFiles>\n    <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n      <![CDATA[https://cdn.example.com/pause-fallback.mp4]]>\n    </MediaFile>\n    <InteractiveCreativeFile type=\"text/html\" apiFramework=\"SIMID\">\n      <![CDATA[https://cdn.example.com/pause-simid.html]]>\n    </InteractiveCreativeFile>\n  </MediaFiles>\n</NonLinear>"
        },
        {
          "type": "paragraphs",
          "heading": "Ship a fallback or lose the impression",
          "paragraphs": [
            "The split between MediaFile and InteractiveCreativeFile is the part worth flagging to anyone building creative for these slots. MediaFile is a renderable asset. InteractiveCreativeFile is a separate interactive layer that needs the player to execute SIMID. If the player cannot run SIMID it renders the MediaFile instead. If there is no MediaFile, it fires the error URI and the impression is gone.",
            "SIMID support across CTV devices is nowhere near universal, and there is no credible public number for how far it reaches. You do not need one to do the arithmetic. At a $30 pause CPM, every percentage point of your device base that cannot execute SIMID and has no fallback to render is 30 cents per thousand impressions you never see, with nothing in your logs to explain it. On a hundred million monthly pause impressions, one percent is $30,000 a month. Five percent is $150,000.",
            "The guidance spells the fallback rule out explicitly, which reads like the working group anticipating exactly this failure and heading it off."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Three integers that change what publishers can sell",
          "paragraphs": [
            "Most of this release is plumbing. One part is not, and it is three new AdCOM Creative Attributes describing motion: 21 Static Visual, 22 Limited Motion (Cinemagraph), 23 Full-Motion Video.",
            "Consider what a publisher could express before. MIME types and protocols describe what a placement can decode. Nothing described what experience it expects. A streamer whose pause slot renders an MP4's first frame as a still image, or one designed for subtle cinemagraph motion rather than full video, had two options: block MP4 entirely and lose every buyer who would have complied, or accept motion creative and hope.",
            "Now the publisher sets battr: [22, 23] to block motion while still accepting MP4 delivery, and the DSP declares what it actually sent with attr. Both sides can check. That opens up demand that was previously unbuyable on those placements, and if you are on the sell side it is the piece worth implementing first."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why a VAST element now carries bid-request values",
          "paragraphs": [
            "VAST elements do not normally carry OpenRTB enumerations. In 4.4 they do, and the reason becomes obvious once you follow where the tag ends up.",
            "The VAST response outlives the bid object. An SSAI stitcher or a measurement vendor sitting downstream of the auction never sees the bid, only a creative. Without the format context it has no way to know whether it is about to render a fullscreen pause ad or a lower-third overlay, and no way to verify the creative matches what was bought. So the DSP echoes the context back into the creative, one signal per Extension, marked ext=\"adcom\".",
            "Given how much CTV inventory now moves through server-side stitching, that is the pragmatic call."
          ]
        },
        {
          "type": "code",
          "heading": "The signal round-trip",
          "language": "xml",
          "code": "<Extensions>\n  <Extension type=\"plcmt\" ext=\"adcom\"><plcmt>7</plcmt></Extension>\n  <Extension type=\"pos\" ext=\"adcom\"><pos>14</pos></Extension>\n  <Extension type=\"playbackmethod\" ext=\"adcom\"><playbackmethod>2</playbackmethod></Extension>\n  <Extension type=\"attr\" ext=\"adcom\"><attr>23</attr></Extension>\n</Extensions>"
        },
        {
          "type": "list",
          "heading": "The values, since the guidance spreads them across four tables",
          "items": [
            "plcmt gains 5 Pause, 6 Screensaver, 7 Overlay, 8 Squeezeback, 9 In-Scene. Values 1 to 4 predate the portfolio.",
            "playbackmethod gains 8 and 9 for Pause with sound on and off, 10 and 11 for Screensaver. Overlay, Squeezeback and In-Scene reuse the existing 1 and 2.",
            "pos extends past the old 0 to 7 ceiling: 7 and 8 for fullscreen and partial Pause and Screensaver, 5/9/10/14/15 for Overlay geometry, 11/12/13/16/17 for Squeezeback layouts. Highest value in the document is 17.",
            "attr gains the three motion attributes above, 21 through 23."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "QR codes get a standard, and the timing is interesting",
          "paragraphs": [
            "Pause and screensaver slots are the obvious home for a QR code. The viewer is not mid-content, the remote is in hand, and there is no rush. The draft adds four typed elements for scan URL, image URL, position and size.",
            "What makes the timing interesting is that eMarketer's Industry KPIs reported CTV QR scan rates falling sharply through Q4 2025, while survey work still puts roughly three quarters of viewers willing to scan a relevant TV QR code. If people are willing but scan rates are dropping, execution is the problem: codes too small, badly placed, on screen too briefly, in slots where nobody is holding a phone.",
            "Standardising position and size in the creative payload is a sensible response, and it is the kind of thing that only gets fixed once it is machine-readable. There is a subtlety worth knowing about: Icon types its xPosition and yPosition as vastIntegerOrPercent_type, so xPosition=\"120\" is valid there and has been for years. QrCodePosition types the same-named attributes as vastPercent_type. CTV screens vary too much in resolution for pixels to mean anything, so percentages are clearly the right choice, but anyone generating QR blocks by copying existing icon code will produce something that looks fine and is not."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "How we decided to treat the draft",
          "paragraphs": [
            "Because the schema is still in discussion, there are two places where vastlint waits rather than enforces. Neither is a problem with the draft; both are the kind of detail that gets settled during working-group discussion.",
            "The draft is scoped to the CTV work. Some 4.2 elements are not carried over: AltText, BlockedAdCategories, Expires, IconClickFallbackImage and IconClickFallbackImages. Nothing in the CTV Ad Portfolio guidance touches any of them, so we read their absence as scope rather than deprecation. vastlint models 4.4 as 4.3's content model plus the additions, and does not derive removals from a document still in progress.",
            "The draft is also stricter on Extension than 4.2, making @type required and restricting custom children to the ##other namespace. In 4.2, type is optional and custom children use processContents=\"skip\". Enforcing the stricter form today would flag a lot of deployed vendor extensions, so we are holding off until the schema settles."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Three example typos, contributed back",
          "paragraphs": [
            "Working through the guidance turned up three small things in its example XML: a Screensaver sample with an unbalanced closing tag, an Overlay sample carrying attr 20 where the document defines 21 through 23, and a template still reading version=\"INSERT VAST VERSION\".",
            "Typos in sample markup, nothing structural, and a decent argument for why validators exist. We sent them upstream so they get cleaned up. Worth knowing if you are copying markup out of that document, which most implementers will be."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Keep 4.2 or 4.3 in your version attribute for now",
          "paragraphs": [
            "This is the practical takeaway, and it is the opposite of what you would expect from a new version number.",
            "Every VAST example in the final guidance declares version=\"4.2\". Not one declares 4.4. They use the new NonLinear content model while sitting on a version string the ecosystem has supported since 2019, which matches the deployed base. A player that version-gates strictly will reject a 4.4 tag outright, so you would gain nothing by moving early.",
            "Build the new content model. Keep the old version string."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What we shipped",
          "paragraphs": [
            "vastlint now recognises version=\"4.4\" and validates the CTV Ad Portfolio content model, with 17 new rules in a dedicated category. The catalog is 212 rules.",
            "The severity design follows the lifecycle split at the top of this post. Rules from the finalised guidance carry normal weight. Rules from the draft schema alone stay at warning or info, so the tooling stays useful without getting ahead of the working group. The only errors are constructs malformed under any reading of any version: a non-integer AdCOM payload, a QR position in pixels.",
            "The new NonLinear content model is accepted on any VAST 4.x document rather than only on 4.4, because the guidance's own examples ship it on 4.2 tags. VAST 3.0 and below are unchanged, with a regression fixture guarding it. When 4.4 finalises we re-examine a handful of severities and the tooling catches up in an afternoon."
          ]
        },
        {
          "type": "cta",
          "heading": "Check a CTV Ad Portfolio tag",
          "paragraph": "Paste a pause, overlay or squeezeback tag into the validator and see which of the 17 CTV Ad Portfolio rules fire, with the spec reference and fix guidance for each. Nothing is stored.",
          "href": "/validate/",
          "label": "Open the VAST validator"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "VAST 4.4: what actually shipped",
              "href": "/docs/vast-4-4/",
              "description": "The full technical breakdown, including every content-model change and where the draft schema is wrong.",
              "source": "vastlint"
            },
            {
              "label": "VAST 4.3 to 4.4 migration guide",
              "href": "/docs/vast-4-3-to-4-4/",
              "description": "Element-by-element changes with a migration checklist.",
              "source": "vastlint"
            },
            {
              "label": "CTV Ad Portfolio",
              "href": "https://iabtechlab.com/standards/ctv-ad-portfolio/",
              "description": "The IAB Tech Lab standard, finalised 22 July 2026 after public comment closed 5 June.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Ad Format Guidelines for Digital Video and CTV",
              "href": "https://github.com/InteractiveAdvertisingBureau/Ad-Format-Guidelines-for-Digital-Video-CTV",
              "description": "The signaling implementation guidelines, including the format-to-signal reference table and the SIMID declaration pattern.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST repository",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast",
              "description": "Where vast_4.4.xsd landed on 17 July 2026, via PR #57 from the 4.4Development branch.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "CTV ad market will more than double by end of 2026",
              "href": "https://www.emarketer.com/content/ctv-ad-market-will-more-than-double-by-end-of-2026",
              "description": "The forecast behind the $38 billion figure and the year CTV upfront spend passes primetime linear.",
              "source": "eMarketer"
            },
            {
              "label": "CTV QR code scan rates fell sharply in Q4 2025",
              "href": "https://www.emarketer.com/content/industry-kpis--ctv-qr-code-scan-rates-fell-sharply-q4-2025",
              "description": "Context for why standardising QR geometry in the creative payload matters now.",
              "source": "eMarketer"
            },
            {
              "label": "The IAB standardized signaling for CTV's new ad formats",
              "href": "/blog/ctv-ad-portfolio-signaling-vast-validation",
              "description": "Our July piece on the signaling work while it was still in public comment.",
              "source": "vastlint"
            },
            {
              "label": "Why SIMID creatives keep failing validation in 2026",
              "href": "/blog/simid-creatives-failing-validation-2026",
              "description": "The interactive layer these formats now lean on, and how it fails.",
              "source": "vastlint"
            }
          ]
        }
      ],
      "updatedAt": "2026-08-02",
      "featured": true
    },
    {
      "slug": "vast-failures-revenue-math",
      "title": "The Revenue Math of Broken VAST: What Silent Delivery Failures Cost at CTV Scale",
      "description": "Error 102, stripped verification, and misattributed SSAI beacons are engineering problems with a revenue denominator. At 2026 CTV prices, a one percent silent failure rate on 100 million monthly impressions is real money, and the expensive inventory fails more often than the cheap kind. The unit economics, failure by failure.",
      "publishedAt": "2026-07-16",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Revenue",
      "tags": [
        "CTV",
        "Revenue",
        "CPM",
        "SSAI",
        "Measurement"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The engineering post and the P&L post are about the same event",
          "paragraphs": [
            "We recently published two engineering pieces: what happens when a player meets a VAST version it does not support, and what an SSAI stitcher does to a tag between QA and the screen. Both describe failures that are silent by construction. The ad plays, the dashboards stay green, and the missing pieces are measurement, verification, and attribution rather than pixels.",
            "This post is the translation for the people who own the number. Silent technical failures do not show up as incidents. They show up as fill rate, discrepancy write-offs, IVT credits, and CPM decay, usually one to three quarters after the engineering event that caused them. The mapping from one to the other is not mysterious. It is arithmetic."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Start with the price of one impression",
          "paragraphs": [
            "CTV inventory in 2026 trades in tiers. FAST and broad AVOD inventory clears around 15 to 25 dollars CPM. Premium AVOD runs 25 to 45 dollars. Live sports adjacency and audience-targeted buys reach 45 to 85 dollars. Divide by a thousand and a single impression is worth between 1.5 and 8.5 cents.",
            "That sounds too small to manage until you multiply by delivery volume. A mid-size streamer or FAST channel doing 100 million ad impressions a month at a blended 30 dollar CPM books 3 million dollars of monthly ad revenue. Every one percent of impressions that fails to deliver, or delivers without the metadata the price depended on, is 30,000 dollars a month, 360,000 a year. And one percent is a polite assumption: DoubleVerify's global benchmarks find that without adequate protections more than one in four CTV impressions would fail minimum criteria for fraud-free, viewable, brand-safe delivery."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure one: the slot goes empty. Visible, priced, survivable",
          "paragraphs": [
            "A hard failure, a version rejection firing error 102, a wrapper chain that times out, a media file the device cannot decode, means no ad renders. The direct cost is the clearing price of that impression, plus the degraded price of whatever backfill caught the slot after the waterfall burned a few hundred milliseconds.",
            "This is the failure finance already sees, because it has a name on the dashboard: fill rate. It is also the least dangerous failure, precisely because it is visible. An error code generates a report, a report generates a ticket, and the loss stops growing. If all your VAST problems were error 102, you would not need this article."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure two: the ad plays but the proof does not. Invisible, repriced",
          "paragraphs": [
            "The quiet version-mismatch failure strips AdVerifications, UniversalAdId, and category metadata while the video plays normally. Nothing is unfilled. What changes is the buyer's side of the ledger: the impression arrives unverifiable, the measurement vendor logs it as unmeasured, and the buyer's count diverges from yours.",
            "That divergence has two revenue consequences. The first is reconciliation: when your ad server and the buyer's measurement disagree, the invoice settles toward the buyer's number, and the gap becomes a discrepancy write-off that never appears in any error report. The second is slower and larger: inventory that persistently fails verification gets repriced. Buyers do not file tickets about your stripped OMID. Their algorithms shade bids on inventory that cannot prove itself, their allow lists quietly drop you from PMPs that require measurement, and the deal renewal comes in lower. CPM decay is the lagging indicator of silent technical failure, and by the time it is visible in the average, the cause is two quarters old."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure three: your beacons look like a bot farm. Misclassified, discounted",
          "paragraphs": [
            "The SSAI failure has the worst exchange rate of the three. When a stitcher fires tracking beacons without forwarding device context, the traffic pattern it produces, one data-center IP emitting thousands of impressions with a server user agent, is exactly what fraud detection is built to catch. The impressions were real. The classification is invalid traffic.",
            "The market context makes misclassification expensive. Pixalate's Q4 2025 benchmarks put US CTV invalid traffic at 19 percent, 21 percent globally, and DoubleVerify reported a 140 percent year-over-year surge in CTV fraud schemes in early 2026. Buyers are paying for IVT filtering and acting on it. Impressions flagged invalid are refunded or credited, and the path that produced them gets scored down as a supply source. Getting a delivery path un-flagged after a vendor has classified it is slow, manual, partner-by-partner work. The engineering fix, forwarding X-Forwarded-For and the device user agent on every server-fired beacon, costs a configuration change. The classification it prevents costs a percentage of everything the path delivers."
          ]
        },
        {
          "type": "quote",
          "quote": "Buyers do not complain about broken measurement. They reprice it. The discount arrives without a meeting, without a ticket, and without a line item saying why.",
          "attribution": "vastlint operations note"
        },
        {
          "type": "paragraphs",
          "heading": "Why the revenue-weighted failure rate is worse than the average",
          "paragraphs": [
            "Failure rates get reported per impression. Revenue does not arrive per impression, it arrives per CPM tier, and the failure modes concentrate in the expensive tiers. Live sports is the 45-to-85-dollar inventory, and it is also the most operationally hostile delivery there is: SSAI stitching under live latency, ad pods assembled seconds before air, transcodes on the fly. Premium PMP deals are the inventory that carries verification requirements, which is exactly the metadata a version downgrade strips.",
            "So the distribution of failures is correlated with price. A blended one percent error rate can hide four percent on the inventory that produces a third of revenue. If you weight your error telemetry by clearing price instead of impression count, the number that comes out is the one that belongs in a revenue conversation, and it is reliably uglier than the one in the QA report."
          ]
        },
        {
          "type": "list",
          "heading": "What to put on the revenue dashboard",
          "items": [
            "Revenue-weighted delivery failure rate: error events multiplied by the clearing price of the impression they killed, not a flat error percentage.",
            "Discrepancy percentage by partner and by delivery path, tracked monthly. A widening gap on one partner is a technical failure wearing an accounting costume.",
            "IVT classification rate by delivery path, split client-side versus SSAI. A gap between the two is beacon attribution, not audience quality.",
            "Fill rate by pod position and by tier, so a backfill cascade in premium pods is visible separately from run-of-network noise.",
            "CPM trend on verification-required deals versus open auction. If the gap narrows, buyers have stopped believing your measurement."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The asymmetry that makes prevention cheap",
          "paragraphs": [
            "Everything above is expensive on the loss side and nearly free on the prevention side. Validating a tag before it enters rotation costs milliseconds. Validating what the stitcher serves costs a scheduled job. Catching a version downgrade in CI costs a failing check in a pull request. Against a single month of one percent silent failure at CTV prices, the entire validation program pays for itself with the first incident it prevents.",
            "The engineering teams already have the tools. What they usually lack is the mandate, because the cost lands in a different department's spreadsheet. If you own the revenue number, the cheapest money you will recover this year is sitting between your QA process and your delivery path."
          ]
        },
        {
          "type": "cta",
          "heading": "Put a gate between broken tags and booked revenue",
          "paragraph": "vastlint validates tags at onboarding, in CI, and against served SSAI output, so version downgrades, stripped verification, and malformed trackers surface as failing checks instead of quarter-end discrepancies.",
          "href": "/validate/",
          "label": "Validate a VAST tag"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "CTV CPM Benchmarks 2026",
              "href": "https://www.namediaexperts.com/blog-posts/ctv-advertising-benchmarks-2026-cpm-vcr-roas",
              "description": "The 2026 tier pricing used above: FAST, premium AVOD, live sports, and audience-targeted CPM ranges.",
              "source": "NA Media Experts"
            },
            {
              "label": "Q4 2025 North America IVT and Ad Fraud Benchmarks",
              "href": "https://www.globenewswire.com/news-release/2026/03/09/3251883/0/en/Pixalate-Releases-Q4-2025-North-America-Invalid-Traffic-IVT-Ad-Fraud-Benchmarks-Connected-TV-CTV-IVT-Rate-in-United-States-at-19.html",
              "description": "US CTV invalid traffic at 19 percent, the market backdrop that makes beacon misclassification costly.",
              "source": "Pixalate"
            },
            {
              "label": "CTV Fraud Schemes Surge 140% Globally",
              "href": "https://doubleverify.com/company/newsroom/global-study-ctv-fraud-schemes-surge-140-globally",
              "description": "DoubleVerify's 2026 study on the growth of CTV fraud and the share of impressions failing minimum delivery criteria.",
              "source": "DoubleVerify"
            },
            {
              "label": "What Actually Happens When Your Player Doesn't Support a VAST Version",
              "href": "/blog/vast-version-not-supported",
              "description": "The engineering half of failure two: which metadata a version mismatch silently strips.",
              "source": "vastlint"
            },
            {
              "label": "SSAI Rewrites Your VAST. Validate What Comes Out, Not What Went In",
              "href": "/blog/ssai-vast-stitch-time-failures",
              "description": "The engineering half of failure three: macros, beacon headers, and stitch-time rewrites.",
              "source": "vastlint"
            },
            {
              "label": "Bid request quality is a revenue line",
              "href": "https://rtblint.org/blog/bid-request-quality-auction-economics/",
              "description": "The same translation exercise one layer up the stack, for the OpenRTB bid stream.",
              "source": "rtblint"
            }
          ]
        }
      ]
    },
    {
      "slug": "vast-version-not-supported",
      "title": "What Actually Happens When Your Player Doesn't Support a VAST Version",
      "description": "Error 102 is the loud failure, and it is the rare one. Most version mismatches play the ad and silently drop verification, identity, and tracking metadata instead. Where VAST version support is actually decided, what each failure mode looks like, and how to catch the quiet ones before they cost revenue.",
      "publishedAt": "2026-07-15",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "VAST versions",
      "tags": [
        "VAST versions",
        "Error 102",
        "CTV",
        "Wrappers",
        "VAST validator"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "One question, three different failures",
          "paragraphs": [
            "Ask what happens when an ad stack meets a VAST version it does not support, and most people picture an error code. That answer exists: VAST error 102, the version-not-supported signal the spec has carried since VAST 3.0. In production it is the rarest of three outcomes. The common outcomes are quieter. Either the player renders the ad and silently ignores the parts of the document it does not understand, or something upstream downgraded the tag to an older version before the player ever saw it, shedding features along the way.",
            "All three outcomes cost money. Only one of them tells you it happened. This post walks through where version support is actually decided, what each failure looks like on a real stack, and how to catch the two silent ones."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where version support is decided",
          "paragraphs": [
            "A VAST document declares its version exactly once, in the version attribute on the root VAST element. The player reads that attribute and chooses its parsing behavior from it. That is the entire in-band negotiation. There is no handshake, no capability exchange, and no fallback protocol inside VAST itself.",
            "The real negotiation happens one layer up, in OpenRTB. A video bid request lists the versions the player accepts in imp.video.protocols, using the AdCOM protocols list: VAST 2.0 is value 2, VAST 3.0 is value 3, and VAST 4.0 through 4.2 with their wrapper variants run from 7 to 14. A buyer that respects the list never sends an unsupported version. A buyer that ignores it, or a request that omits it, is how a 4.2 document arrives at a player built for 2.0.",
            "The third decision point is configuration. Ad servers and SSPs let you choose which VAST version they render out, and many default to 2.0 or 3.0 on purpose, because old versions play everywhere. Version support is therefore decided three times, by three different parties, and any one of them can create the mismatch."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The loud failure: error 102",
          "paragraphs": [
            "When a player checks the version attribute and refuses to proceed, the spec gives it error code 102: VAST version of response not supported. The player substitutes 102 into the [ERRORCODE] macro, fires the Error tracker, abandons the ad, and falls through to whatever the waterfall has next. The impression never fires, so the buyer logs a lost opportunity and the publisher logs an unfilled or refilled slot.",
            "Error 102 has one virtue: it is visible. It shows up in error reporting, ad server dashboards break it out, and both sides can see the disagreement and fix it. The fix is alignment work, either the demand side stops sending versions the player cannot read, or the player upgrades.",
            "Two neighboring codes matter for diagnosis. Error 100 is an XML parsing failure and 101 is a schema validation failure. Players without a strict version check often surface a version problem as 100 or 101 instead, when an element from a newer version trips their parser. If a partner's 100s spike right after you move to a newer VAST version, you are usually looking at a version problem wearing a parsing costume."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The quiet failure: the ad plays, the features don't",
          "paragraphs": [
            "Most modern players do not hard-reject on version. They parse the elements they know and skip the rest. Google's IMA SDK reads the version attribute and applies version-appropriate parsing across 2.0 through 4.3. Roku's RAF accepts 4.2 and 4.3 documents but silently ignores some newer fields. For players like these, an unsupported version does not fail. It degrades.",
            "The degradation pattern is consistent: the media file plays, and the money-adjacent metadata disappears."
          ]
        },
        {
          "type": "list",
          "heading": "What silently disappears when a 4.x tag meets an older parser",
          "items": [
            "AdVerifications and OMID measurement. VAST 4.1 moved verification out of Extensions into a first-class element, so an older parser never sees it. Viewability and IVT measurement vanish while the ad plays normally.",
            "UniversalAdId, added in 4.0. Creative deduplication and cross-platform frequency capping lose their key.",
            "Mezzanine, added in 4.0. SSAI stitchers lose the mastering-quality source they transcode from and fall back to whatever MediaFile survives.",
            "ClosedCaptionFiles, added in 4.2. Caption files are dropped without any accessibility warning.",
            "Category with its authority attribute. Brand safety classification quietly falls back to nothing.",
            "SIMID interactivity, formalized in 4.3. Interactive layers simply do not render, while the underlying video still plays."
          ]
        },
        {
          "type": "quote",
          "quote": "Error 102 costs you one impression and files a report about it. The quiet failure costs you measurement, verification, and dedup on every impression while the dashboards stay green.",
          "attribution": "vastlint operations note"
        },
        {
          "type": "paragraphs",
          "heading": "Wrappers multiply the mismatch",
          "paragraphs": [
            "A wrapper chain is not one VAST document. It is one document per hop, and each hop declares its own version. A 4.2 wrapper can point to a 3.0 wrapper that resolves to a 2.0 inline, and nothing in the spec forbids it. The effective feature set of the chain is the minimum of the versions along it, applied hop by hop by whatever parses each document.",
            "That has two operational consequences. Verification injected at the wrapper level survives only if the player understands the wrapper's version. And a downgrade anywhere in the chain, say an SSP re-rendering to 2.0 for compatibility, strips 4.x features for everything downstream, no matter how carefully the inline creative was authored."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why old versions still dominate",
          "paragraphs": [
            "The economics explain the state of the ecosystem. Serving VAST 2.0 or 3.0 is the lowest common denominator: it plays on everything, so nothing visibly breaks, so the integration ticket never gets opened. That is why, seventeen years after VAST 2.0 shipped, a large share of production tags still declare 2.0 or 3.0 even when the buy paid for a 4.x feature set.",
            "The asymmetry is the trap. A version rejection is an incident with an error code and an owner. Silent feature loss is invisible, so every rational participant downgrades toward compatibility, and the industry keeps trading 4.x features that are stripped before they reach glass. If you bought OMID verification or rely on UniversalAdId dedup, the version your stack actually delivers end to end is not a detail. It is whether you got what you paid for."
          ]
        },
        {
          "type": "list",
          "heading": "The playbook",
          "items": [
            "Declare the version you actually use. If the document contains 4.x elements, the root attribute must say so. IMA and other SDKs pick parsing rules from that attribute, and a 4.1 element inside a document declaring version 3.0 may be silently ignored.",
            "Know your player matrix before trafficking. IMA parses 2.0 through 4.3, RAF tops out with partial 4.2 and 4.3 handling, and every CTV platform has its own quirks. The per-platform guides on this site list what each SDK reads and drops.",
            "Populate and respect imp.video.protocols in the bid stream. The protocols list exists so this negotiation happens before the tag is sent, not after it fails.",
            "Validate what the transcoder emits, not what you authored. If an SSP, ad server, or SSAI stitcher re-renders your tag, pull the served document and validate that, because the downgrade happens between your QA and the device.",
            "Pin validation to the version you traffic and run it in CI, so a partner-side version change shows up as a failing check instead of a quarter-end revenue question."
          ]
        },
        {
          "type": "cta",
          "heading": "Check a tag against its declared version",
          "paragraph": "vastlint validates version-specific rules across VAST 2.0 through 4.3: elements that do not exist in the declared version, attributes that arrived later than the version claims, and version-illegal combinations that players resolve by silently dropping features.",
          "href": "/validate/",
          "label": "Validate a VAST tag"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "VAST 4.3 specification",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The current spec, including the version attribute contract and the error code table.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Understand VAST error codes",
              "href": "https://support.google.com/admanager/answer/4442429",
              "description": "Google Ad Manager's operational breakdown of VAST errors, including 100, 101, and 102.",
              "source": "Google"
            },
            {
              "label": "VAST Versions Compared: 2.0-4.3",
              "href": "/docs/vast-versions/",
              "description": "What each version added, the compatibility matrix, and which version to use in 2026.",
              "source": "vastlint"
            },
            {
              "label": "VAST error code reference",
              "href": "/docs/vast-error-codes/",
              "description": "Every VAST error code with causes and fixes, including the 1xx version and parsing family.",
              "source": "vastlint"
            },
            {
              "label": "VAST and OpenRTB: how the two specs meet",
              "href": "https://rtblint.org/guides/vast-and-openrtb/",
              "description": "The bid-stream side of version negotiation, including imp.video.protocols.",
              "source": "rtblint"
            }
          ]
        }
      ]
    },
    {
      "slug": "ssai-vast-stitch-time-failures",
      "title": "SSAI Rewrites Your VAST. Validate What Comes Out, Not What Went In",
      "description": "In CTV, the tag you authored is not the tag that runs. Server-side ad insertion unwraps your wrapper chain, transcodes your media, rewrites your trackers, and fires your beacons from a data center. Five stitch-time failure modes, and the points in the pipeline where validation actually prevents them.",
      "publishedAt": "2026-07-15",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "CTV delivery",
      "tags": [
        "SSAI",
        "CTV",
        "VAST macros",
        "Measurement",
        "Tracking"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The tag you authored is not the tag that runs",
          "paragraphs": [
            "Most CTV ad delivery now runs through server-side ad insertion. A stitcher sits between the ad server and the device, fetches your VAST on the server, splices the creative directly into the content stream, and hands the device one continuous video. The device may never see your XML at all.",
            "Almost all VAST QA happens on the document you built: the tag is validated at authoring time, certified with a partner, and archived in a ticket. Between that QA and the glass, the stitcher unwraps it, transcodes it, rewrites it, and often takes over firing its trackers. Each of those transformations is a place where a valid tag becomes a broken delivery, and none of them show up in the QA you did upstream."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What a stitcher actually does to your VAST",
          "paragraphs": [
            "The stitcher fetches the tag server-side and walks the wrapper chain itself, so redirect latency and depth limits play out in a data center rather than on the device. It selects a media file, or transcodes one, to match the content stream's resolution, bitrate, and codec. VAST 4.0 added the Mezzanine element for exactly this consumer: a mastering-quality source the stitcher can transcode cleanly instead of upscaling a compressed MediaFile.",
            "Then it handles tracking, in one of two modes. In client-side beaconing, the stitcher passes tracking metadata to the player SDK and the device fires events. In server-side beaconing, the stitcher fires impressions and quartiles itself on the device's behalf. Every failure mode below traces back to one of these transformations."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure one: macros nobody expanded",
          "paragraphs": [
            "VAST 4.1 standardized the macro vocabulary: [TIMESTAMP], [CACHEBUSTING], [DEVICEUA], [IFA], and the rest. In client-side playback the player expands them at fire time. In SSAI the stitcher has to do it, and the handoff is where it breaks. The classic symptom is a tracker URL that arrives at the ad server with the literal string [CACHEBUSTING] or [TIMESTAMP] still in it.",
            "Unexpanded macros are not cosmetic. A missing cache buster means intermediaries dedupe distinct impressions. A missing timestamp breaks sequential attribution. A device macro left literal means the measurement vendor receives a beacon it cannot attribute to any device class. Validate the macro syntax in every tracker URL before the tag enters a stitcher's cache, and audit served beacons for literal bracket strings after."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure two: beacons from a data center",
          "paragraphs": [
            "In server-side beaconing mode, your impression pixel fires from the stitcher's infrastructure: a cloud IP and a server user agent. To every downstream system that was built for client-fired beacons, that traffic pattern is indistinguishable from a bot farm, because mechanically it is one.",
            "IAB Tech Lab's SSAI guidance defines the fix: the stitcher forwards the original device context on every beacon, X-Forwarded-For for the device IP and X-Device-User-Agent for the device UA, plus the standardized VAST macros carrying device identity. When those headers are missing, ad servers cannot dedupe across devices, IVT filters flag the traffic, measurement vendors discard it, and CPMs follow. If you buy or sell through SSAI, beacon header forwarding is a certification item, not a nice-to-have."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure three: the schedule is not the playback",
          "paragraphs": [
            "A stitcher knows when it inserted an ad into the stream. It does not necessarily know whether the device kept playing. Pure server-side quartile firing reports what the schedule intended, not what the viewer saw: a user who backs out at second three can still generate a server-fired complete.",
            "This is why the Media Rating Council's SSAI guidance pushes measurement toward client-side confirmation, and why serious CTV pipelines run hybrid beaconing, with the device confirming playback events even when the server manages the rest. When you evaluate an SSAI partner, the question to ask is precise: which events fire from the server, which from the device, and what happens to quartiles when the session dies mid-pod."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure four: verification and interactivity go blind",
          "paragraphs": [
            "AdVerifications carries JavaScript that expects to execute in a client runtime and observe rendering. There is no browser inside a stitcher. Unless the device-side player integrates the OM SDK for CTV and executes the verification resource, OMID measurement on an SSAI path is a field in the XML and nothing else. The same applies to interactive layers: a SIMID creative needs a client player that loads it, and a stitcher that flattens the ad into the stream has nowhere to run it.",
            "The failure is contractual as much as technical. Deals get signed on measured viewability against inventory where the delivery path cannot execute the measurement. If verification matters to the buy, the SSAI path needs an explicit answer for where the verification code runs."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Failure five: the cache serves yesterday's tag",
          "paragraphs": [
            "Stitchers cache aggressively, both transcoded creatives and resolved VAST documents, because stitch-time budgets are tight. The cost is staleness: a campaign that ended, a tracker that rotated, or a creative that was replaced can keep serving from cache until eviction. If your trackers are versioned or your creatives legally time-boxed, the stitcher's cache TTL is part of your compliance surface. Ask for it in writing."
          ]
        },
        {
          "type": "list",
          "heading": "Where validation actually helps",
          "items": [
            "At creative onboarding, before the tag enters anyone's cache: full spec validation, version-appropriate structure, and macro syntax in every tracker URL.",
            "Before stitch execution: confirm a Mezzanine or transcode-suitable MediaFile exists, wrapper depth fits the stitcher's fetch budget, and every tracker is https.",
            "On the served output: pull what the stitcher actually delivers and validate that document, because unwrapping and re-rendering can drop elements your QA verified upstream.",
            "On the beacon stream: sample served beacons for literal macro brackets, missing forwarding headers, and data-center-only IPs on impression events.",
            "An Error tracker in the tag, always, so that when something does fail at stitch time, it reports instead of vanishing."
          ]
        },
        {
          "type": "cta",
          "heading": "Lint the tag at every handoff",
          "paragraph": "The CI guide covers running vastlint at onboarding, before cache insertion, and against served output, so the document that reaches the stitcher is the document you certified.",
          "href": "/docs/validate-vast-in-ci/",
          "label": "Validate VAST in CI"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "VAST Macros in SSAI Environments",
              "href": "https://iabtechlab.com/wp-content/uploads/2020/11/IABTechLab_SSAI_VAST_Macros_v1.0-Nov-2020.pdf",
              "description": "The IAB Tech Lab guidance on macro expansion and device context forwarding for server-side beacons.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Solving Tech Challenges in SSAI",
              "href": "https://iabtechlab.com/solving-tech-challenges-in-ssai-takeaways-from-recent-workshop/",
              "description": "Workshop takeaways on where SSAI implementations diverge and what standardization is still missing.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Server-side Ad Insertion and OTT Guidance",
              "href": "https://mediaratingcouncil.org/sites/default/files/Standards/083021%20SSAI%20and%20OTT%20Guidance%20%20FINAL.pdf",
              "description": "MRC's measurement requirements for SSAI delivery, including client-side confirmation.",
              "source": "Media Rating Council"
            },
            {
              "label": "VAST macros reference",
              "href": "/docs/vast-macros/",
              "description": "The standardized macro list, expansion rules, and validation checks vastlint runs on tracker URLs.",
              "source": "vastlint"
            },
            {
              "label": "Where CTV Ad Revenue Leaks: Protocol, Infrastructure, and Standards Failures",
              "href": "/blog/ctv-revenue-loss-protocol-infrastructure-standards",
              "description": "The wider map of CTV delivery loss that stitch-time failures sit inside.",
              "source": "vastlint"
            },
            {
              "label": "Why CTV VAST Tags Still Fail After QA",
              "href": "/blog/why-ctv-vast-tags-fail-after-qa",
              "description": "The upstream half of this story: why authoring-time QA misses delivery-time failures.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "ctv-ad-portfolio-signaling-vast-validation",
      "title": "The IAB Standardized Signaling for CTV's New Ad Formats. The VAST Payload Is Still Unverified.",
      "description": "IAB Tech Lab closed public comment on standardized signaling for the CTV Ad Portfolio in June 2026, adding a common way to trade Pause, Overlay, Squeeze Back, and Menu ads across AdCOM, VAST, and Native. The signal says which format was bought. It does not verify that the VAST payload conforms, and agentic buyers will trade these formats before a human reads the tag.",
      "publishedAt": "2026-07-11",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "CTV standards",
      "tags": [
        "CTV",
        "VAST validator",
        "IAB",
        "Agentic",
        "Standards"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The IAB just finished defining how CTV's new formats get bought and sold",
          "paragraphs": [
            "On June 5, 2026, IAB Tech Lab closed the public comment period on standardized signaling for its CTV Ad Portfolio. The changes are now merging into the GitHub specifications. They are not a new format spec. They are the missing trading vocabulary for formats the portfolio already named, and they touch three core standards at once: AdCOM, VAST, and the Native Ads specification.",
            "This is the concrete deliverable behind a line in the Tech Lab agentic roadmap that most people skimmed past. The roadmap committed to completing the signals for programmatic trading in OpenRTB, VAST, and SIMID by Q2 2026. The CTV Ad Portfolio signaling is a large part of what that sentence meant. Q2 is now over, and the work shipped."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the signaling actually adds",
          "paragraphs": [
            "For years, connected TV advertising meant one programmatic shape: a linear video ad that interrupts the stream, served as a VAST tag with MediaFiles and tracking. The CTV Ad Portfolio names a set of formats that do not fit that shape. Pause ads appear when the viewer stops playback. Overlay ads sit in the lower third while content keeps running. Squeeze back ads shrink the program into an L or a frame to share the screen. Menu and screensaver ads live in the platform interface, outside video playback entirely.",
            "Buyers and sellers already ran these as custom deals, trafficked by hand, because there was no standard way to say inside a bid which format was on offer. The new signaling adds that vocabulary. A seller can now declare, in a machine-readable field, that an impression is a pause ad rather than a mid-roll, and a buyer can bid on it as such. As IAB Tech Lab CEO Anthony Katsur put it, standard formats are only part of the equation, and you need a clear way to signal what is actually being bought and sold."
          ]
        },
        {
          "type": "list",
          "heading": "The formats getting a standard programmatic signal",
          "items": [
            "Pause ad: a static or video experience shown when the viewer pauses content with the remote.",
            "Overlay ad: a non-linear unit in the lower third or a corner while the program continues to play.",
            "Squeeze back ad: the program resizes into an L-shape, frame, or double box so an ad can share the screen.",
            "Screensaver ad: an OS or app-initiated experience shown during idle time.",
            "Menu ad: a unit placed in the home screen or navigation UI, outside video playback.",
            "In-scene insertion: branded elements composited into the content itself, closer to product placement than a spot."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "This lands on the agentic buying stack immediately",
          "paragraphs": [
            "Two agentic standards stacks are already in production, and both resolve a video buy to a VAST tag. IAB Tech Lab's AAMP wires OpenRTB, AdCOM, OpenDirect, and VAST together under agent interfaces. The Ad Context Protocol, now at 3.1, runs an agent-native pipeline from inventory discovery through creative production, and a video creative on that path ends as a VAST document handed to the sell side. Neither stack changes the endpoint. Every video transaction still resolves to InLine or Wrapper, MediaFiles, Impression pixels, and TrackingEvents.",
            "The new signaling changes what the agents negotiate over. A seller agent will offer a pause ad, a buyer agent will bid on it by format, and the deal will clear machine to machine without a human reading the tag. The format is no longer an implied pre-roll. It is a declared contract with its own rendering behavior, and the VAST that fulfills it has to match the declaration."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "A signal is a promise, not a proof",
          "paragraphs": [
            "Standardized signaling solves the discovery and transaction problem. It does nothing about correctness. The AdCOM or VAST field that says pause ad is an assertion by the seller. It is not a check that the delivered payload is a well-formed pause ad, or valid VAST at all. The trade can clear on a signal while the tag underneath is malformed, mis-shaped for the format, or wrapped in a chain that drops the very signal that sold it.",
            "This is the same gap the agentic protocols already carry, now widened by new surface. The protocol layer moves deal state and format signals between agents. The correctness of what actually ships is out of scope for the signaling, and out of scope for AAMP and AdCP alike. A new format vocabulary means new ways for the payload to disagree with the promise."
          ]
        },
        {
          "type": "list",
          "heading": "Where the new formats break at the payload",
          "items": [
            "A tag signaled as a non-linear pause or overlay ad but structured as a standard linear InLine, so the player renders it in the wrong slot or not at all.",
            "Interactive overlay and squeeze back formats that rely on SIMID for remote or QR interaction, a component with a documented history of failing validation.",
            "MediaFiles whose dimensions, delivery, or apiFramework do not match the format the impression was sold as.",
            "TrackingEvents mapped to a linear lifecycle that never fires for a non-interruptive format, silently losing measurement.",
            "Wrapper chains that resolve to an InLine stripped of the format signal or the universal ad ID, so the payload no longer proves what the deal promised."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Validate the artifact, not just the deal",
          "paragraphs": [
            "The fix is not exotic. It is a validation step at the payload, before the tag enters a deal and before an agent commits to it. vastlint validates the VAST document these formats ship as: structure across VAST 2.0 through 4.3, MediaFiles, tracking, wrapper resolution, universal ad IDs, OMID, and SIMID. It checks what the tag is, independent of what a signal claims it is.",
            "In an agentic loop that matters more, not less, because there is no human in the path to catch a payload that does not match its declaration. Run the vastlint MCP server inside a buyer or seller agent and the tag gets validated before the deal clears, in the same protocol the agents already speak. The signal tells the agents what was bought. Validation confirms that what ships is what was signaled."
          ]
        },
        {
          "type": "cta",
          "heading": "Wire validation into your agent loop",
          "paragraph": "The agentic integration guide covers connecting the vastlint MCP server to AAMP buyer agents, AdCP pipelines, A2A orchestrators, and plain MCP clients like Claude and Cursor, so the VAST payload gets checked before an agent commits to a deal.",
          "href": "/docs/agentic/",
          "label": "Read the agentic integration guide"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "CTV Ad Portfolio",
              "href": "https://iabtechlab.com/standards/ctv-ad-portfolio/",
              "description": "The IAB Tech Lab portfolio that defines Pause, Overlay, Squeeze Back, Menu, Screensaver, and In-Scene formats.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab Introduces Standardized Signals For CTV Ad Portfolio For Public Comment",
              "href": "https://www.prnewswire.com/news-releases/iab-tech-lab-introduces-standardized-signals-for-ctv-ad-portfolio-for-public-comment-302763676.html",
              "description": "The May 2026 announcement of AdCOM, VAST, and Native signaling updates, with public comment open through June 5, 2026.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Navigating the Agentic Frontier: The IAB Tech Lab 2026 Roadmap",
              "href": "https://iabtechlab.com/navigating-the-agentic-frontier-the-iab-tech-lab-2026-roadmap/",
              "description": "The roadmap that committed to completing programmatic trading signals for OpenRTB, VAST, and SIMID in Q2 2026.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Why SIMID creatives keep failing validation in 2026",
              "href": "/blog/simid-creatives-failing-validation-2026",
              "description": "The interactive layer these overlay and squeeze back formats lean on, and why it fails validation.",
              "source": "vastlint"
            },
            {
              "label": "What Is the Latest VAST Version? VAST 4.3, VAST 4.4 Status, and the IAB CTV Addendum",
              "href": "/blog/latest-vast-version",
              "description": "Version context for the VAST changes underneath the CTV Ad Portfolio signaling work.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "content-taxonomy-authority-and-shareable-reports-in-vastlint",
      "title": "Content Taxonomy authority validation and shareable reports land in vastlint 0.8.0",
      "description": "vastlint 0.8.0 validates the authority attribute on <Category> and <BlockedAdCategories> against the IAB Content Taxonomy registry, and vastlint check --share now returns a public report link. Four new rules, 191 total, plus a crates.io housekeeping note for cargo users.",
      "publishedAt": "2026-07-05",
      "updatedAt": "2026-07-05",
      "author": "Alex Sekowski",
      "readingTime": "6 min read",
      "heroKicker": "Product update",
      "tags": [
        "Content Taxonomy",
        "Brand safety",
        "VAST validator",
        "Ad ops",
        "Release"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "What shipped",
          "paragraphs": [
            "vastlint 0.8.0 adds IAB Content Taxonomy authority validation: four new rules that check the value of the authority attribute on <Category> and <BlockedAdCategories> elements, bringing the catalog to 191 rules. Presence checks existed already; these validate what the attribute actually says.",
            "Shareable report links are also live. vastlint check tag.xml --share validates as usual, uploads the report, and prints a public vastlint.org/r/ URL you can paste into Slack, a ticket, or a partner escalation. The tag itself never leaves your machine.",
            "Both run everywhere the core runs: the CLI, the Rust, JS, Python, Ruby, Go, and Elixir libraries, the web validator, and the hosted MCP server at vastlint.org/mcp."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the authority attribute matters",
          "paragraphs": [
            "A category code like IAB6-7 means nothing on its own. It is a key into a taxonomy, and the authority attribute names which one: the URL of the organization that maintains the category list. VAST 4.0 made authority required on <Category>, and VAST 4.1 added it to <BlockedAdCategories>.",
            "In production tags, authority carries everything from bare domains to typos to free prose. A malformed value breaks category mapping for every downstream system that tries to resolve it. On <BlockedAdCategories> the failure is quieter and worse: a block list nobody can resolve blocks nothing, and the wrapper's brand safety intent silently evaporates."
          ]
        },
        {
          "type": "code",
          "heading": "Three authorities, three different verdicts",
          "language": "xml",
          "code": "<Category authority=\"my taxonomy\">IAB6-7</Category>\n<Category authority=\"taxonomy.example.com\">IAB6-7</Category>\n<Category authority=\"https://www.iabtechlab.com/IABTC/2.2\">IAB6-7</Category>"
        },
        {
          "type": "list",
          "heading": "What vastlint reports on that snippet",
          "items": [
            "VAST-4.0-category-authority-not-uri (warning) on the first: \"my taxonomy\" cannot be read as an authority URL, so no downstream system can resolve the codes.",
            "VAST-4.0-category-authority-unknown (info) on the second: well-formed, but not an IAB Content Taxonomy registry host. Custom taxonomies are legal per spec, which is why this is Info rather than a warning; it only works if every party in the chain resolves the same authority.",
            "The third passes clean. Bare domains (iabtechlab.com), scheme and www prefixes, iabtechlab.com subdomains such as ads.iabtechlab.com, and version-qualified paths like iabtechlab.com/IABTC/2.2 are all recognised forms.",
            "The same pair of checks runs on <BlockedAdCategories> in wrappers from VAST 4.1 up, as VAST-4.1-blockedadcategories-authority-not-uri and VAST-4.1-blockedadcategories-authority-unknown."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Shareable report links",
          "paragraphs": [
            "Validation results usually die in a terminal scrollback. When the problem is in a partner's tag, you end up screenshotting output or pasting JSON into a ticket. --share replaces that with a link: the report page shows every issue with its rule ID, severity, location, and spec reference, links each rule to its docs page, and works for whoever you send it to, no account needed.",
            "What gets uploaded is the report, never the tag: rule IDs, severities, XPath locations, messages, and summary counts. The input XML stays local. --share is off by default and independent of telemetry, and the default no-storage behaviour of every other vastlint surface is unchanged."
          ]
        },
        {
          "type": "code",
          "heading": "One flag, one link",
          "language": "sh",
          "code": "$ vastlint check preroll.xml --share\n...\nShareable report: https://vastlint.org/r/f63a5b935c"
        },
        {
          "type": "paragraphs",
          "heading": "If you install with cargo",
          "paragraphs": [
            "A housekeeping note for crates.io users: a release pipeline bug meant versions 0.6.3 through 0.7.2 published to npm, PyPI, RubyGems, and hex.pm but never reached crates.io. The pipeline is fixed and both crates are current again. If cargo install vastlint-cli has been serving you 0.6.2, reinstalling picks up macro validation, --share, and the taxonomy rules in one jump."
          ]
        },
        {
          "type": "list",
          "heading": "Also in 0.8.0",
          "items": [
            "Project governance docs: GOVERNANCE.md (roles, key custody, continuity plan), a Contributor Covenant 2.1 code of conduct, a rewritten CONTRIBUTING.md with a DCO requirement and an explicit test policy, and a security assurance case in SECURITY.md. Part of ongoing OpenSSF Best Practices Silver work.",
            "The web validator at vastlint.org/validate now runs the current core, so browser results match the CLI rule for rule.",
            "Full details in the changelog, linked below."
          ]
        },
        {
          "type": "cta",
          "heading": "Check your authorities now",
          "paragraph": "Paste a VAST tag into the validator. If a Category or BlockedAdCategories authority is malformed or unresolvable, you get the rule ID, the exact location, and the fix.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "IAB Tech Lab Content Taxonomy",
              "href": "https://iabtechlab.com/standards/content-taxonomy/",
              "description": "The registry the new authority checks resolve against, including current taxonomy versions.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST specification",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "VAST 4.x defines the authority attribute on Category (4.0) and BlockedAdCategories (4.1).",
              "source": "IAB Tech Lab"
            },
            {
              "label": "vastlint changelog",
              "href": "https://github.com/aleksUIX/vastlint/blob/main/CHANGELOG.md",
              "description": "Everything in 0.8.0, including the release pipeline fix for crates.io.",
              "source": "GitHub"
            },
            {
              "label": "Rule reference",
              "href": "https://vastlint.org/docs/rules/",
              "description": "All 191 rules with examples and fix guidance, including the four new authority rules.",
              "source": "vastlint"
            }
          ]
        }
      ]
    },
    {
      "slug": "aamp-vs-adcp-agentic-advertising-standards",
      "title": "AAMP vs AdCP: What IAB Tech Lab and AAO Are Each Building for Agentic Advertising",
      "description": "IAB Tech Lab shipped AAMP 2.0 in June 2026 with transaction-ready buyer and seller agent SDKs. AAO shipped AdCP 3.0 in April. A comparison of the two standards stacks, and the VAST delivery layer both of them depend on but neither verifies.",
      "publishedAt": "2026-07-05",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Agentic advertising",
      "tags": [
        "Standards",
        "Agentic",
        "IAB",
        "Programmatic"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Agentic advertising now has two standards bodies",
          "paragraphs": [
            "Eighteen months ago, agent-driven ad buying was a keynote topic. Today it is two competing standards stacks with shipped software. IAB Tech Lab released AAMP 2.0 in June 2026, adding transaction-ready buyer and seller agent SDKs to the framework it launched in January. AgenticAdvertising.Org, the trade association formed around the Ad Context Protocol, shipped AdCP 3.0 in April and already has 3.1 release candidates in review.",
            "The two efforts are not coordinated. Tech Lab publicly positioned AAMP as the standards-grounded alternative to AdCP, and AAO kept building anyway. Programmatic teams do not get to wait out the fight: buyer agents, seller agents, and the platforms between them are adopting pieces of both, and every video transaction in either stack still resolves to the same artifact at the delivery layer, a VAST tag."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The IAB Tech Lab stack: AAMP",
          "paragraphs": [
            "AAMP (Agentic Advertising Management Protocols) is Tech Lab's umbrella for everything agentic. It rests on three pillars. Agent Foundations contains ARTF, the Agentic Real Time Framework, which defines how agent services run as containers inside host platforms, including real-time bidders. Agentic Protocols covers the Buyer and Seller Agent SDKs plus Agentic Direct, Agentic Deals, and Agentic RTB. Trust and Transparency is anchored by an Agent Registry.",
            "The design philosophy is explicit: build on the rails that already move money. AAMP wires OpenRTB, AdCOM, OpenDirect, and VAST together, with the Model Context Protocol and Google's Agent2Agent protocol as the agent interfaces.",
            "Version 1.0 could only transact direct deals. The 2.0 release added programmatic. The Buyer Agent SDK now creates and optimizes programmatic deals through a three-layer hierarchy of orchestration agents, channel specialists, and functional agents. The Seller Agent SDK turns a static media kit into a storefront that adapts pricing and packaging to the buyer and the deal stage. A Deals Library acts as the system of record, with native OpenDirect 2.1 and Deals API support. Approval gates and audit logs keep humans at the sign-off points."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The AAO stack: AdCP",
          "paragraphs": [
            "The Ad Context Protocol launched in October 2025 from a consortium that included Yahoo, PubMatic, Optable, Scope3, Swivel, and Triton Digital. Governance has since been formalized under AgenticAdvertising.Org (AAO), a trade association with four equally weighted voting classes: brands, agencies, publishers, and technology providers. The reference sell-side implementation lives with the Prebid community, deliberately separate from spec governance.",
            "Where AAMP extends existing rails, AdCP was designed agent-native from the start. It is built directly on MCP and runs asynchronously, so humans can approve while agents negotiate. AdCP 3.0, released in April 2026, stretched the protocol across the full campaign lifecycle: inventory discovery, media buys, creative production with brand.json and the Creative Protocol, governance, and reporting across 20 media channels. The working group is already iterating on 3.1, which tightens the creative lifecycle with retention contracts and status webhooks.",
            "Adoption is real on the sell side. AdCP is in production at Snap, Pinterest, Reddit, Netflix, and Vox Media."
          ]
        },
        {
          "type": "list",
          "heading": "Where the stacks actually differ",
          "items": [
            "Governance: IAB Tech Lab is the incumbent body that already maintains VAST, OpenRTB, and OpenDirect. AAO is a new trade association built specifically for agentic advertising, with brands and agencies holding equal votes to publishers and vendors.",
            "Design center: AAMP layers agents on top of the existing programmatic rails. AdCP defines new MCP-native tasks first and treats legacy systems as integration targets.",
            "Coverage: AAMP is deepest at the transaction layer, with ARTF containers running inside bidder infrastructure. AdCP is broadest across the lifecycle, from planning through creative production to reporting.",
            "Interfaces: both name MCP as a core agent protocol, which means a tool exposed as an MCP server can serve agents on either stack without modification.",
            "Verification: neither stack validates the creative payload. Both move deal state and context between agents; the correctness of what actually ships is out of scope for both specs."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Both stacks still hand off to VAST",
          "paragraphs": [
            "Follow a video buy through either stack and the endpoint is identical. An AAMP agentic deal or an AdCP media buy ultimately serves through an ad server that returns VAST XML: an InLine or Wrapper, MediaFiles, Impression pixels, TrackingEvents. AAMP names VAST among the standards it builds on. An AdCP creative agent that produces video hands a VAST tag to the seller side. Twenty channels of protocol surface on one side, one XML document on the other.",
            "That document is where delivery fails. A missing Duration, an HTTP media URL on a CTV device that requires HTTPS, a wrapper chain that exceeds the player's depth limit, a VPAID creative on an inventory path that dropped VPAID years ago: none of it is visible at the protocol layer. The deal confirms cleanly, the agents log success, and the impression dies at runtime with a VAST error code nobody is watching.",
            "Human traffickers used to be the backstop. In an agent-to-agent transaction there is no trafficker. If the tag gets checked at all, something in the loop has to check it, which means validation has to be a tool the agent calls before the deal confirms, not a QA pass scheduled after launch."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What to do while the standards fight plays out",
          "paragraphs": [
            "Betting on a single winner is unnecessary. MCP is the shared interface: AAMP's Buyer Agent SDK accepts additional MCP tool servers, and AdCP is MCP-native end to end. A validator exposed over MCP plugs into both stacks today.",
            "vastlint runs 233 rules grounded in the IAB VAST, OMID, and SIMID specs and returns deterministic, machine-readable results. It is available as a hosted MCP endpoint at vastlint.org/mcp, as a CLI for pipelines, and as native libraries. Point either stack's agent at it and gate deal confirmation on a clean tag. The protocols will keep changing; the payload they deliver has been VAST for two decades and will still be VAST when the governance questions settle."
          ]
        },
        {
          "type": "cta",
          "heading": "Wire validation into your agent loop",
          "paragraph": "The agentic integration guide covers connecting the vastlint MCP server to AAMP buyer agents, AdCP pipelines, A2A orchestrators, and plain MCP clients like Claude and Cursor, with working configuration for each.",
          "href": "/docs/agentic/",
          "label": "Read the agentic integration guide"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "AAMP: Agentic Advertising Management Protocols",
              "href": "https://iabtechlab.com/standards/aamp-agentic-advertising-management-protocols/",
              "description": "IAB Tech Lab's umbrella page for the AAMP framework and its three pillars.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "AAMP 2.0 release announcement",
              "href": "https://iabtechlab.com/aamp-2-0-release-brings-transaction-ready-buyer-and-seller-agent-sdks/",
              "description": "The June 2026 release that added transaction-ready buyer and seller agent SDKs and programmatic deals.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Ad Context Protocol documentation",
              "href": "https://docs.adcontextprotocol.org",
              "description": "Official AdCP docs: tasks, the Creative Protocol, brand.json, and the 3.x changelog.",
              "source": "AdCP"
            },
            {
              "label": "AgenticAdvertising.Org",
              "href": "https://agenticadvertising.org",
              "description": "The trade association that governs AdCP, with its four-class voting structure.",
              "source": "AAO"
            },
            {
              "label": "IAB Tech Lab, not a fan of AdCP, releases an agentic advertising framework",
              "href": "https://www.thecurrent.com/marketing-strategy-iab-tech-lab-adcp-agentic-advertising-framework-ai",
              "description": "Coverage of the split between the Tech Lab and AAO tracks.",
              "source": "The Current"
            },
            {
              "label": "AdCP and VAST: the full breakdown",
              "href": "/docs/adcp/",
              "description": "How AdCP's creative and delivery layers map onto VAST validation.",
              "source": "Docs"
            }
          ]
        }
      ]
    },
    {
      "slug": "ctv-revenue-loss-protocol-infrastructure-standards",
      "title": "Where CTV Ad Revenue Leaks: Protocol, Infrastructure, and Standards Failures",
      "description": "US connected TV is heading past a record year, but a large share of the money never becomes working media. Here is where it leaks, with the numbers: broken ad-tag protocol, latency and wrapper-chain infrastructure, and non-compliance with the IAB standards that make an impression measurable.",
      "publishedAt": "2026-06-27",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "CTV economics",
      "tags": [
        "CTV",
        "Revenue recovery",
        "Standards",
        "Ad ops"
      ],
      "featured": false,
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The market got big. The plumbing did not keep up.",
          "paragraphs": [
            "US connected TV is no longer the upstart line item. The IAB projects that US digital video ad spend will pass $80 billion in 2026, growing faster than the ad market overall and crossing 60% of all TV and video budgets for the first time. Inside that total, the IAB's 2026 forecast puts CTV growth at 13.8% while linear TV slips 1.7%. The budget is moving to streaming, and it is moving fast.",
            "The delivery stack underneath it did not scale as cleanly. A CTV impression is the end of a long chain: a request, one or more wrapper redirects, a VAST response, a media file, verification and measurement code, all of it resolving on a living-room device with a thin runtime and an impatient viewer. Every link in that chain is a place where money stops being working media.",
            "The losses sort into three buckets. Protocol failures, where the ad tag itself is malformed or non-conforming. Infrastructure failures, where latency and redirect depth eat the impression before it renders. And non-compliance with standards, where the impression serves but cannot be measured, verified, or trusted. The first two are mostly preventable before launch. The third is what makes the whole market discount the inventory."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The macro number nobody wants to own",
          "paragraphs": [
            "Start with the size of the leak, because it sets the stakes. The ANA's Programmatic Media Supply Chain Transparency Study found that of every dollar entering a demand-side platform, only about 36 cents reaches a consumer in working media. The study put roughly a quarter of open-web programmatic spend, around $22 billion a year, into the wasteful or unproductive column.",
            "Fraud is its own slice of that. Juniper Research estimated $84 billion lost to ad fraud in 2023, about 22% of global digital ad spend, and projected it would rise toward $172 billion by 2028. CTV is now a prime target: Pixalate measured a 19% invalid-traffic rate for US connected TV in Q4 2025, and DoubleVerify reported that bots accounted for 65% of all CTV fraud, a higher share than any other channel.",
            "Those are macro numbers, and not all of them are something a single ad-ops team can fix. But they describe the discount the market applies to inventory it cannot trust. The practical question for anyone shipping tags is narrower and more actionable: which of these losses are sitting in your own delivery path before the campaign even launches?"
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Protocol: the tag is broken before it serves",
          "paragraphs": [
            "A VAST tag is a contract. The IAB specification says an InLine ad carries at least one Impression, that a MediaFile declares a delivery type and bitrate, that a Duration is present and well-formed, that wrapper chains terminate in real creative. A tag can violate any of those and still be valid XML that parses cleanly. It loads, and it is wrong.",
            "When that happens on a player, it does not fail silently in the abstract. It fails with a code. VAST error 301 fires when a redirect does not return a valid response inside the timeout. Error 302 fires when the wrapper limit is reached. Those codes exist precisely because malformed and non-conforming tags are a leading cause of an ad slot going dark, and the slot going dark is revenue that was sold and not delivered.",
            "The protocol surface is also a moving target across versions. VPAID, the old interactive and verification layer, ran arbitrary JavaScript inside the publisher's player. The IAB Tech Lab deprecated it in 2019 because it slowed page loads, opened a security and malware surface, and did not work on mobile or OTT. The replacement split the job into three conforming pieces: SIMID for interactivity, VAST for delivery, and OMID for verification. Tags that still lean on VPAID as a fallback, or that mix the layers incorrectly, are shipping a known-deprecated dependency into the exact environment, CTV, where it was never designed to run."
          ]
        },
        {
          "type": "list",
          "heading": "Protocol-level failures that quietly cost impressions",
          "items": [
            "Missing required fields: an InLine without an Impression, a Linear without a Duration, a Creative without a UniversalAdId in VAST 4.x.",
            "Malformed values: durations that do not match HH:MM:SS, MediaFile delivery types outside the allowed enum, URLs that are not valid URIs.",
            "Insecure resources: HTTP MediaFile or tracking URLs that get blocked by mixed-content policy on secure inventory, so the asset never loads and the beacon never fires.",
            "Deprecated dependencies: VPAID treated as a fallback instead of a migration to SIMID and OMID.",
            "Version drift: a tag that declares one VAST version but uses structures from another, so strict players reject it."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Infrastructure: latency and wrapper chains",
          "paragraphs": [
            "Even a perfectly conforming tag loses money if it arrives too late. CTV viewers abandon quickly. A widely cited peer-reviewed study of 23 million video views (Krishnan and Sitaraman) found that viewers begin abandoning after about two seconds of startup delay, and that each additional second of delay raises the abandonment rate by roughly 5.8%. Time-to-first-frame is not a quality-of-experience nicety. It is a fill-and-completion lever.",
            "Wrapper chains are where that latency accumulates. Each redirect is one more network dependency, one more timeout surface, one more place tracking can diverge from the final inline response. The VAST 4.2 specification recommends limiting a chain to five wrappers before an InLine response, after which a player may reject the rest of the chain. Players enforce their own timeouts well before that: the Google IMA SDK defaults to a five-second load timeout per wrapper. A chain that is technically legal can still blow the budget one hop at a time.",
            "The reason this matters so much in CTV specifically is that the completion bar is high. FreeWheel's marketplace report puts long-form and CTV video completion around 95%. When nearly every successfully rendered ad runs to completion, the impressions you lose are almost entirely the ones that never rendered: the timeout, the dead redirect, the asset that loaded too slowly to count. The loss hides in the gap between ads requested and ads served, not in the completion rate you actually report."
          ]
        },
        {
          "type": "quote",
          "quote": "In CTV the completion rate is not where the money leaks. The leak is upstream, in the impressions that never rendered because a tag was malformed, a redirect timed out, or the chain ran one hop too deep.",
          "attribution": "vastlint operations note"
        },
        {
          "type": "paragraphs",
          "heading": "Non-compliance: served, but unmeasurable",
          "paragraphs": [
            "The third bucket is the one that depresses the price of the whole pool. An impression can render perfectly and still be worth less because no one can prove it happened the way the buyer needs.",
            "Standardized measurement coverage is still partial on CTV. When the IAB Tech Lab extended the Open Measurement SDK to Samsung and LG in 2024, it described that as bringing OM SDK to about 40% of the CTV market, which means the majority of CTV was still outside the standard measurement path. DoubleVerify found that only half of CTV impressions offered full app-level transparency in 2024. Server-side ad insertion compounds this: because beacons fire from the server rather than the player, the MRC's SSAI and OTT guidance is explicit that viewability and interaction cannot be confirmed the way a client-side beacon confirms them, which is why client beacons are still recommended even under SSAI.",
            "Put those together and a large share of CTV inventory is technically delivered but hard to verify, and unverifiable inventory trades at a discount. DoubleVerify's own framing is blunt: absent verification, more than one in four CTV impressions would fail to meet the minimum bar for fraud-free, viewable, brand-safe, brand-suitable delivery, and it estimates roughly $700,000 in wasted spend for every billion impressions when viewability protections are missing. Compliance with the measurement standards is not paperwork. It is what lets the impression be sold at full value."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What you actually control before launch",
          "paragraphs": [
            "Two of the three buckets are addressable before a single impression serves, and they are the two that do not require a measurement contract or a fraud vendor to fix. The protocol bucket is deterministic: a tag either conforms to its declared VAST version or it does not, and that is checkable. The infrastructure bucket is mostly observable: wrapper depth, redirect timing, final media attributes, and insecure resources can all be inspected on the real chain before you traffic it.",
            "The non-compliance bucket is partly yours too. You cannot single-handedly fix CTV measurement coverage, but you can make sure your tags carry conforming verification and interactivity layers, secure resources, and the required identifiers, so your inventory is on the right side of the line when measurement is available.",
            "The point is to stop treating these as post-mortem categories. Underdelivery, low fill, and reporting disputes are usually the late symptoms of failures that were visible in the tag and the chain at launch time."
          ]
        },
        {
          "type": "code",
          "heading": "A pre-launch checklist mapped to where money leaks",
          "language": "text",
          "code": "Protocol (deterministic, validate the XML):\n  [ ] Required fields present: Impression, Duration, MediaFile, UniversalAdId (4.x)\n  [ ] Values well-formed: duration format, delivery enum, valid URIs\n  [ ] No HTTP resources on secure inventory (MediaFile + trackers HTTPS)\n  [ ] No VPAID fallback; SIMID + OMID where interactivity/verification is needed\n  [ ] Declared VAST version matches the structures actually used\n\nInfrastructure (observe the real chain):\n  [ ] Wrapper depth at or under the 5-hop spec ceiling, ideally fewer\n  [ ] Each redirect resolves well inside the player timeout (IMA default 5s)\n  [ ] Final MediaFile MIME, bitrate, and dimensions match the target device\n  [ ] No 3xx/4xx/5xx behavior in intermediate redirects\n\nCompliance (so the impression is worth full price):\n  [ ] Verification resources conform to OMID\n  [ ] Tracking remains consistent across the chain, not just at the first hop\n  [ ] AdVerifications and required identifiers present and well-formed"
        },
        {
          "type": "paragraphs",
          "heading": "Where validation actually helps, and where it does not",
          "paragraphs": [
            "Be honest about scope. A linter cannot recover money lost to bot fraud, cannot extend measurement coverage to a platform that lacks it, and cannot make a slow CDN fast. Those need verification vendors, measurement partners, and infrastructure work.",
            "What a linter does is remove an entire class of loss deterministically: the malformed, non-conforming, insecure, or deprecated tag that was going to fail or go unmeasured before it ever left your hands. That is the protocol bucket in full and a meaningful part of the compliance bucket, checked in milliseconds against the published IAB specification, with a stable rule ID and a spec reference for every finding.",
            "vastlint is built for exactly that floor: 233 rules across VAST 2.0 through 4.3 plus VMAP, DAAST, SIMID, and OMID, available as a CLI, as libraries, as a GitHub Action, as a hosted MCP server, and as a URL inspector that walks every wrapper hop on the live chain. It will not fix the parts of CTV economics that are genuinely someone else's problem. It will make sure none of your lost revenue is the kind you could have caught for free."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "Common CTV VAST errors",
              "href": "/docs/ctv-vast-errors/",
              "description": "The errors that show up specifically on connected TV devices and why they fail there.",
              "source": "Docs"
            },
            {
              "label": "VAST error codes reference",
              "href": "/docs/vast-error-codes/",
              "description": "What 301 (redirect timeout), 302 (wrapper limit), and the rest actually mean in delivery.",
              "source": "Docs"
            },
            {
              "label": "VAST wrapper chains: limits and debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Wrapper depth, timeout behavior, and how to keep latency from eating the impression.",
              "source": "Guide"
            },
            {
              "label": "VPAID is deprecated, stop treating it as a fallback",
              "href": "/docs/vpaid-deprecated/",
              "description": "Why VPAID was retired and how to migrate to SIMID and OMID for CTV.",
              "source": "Docs"
            },
            {
              "label": "Validating OMID in VAST tags",
              "href": "/docs/omid/",
              "description": "Getting the verification layer right so the impression stays measurable.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "US digital video ad spend to surpass $80B in 2026",
              "href": "https://www.iab.com/news/u-s-digital-video-ad-spend-to-surpass-80b-in-2026/",
              "description": "IAB 2026 Digital Video Ad Spend and Strategy Report: market size and growth versus the total ad market.",
              "source": "IAB"
            },
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The spec family that defines conformance, wrapper limits, and inline responses.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Understand VAST error codes",
              "href": "https://support.google.com/admanager/answer/4442429",
              "description": "Google Ad Manager reference for 301 redirect timeout, 302 wrapper limit, and related delivery errors.",
              "source": "Google Ad Manager"
            },
            {
              "label": "IAB Tech Lab introduces SIMID to replace VPAID",
              "href": "https://iabtechlab.com/press-releases/iab-tech-lab-releases-for-public-comment-a-new-specification-to-improve-transparency-and-user-experience-in-video-advertising/",
              "description": "The rationale for deprecating VPAID and splitting interactivity (SIMID), delivery (VAST), and verification (OMID).",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Open Measurement SDK expands to new CTV platforms",
              "href": "https://www.prnewswire.com/news-releases/iab-tech-lab-expands-open-measurement-sdk-to-new-ctv-platforms-302158395.html",
              "description": "IAB Tech Lab on OM SDK reaching roughly 40% of the CTV market, the measurement-coverage gap.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "DV Global Insights 2025: bot fraud in CTV",
              "href": "https://doubleverify.com/blog/ctv/verify/dv-global-insights-2025-bot-fraud-in-ctv-the-hidden-drain-on-ad-budgets",
              "description": "DoubleVerify on the 65% bot share of CTV fraud and the cost of unprotected, unverified inventory.",
              "source": "DoubleVerify"
            },
            {
              "label": "Pixalate Q4 2025 North America IVT benchmarks",
              "href": "https://www.globenewswire.com/news-release/2026/03/09/3251883/0/en/Pixalate-Releases-Q4-2025-North-America-Invalid-Traffic-IVT-Ad-Fraud-Benchmarks-Connected-TV-CTV-IVT-Rate-in-United-States-at-19.html",
              "description": "Pixalate's 19% US CTV invalid-traffic rate across 100B+ programmatic impressions.",
              "source": "Pixalate"
            },
            {
              "label": "ANA Programmatic Media Supply Chain Transparency Study",
              "href": "https://www.ana.net/miccontent/show/id/rr-2023-12-ana-programmatic-media-supply-chain-transparency-study",
              "description": "Where the open-web programmatic dollar goes: roughly 36 cents reaching the consumer.",
              "source": "ANA"
            },
            {
              "label": "Video Stream Quality Impacts Viewer Behavior (IMC 2012)",
              "href": "https://people.cs.umass.edu/~ramesh/Site/HOME_files/imc208-krishnan.pdf",
              "description": "Krishnan and Sitaraman: each added second of startup delay raises abandonment by about 5.8%.",
              "source": "ACM IMC"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Catch the loss you control before launch",
          "paragraph": "Paste a live VAST URL into the inspector to walk every wrapper hop, or validate the XML against 233 IAB-grounded rules. The cheapest revenue to recover is the kind a malformed tag was about to throw away.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "vast-validity-is-a-verifiable-reward",
      "title": "Most of Advertising Can't Be a Training Reward. VAST Validity Can.",
      "description": "Reinforcement learning with verifiable rewards works where a rule-based checker can score an output without a human or a learned judge. Math and code qualify. So does VAST. Here is why ad-tag validity is one of the few verifiable rewards in advertising, and how to wire vastlint into a training or fine-tuning loop.",
      "publishedAt": "2026-06-19",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Model training",
      "tags": [
        "Model training",
        "RLVR",
        "Agentic",
        "Standards"
      ],
      "featured": false,
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The reason RLVR works is the reward, not the model",
          "paragraphs": [
            "The most reliable post-training results of the last two years came from a narrow setup: reinforcement learning with verifiable rewards. Instead of a human rating outputs or a second model guessing at quality, a rule-based checker scores each generation against objective, task-grounded criteria. The model generates, the checker returns a verdict, the policy updates against that verdict.",
            "It works best in two places: mathematical reasoning, where an answer is right or wrong, and code generation, where a compiler and a test suite decide. The common thread is not the domain. It is that a cheap, deterministic verifier exists. Where you can compute correctness without a human and without a learned reward model, RL has a clean signal to optimise against. Where you cannot, you are back to expensive labels and reward models that drift.",
            "That framing is worth bringing to advertising, because it changes which problems are tractable. Most of advertising is not verifiable. A few corners of it are. VAST is one of them."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Most adtech signals make terrible rewards",
          "paragraphs": [
            "Think about what you would actually want a media or creative model to optimise. Creative quality is subjective and needs a human or a learned judge. Fill rate, click-through, completion, and revenue are real signals, but they are noisy, they arrive hours or days late, and they are confounded by auction dynamics, audience, and seasonality. Worse, they are gameable: a model can learn to produce tags that score well on a proxy metric without being correct, which is exactly the failure mode verifiable rewards were meant to avoid.",
            "None of those signals give you what a verifier gives you: an immediate, deterministic, ungameable verdict on a single output, with no human in the loop and no second model to train and maintain. For most of advertising, that verdict does not exist.",
            "For VAST, it does. A VAST tag either conforms to the IAB specification at its declared version or it does not. The check is structural, it is grounded in a published standard, and it returns the same answer every time. That is the precise property that made code and math good RLVR domains, and it is rare enough in advertising to be worth building on."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why VAST is verifiable when the rest of the stack is not",
          "paragraphs": [
            "A VAST tag is a contract, not an opinion. The spec says an InLine ad must carry at least one Impression, that a MediaFile has a bitrate and a delivery type, that wrapper chains terminate, that a Duration is present and well-formed. These are not matters of taste. They are checkable against the IAB VAST 2.0 through 4.3 specifications, and a violation is a violation regardless of who is looking.",
            "The catch that makes this useful rather than trivial: a broken VAST tag is still well-formed XML. It parses. A model generating tags will happily produce output that loads cleanly and is wrong, missing a required Impression, pointing at an insecure MediaFile, burying the creative four wrappers deep. None of that throws. So 'it parsed' is not a reward. 'It conforms to the spec' is, and computing that is exactly what a linter does.",
            "vastlint is that linter, built as one Rust core with a Python binding that runs in-process. For a training loop, the binding is the relevant part: validation is a function call, not a subprocess and not a network hop, and it returns a structured result you can turn into a reward in a couple of lines."
          ]
        },
        {
          "type": "list",
          "heading": "What the verifier has to give a training loop",
          "items": [
            "Determinism: the same tag scores the same every step, so the reward is stable and the policy is not chasing a moving target.",
            "Speed in-process: training and rejection sampling touch millions of generations, so a subprocess or network call per sample would dominate the loop. A function call against the Rust core clears a production-size tag in well under a millisecond.",
            "Structured output, not a verdict string: per-rule severities and counts, so you can shape a dense reward instead of a single pass or fail bit.",
            "Spec grounding: every rule traces to a section of the IAB VAST spec, so the thing you optimise toward is standards conformance, not a vendor heuristic the model can overfit.",
            "Version awareness: the tag declares a version, and the checker validates against that version's rules, so the model is rewarded for being correct at the spec it claims."
          ]
        },
        {
          "type": "code",
          "heading": "The reward, concretely",
          "language": "python",
          "code": "import vastlint\n\n# Verifiable reward: deterministic, sub-millisecond, no human, no learned judge.\ndef vast_reward(xml: str) -> float:\n    result = vastlint.validate(xml)\n    if result.valid:\n        return 1.0\n    s = result.summary\n    return -1.0 * s.errors - 0.25 * s.warnings   # shaped, not just pass/fail\n\n\n# Rejection sampling: turn a base model into a clean SFT set without labels.\ndef build_sft_examples(prompt: str, samples: list[str]) -> list[dict]:\n    return [\n        {\"prompt\": prompt, \"completion\": xml}\n        for xml in samples\n        if vastlint.validate(xml).valid\n    ]"
        },
        {
          "type": "paragraphs",
          "heading": "Binary is potent. Dense is better.",
          "paragraphs": [
            "The simplest version of this is a binary reward: valid is one, invalid is zero. That is enough to move a model, and it is how most verifiable-reward setups start. But a binary signal is sparse. Early in training the model is wrong almost every time, so almost every sample returns zero and there is little gradient to learn from.",
            "Because vastlint returns per-rule counts rather than a single bit, you do not have to stay binary. A tag with one error is closer to correct than a tag with ten, and you can say so: weight by severity, penalise an insecure MediaFile more heavily than a missing recommended mezzanine, reward getting from ten errors to one even when the tag is not yet clean. Recent RL work keeps finding the same thing, that when the verifiable reward is sparse it pays to make it dense, and the structured result is what lets you do that here without inventing a separate scorer.",
            "Per-rule output is also what makes the model debuggable during training. Track the valid rate across checkpoints and you get one number. Track which rule IDs fail most and you get a map of what the model has not learned yet, so a regression shows up as a specific spec violation instead of a number that quietly slid."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where a VAST reward actually fits",
          "paragraphs": [
            "The obvious target is any model that writes or repairs ad tags: a creative agent that emits a VAST document, a fine-tuned model that takes a broken tag and returns a fixed one, an SSAI or templating system that assembles tags from parts. In agentic pipelines this lines up with the Ad Context Protocol, where a build_creative step can produce a vast asset and a sync_creatives step hands it to a seller. Training that generator against a verifier means fewer rejections downstream, because the tag was scored against the same standard the seller will check it with.",
            "One honest boundary. Spec validity is necessary, not sufficient. A tag that passes vastlint can still fail to play in a specific player, exchange, or CTV environment, because those impose constraints beyond the standard. So validity is a reward component, the verifiable floor, not the whole objective. That is a feature, not a limitation: it is precisely the part of the problem that can be scored without a human, which is what makes it the right place to apply RL with verifiable rewards. Use it for the floor, and keep human or metric-based signals for the parts that genuinely are not verifiable.",
            "The point is narrow and, hopefully, useful. Advertising has very few places where you can score a model output deterministically and cheaply. Ad-tag conformance is one of the clearest, the verifier already exists, and it is a pip install away."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "VAST validation in Python",
              "href": "/docs/best-vast-validator-python/",
              "description": "The Python package: install, the structured result shape, and the training, agentic, and AdCP use cases.",
              "source": "Docs"
            },
            {
              "label": "Agentic ad delivery",
              "href": "/docs/agentic/",
              "description": "Where validation sits in MCP, AAMP, and AdCP agent workflows.",
              "source": "Docs"
            },
            {
              "label": "MCP docs",
              "href": "/docs/mcp/",
              "description": "The same Rust core exposed as an MCP tool for agents that call validation over the protocol.",
              "source": "Docs"
            },
            {
              "label": "Rules reference",
              "href": "/docs/rules/",
              "description": "The rule catalog and severities the verifier scores against.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Reinforcement Learning with Verifiable Rewards (RLVR)",
              "href": "https://www.emergentmind.com/topics/reinforcement-learning-with-verified-rewards-rlvr",
              "description": "Overview of the post-training paradigm: rule-based verifiers as direct supervision, with success concentrated in math and code.",
              "source": "EmergentMind"
            },
            {
              "label": "Crossing the Reward Bridge: Expanding RLVR Across Diverse Domains",
              "href": "https://arxiv.org/pdf/2503.23829",
              "description": "On extending verifiable-reward RL beyond the math and code domains where it first worked.",
              "source": "arXiv"
            },
            {
              "label": "Hybrid Reinforcement: When Reward Is Sparse, It's Better to Be Dense",
              "href": "https://arxiv.org/pdf/2510.07242",
              "description": "Evidence that dense, shaped reward beats sparse binary reward when verifiable signals are sparse.",
              "source": "arXiv"
            },
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The published IAB standard that defines what conformance, and therefore the reward, means.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Ad Context Protocol: Introduction",
              "href": "https://docs.adcontextprotocol.org/docs/intro",
              "description": "The MCP-based protocol whose vast creative asset a trained generator would produce and a seller would validate.",
              "source": "AdCP"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Put a verifier in your training loop",
          "paragraph": "vastlint is a deterministic, sub-millisecond VAST verifier with a zero-dependency Python binding. Install it and turn spec conformance into a reward signal.",
          "href": "/docs/best-vast-validator-python/",
          "label": "Read the Python guide"
        }
      ]
    },
    {
      "slug": "simid-creatives-failing-validation-2026",
      "title": "Why SIMID creatives keep failing validation in 2026",
      "description": "With VPAID gone from Google IMA and Ad Manager, interactive ads now ship as SIMID. The catch: most SIMID creatives fail VAST validation on the same handful of issues. Here are the InteractiveCreativeFile, apiFramework, nonlinear iframe, and HTTPS errors that block them, and how to catch every one before launch.",
      "publishedAt": "2026-06-18",
      "updatedAt": "2026-06-18",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Interactive ads",
      "tags": [
        "SIMID",
        "VPAID",
        "Interactive ads",
        "CTV",
        "VAST validator"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The interactive ad you shipped no longer renders",
          "paragraphs": [
            "VPAID is gone from the places that mattered. Google IMA dropped VPAID rendering, Google Ad Manager finished sunsetting it, and CTV never accepted it in the first place. The replacement is SIMID, the IAB Secure Interactive Media Interface Definition, and in 2026 it is no longer optional: buyers and SSPs increasingly require interactive creatives to be delivered as SIMID inside VAST 4.x or not at all.",
            "Here is the pattern we keep seeing. A creative that worked fine as VPAID gets re-wrapped as SIMID, passes a quick visual smoke test in one player, then fails silently across half the inventory. The creative is fine. The VAST envelope around it is not. SIMID moved the interactivity into a sandboxed, postMessage-driven iframe, and that change shifts where things break: from runtime JavaScript errors to structural problems in the tag that a validator catches in milliseconds."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where SIMID actually lives in the tag",
          "paragraphs": [
            "SIMID is not a media file. For a linear ad, the interactive layer is declared with an InteractiveCreativeFile element inside MediaFiles, carrying apiFramework=\"SIMID\" and a type attribute for the document MIME type, alongside the regular video MediaFile that plays underneath it. For a nonlinear ad, SIMID is referenced through the NonLinear creative as an iframe resource. The player loads that resource in a sandbox and talks to it over a defined postMessage protocol. There is no direct DOM access the way VPAID had, which is the whole point.",
            "That structure is also exactly where validation fails. The video underneath is valid VAST, so superficial checks pass, but the SIMID declaration is malformed, mistyped, or served over the wrong scheme. The ad either falls back to the linear video with no interactivity or gets rejected outright."
          ]
        },
        {
          "type": "list",
          "heading": "The five issues that block most SIMID creatives",
          "items": [
            "Missing or wrong apiFramework. The InteractiveCreativeFile must declare apiFramework=\"SIMID\". A blank value, a casing mismatch, or a leftover apiFramework=\"VPAID\" makes the player treat the file as an unknown resource and skip the interactive layer.",
            "Missing type on the SIMID resource. The type attribute tells the player what document it is loading. Omit it and many players will not initialise the creative. This is the nonlinear-iframe SIMID type requirement.",
            "Nonlinear SIMID delivered without an iframe resource. A nonlinear SIMID creative has to be an iframe resource. Pointing it at a static or HTML resource instead is a structural error that fails validation before the creative ever loads.",
            "Non-HTTPS resource URLs. SIMID resources served over http break on every modern player and CTV device. Mixed-content blocking is silent: no error dialog, just a creative that never appears.",
            "No video fallback. SIMID layers interactivity on top of a real MediaFile. Ship the InteractiveCreativeFile without a valid video MediaFile underneath and there is nothing to play when interactivity is unavailable, which is most of CTV."
          ]
        },
        {
          "type": "code",
          "heading": "A linear SIMID declaration that validates",
          "language": "xml",
          "code": "<MediaFiles>\n  <!-- The video that actually plays -->\n  <MediaFile delivery=\"progressive\" type=\"video/mp4\"\n             width=\"1280\" height=\"720\">\n    https://cdn.example.com/ad-720p.mp4\n  </MediaFile>\n\n  <!-- The SIMID interactive layer on top of it -->\n  <InteractiveCreativeFile apiFramework=\"SIMID\"\n                           type=\"text/html\">\n    https://cdn.example.com/simid/creative.html\n  </InteractiveCreativeFile>\n</MediaFiles>"
        },
        {
          "type": "paragraphs",
          "heading": "Why this slips through QA",
          "paragraphs": [
            "Manual QA tests one creative in one player on one device. SIMID failures are conditional: a missing type attribute breaks the creative on a CTV player but renders fine in a forgiving desktop SDK, and an http resource is blocked only where the page is served over https. By the time the gap shows up in delivery, the campaign is live and the interactive impressions are quietly falling back to plain video.",
            "Structural validation does not have that blind spot. Every InteractiveCreativeFile, every apiFramework value, every resource scheme, and every nonlinear iframe requirement is a deterministic check. Run it once on the tag and you see all of them at once, with the rule ID and the exact fix, before the creative reaches a player at all."
          ]
        },
        {
          "type": "cta",
          "heading": "Check your SIMID tag now",
          "paragraph": "Paste your VAST tag into the validator. It flags every SIMID issue, the InteractiveCreativeFile attributes, the apiFramework value, the nonlinear iframe requirement, and any non-HTTPS resource, with a rule ID, severity, and the exact fix.",
          "href": "/validate/",
          "label": "Validate a VAST tag"
        },
        {
          "type": "paragraphs",
          "heading": "Fix it once, keep it fixed",
          "paragraphs": [
            "The durable fix is to put the same structural check in front of every interactive creative, not just the ones someone remembers to spot-test. Validate the tag the moment it is trafficked, fail the build when a SIMID rule trips, and the fallback-to-video failure mode disappears. The rules below are the specific SIMID checks vastlint runs, each with examples and fix guidance, plus the broader VAST and IMA context that decides whether your interactive creative renders at all."
          ]
        },
        {
          "type": "resources",
          "heading": "Go deeper on vastlint",
          "items": [
            {
              "label": "What is SIMID? IAB's secure replacement for VPAID",
              "href": "/docs/simid/",
              "description": "How SIMID works with VAST 4.x: the InteractiveCreativeFile element, apiFramework=\"SIMID\", the iframe postMessage API, and SIMID versus VPAID.",
              "source": "Docs"
            },
            {
              "label": "Nonlinear SIMID must be an iframe resource",
              "href": "/docs/simid-rules/SIMID-1.1-nonlinear-simid-no-iframe/",
              "description": "The rule that catches nonlinear SIMID creatives delivered without the required iframe resource.",
              "source": "Rule"
            },
            {
              "label": "SIMID iframe resource requires a type",
              "href": "/docs/simid-rules/SIMID-1.1-iframe-simid-type-required/",
              "description": "Why a missing type attribute on the SIMID iframe resource stops players from initialising the creative.",
              "source": "Rule"
            },
            {
              "label": "SIMID needs a video MediaFile underneath",
              "href": "/docs/simid-rules/SIMID-1.0-simid-mediafile-required/",
              "description": "The fallback rule: a SIMID layer without a valid video MediaFile has nothing to play on CTV.",
              "source": "Rule"
            },
            {
              "label": "Google IMA SDK and VAST: AdsLoader, contentComplete, and errors",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "How IMA handles VAST after VPAID, and the delivery errors to fix before launch.",
              "source": "Guide"
            },
            {
              "label": "VAST versions compared: 2.0 to 4.3, and which to use",
              "href": "/docs/vast-versions/",
              "description": "Which VAST version supports SIMID, what changed for CTV, and what to target for new interactive tags.",
              "source": "Docs"
            },
            {
              "label": "VAST error codes and rules: 233 fixes",
              "href": "/docs/rules/",
              "description": "The full searchable rule catalog, including every SIMID, VAST, and VMAP check with XML examples.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "SIMID 1.2 specification",
              "href": "https://iabtechlab.com/standards/secure-interactive-media-interface-definition-simid/",
              "description": "The IAB Tech Lab SIMID standard: the interface, the postMessage protocol, and how SIMID is referenced from VAST.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST 4.x specification",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The VAST standard that defines InteractiveCreativeFile, apiFramework, and how SIMID is carried inside the tag.",
              "source": "IAB Tech Lab"
            }
          ]
        }
      ]
    },
    {
      "slug": "vmap-and-daast-validation-in-vastlint-core",
      "title": "VMAP and DAAST validation land in vastlint core",
      "description": "vastlint core now validates VMAP 1.0 ad-break playlists and DAAST 1.0 digital-audio tags alongside VAST 2.0–4.3. 53 new rules, document-type detection, and embedded-VAST checking, all from the same CLI, library, and MCP server. Here is what shipped, why these two formats still break in production, and how to put structural checks in front of every break and every audio tag.",
      "publishedAt": "2026-06-13",
      "updatedAt": "2026-06-13",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Product update",
      "tags": [
        "VMAP",
        "DAAST",
        "Digital audio",
        "Ad ops",
        "VAST validator"
      ],
      "featured": false,
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "What shipped",
          "paragraphs": [
            "vastlint core 0.5.0 adds dedicated validation chains for two IAB formats that sit right next to VAST in real ad stacks but rarely get the same scrutiny: VMAP 1.0 (the playlist that schedules your ad breaks) and DAAST 1.0 (the audio sibling of VAST). The validator now detects the document type automatically and routes each file to the right rule set: 24 new rules for VMAP, 29 for DAAST, on top of the existing VAST 2.0–4.3 coverage. The catalog is now 187 rules.",
            "There is nothing new to install or configure. The same validate() entry point that handles a VAST tag now recognises a <vmap:VMAP> or <DAAST> root and runs the matching chain. The result carries a new document_type field (Vast, Vmap, or Daast) so you always know which rule set produced the findings. Every rule keeps the vastlint contract: a stable ID, a default severity, a spec reference, and a docs page with examples and fix guidance."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "VMAP, briefly: the where and when of ad breaks",
          "paragraphs": [
            "VMAP (Video Multiple Ad Playlist) is the IAB standard a content owner uses to describe ad-break structure when they do not control the player. It was published on July 19, 2012 and has had exactly one version since. The mental model worth keeping: VMAP handles the where and the when of ad placement (pre-roll, mid-rolls at specific offsets, post-roll), and VAST handles the what (the actual creative inside each break).",
            "A VMAP document is a playlist of <AdBreak> elements. Each break carries a timeOffset (a timecode, a percentage, the keywords start or end, or an #m position), a breakType (linear, nonlinear, display), and an <AdSource> that either embeds a VAST document inline, points at an ad tag URI, or carries custom data. That flexibility is exactly where it breaks in production."
          ]
        },
        {
          "type": "list",
          "heading": "What actually goes wrong with VMAP",
          "items": [
            "Malformed timeOffset. A mid-roll meant for 00:15:00 written as 15:00, or a stray percentage sign, silently drops the break instead of failing loud. vastlint flags the format against the spec grammar before a player ever has to guess.",
            "An <AdSource> with more than one payload, or none. The spec requires exactly one of <VASTAdData>, <AdTagURI>, or <CustomAdData>. Stitchers and ad servers that template these documents routinely emit two, or leave the element empty.",
            "AdTagURI or CustomAdData not wrapped in CDATA. URIs with query strings and ampersands corrupt the document when they are not in a CDATA block. This is the classic mid-roll that works in test and breaks on the first real macro-laden tag.",
            "Inline VAST that is broken on its own terms. A structurally valid VMAP can wrap a structurally invalid VAST. vastlint validates the embedded <VAST> with the full VAST rule chain and reports issues with /VMAP/AdBreak[i]/AdSource/VASTAdData paths plus document-absolute line and column, so you know which break failed and why.",
            "repeatAfter that does nothing. repeatAfter has no effect when timeOffset is start or end. vastlint warns instead of letting a no-op ship as if it scheduled recurring breaks."
          ]
        },
        {
          "type": "code",
          "heading": "VMAP that looks fine and is not",
          "language": "xml",
          "code": "<vmap:VMAP xmlns:vmap=\"http://www.iab.net/videosuite/vmap\" version=\"1.0\">\n  <vmap:AdBreak timeOffset=\"15:00\" breakType=\"linear\">\n    <vmap:AdSource id=\"mid-1\">\n      <vmap:AdTagURI templateType=\"vast3\">\n        https://ads.example.com/vast?cb=[CACHEBUSTER]&pos=mid\n      </vmap:AdTagURI>\n    </vmap:AdSource>\n  </vmap:AdBreak>\n</vmap:VMAP>"
        },
        {
          "type": "list",
          "heading": "What vastlint reports on that snippet",
          "items": [
            "VMAP-1.0-adbreak-timeoffset-format (error): timeOffset \"15:00\" is not a valid hh:mm:ss[.mmm], n%, start, end, or #m value. The mid-roll will not schedule where you think.",
            "VMAP-1.0-adtaguri-cdata (error): the AdTagURI contains an unescaped ampersand and is not inside a CDATA block, so the document is not well-formed once the macro expands.",
            "VMAP-1.0-root-namespace (warning) would also fire if the vmap namespace URI were missing or wrong."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "DAAST, and why audio still matters in 2026",
          "paragraphs": [
            "DAAST (Digital Audio Ad Serving Template) is the audio counterpart the IAB released for public comment in 2014. It mirrors VAST 3.0 but swaps the video assumptions for audio ones: <Category> is required, creatives carry audio MediaFiles, <VideoClicks> becomes <AdInteractions>, and the tracking event set is audio-specific.",
            "Here is the part that trips teams up: DAAST 1.0 is formally deprecated. In November 2018 the IAB merged audio support into VAST 4.1 via an optional adType attribute on the <Ad> element, and the recommendation since then is to serve audio with VAST 4.1 or later. So why validate DAAST at all in 2026?",
            "Because the money has not stopped and neither have the legacy tags. IAB and PwC put US digital audio ad spend at $8.4 billion in 2025, up 10.2% year over year, with podcast revenue alone growing 17.6% to roughly $2.9 billion. A market that large still has long-lived DAAST inventory, DSP creatives, and ad-server templates in circulation. When a DAAST tag shows up, you want to know whether it is a clean DAAST document, a DAAST document with VAST leftovers, or a VAST tag someone mislabeled. vastlint answers exactly that."
          ]
        },
        {
          "type": "list",
          "heading": "The DAAST checks that catch real mistakes",
          "items": [
            "VAST elements smuggled into DAAST. <VideoClicks> and <VASTAdTagURI> are VAST constructs. In DAAST you use <AdInteractions> and <DAASTAdTagURI>. vastlint flags both, which is the single most common symptom of a copy-pasted VAST tag wearing a DAAST root.",
            "Missing <Category>. Optional in VAST, required in DAAST. Easy to drop when a template was forked from a video flow.",
            "Video MIME types on an audio creative. A MediaFile typed video/mp4 inside a DAAST creative is almost always wrong; vastlint warns so the audio rendition is not a silent video.",
            "AudioInteractions vs AdInteractions. The element was renamed to <AdInteractions> in the final DAAST release. Old generators still emit the draft name.",
            "Audio pricing models. DAAST adds cpo (cost per order) to the usual cpm/cpc/cpe/cpv set, and requires model plus currency. vastlint validates the enum and the required attributes.",
            "Error and tracking macros. Root-level <Error> presence and the [ERRORCODE] macro are checked so failed audio impressions are actually reportable."
          ]
        },
        {
          "type": "code",
          "heading": "A VAST tag pretending to be DAAST",
          "language": "xml",
          "code": "<DAAST version=\"1.0\">\n  <Ad id=\"audio-1\">\n    <InLine>\n      <AdTitle>Morning drive spot</AdTitle>\n      <Impression><![CDATA[https://t.example.com/imp]]></Impression>\n      <Creatives>\n        <Creative>\n          <Linear>\n            <Duration>00:00:30</Duration>\n            <MediaFiles>\n              <MediaFile delivery=\"progressive\" type=\"video/mp4\">\n                <![CDATA[https://cdn.example.com/spot.mp4]]>\n              </MediaFile>\n            </MediaFiles>\n            <VideoClicks>\n              <ClickThrough><![CDATA[https://example.com]]></ClickThrough>\n            </VideoClicks>\n          </Linear>\n        </Creative>\n      </Creatives>\n    </InLine>\n  </Ad>\n</DAAST>"
        },
        {
          "type": "list",
          "heading": "vastlint's verdict",
          "items": [
            "DAAST-1.0-inline-category (error): <Category> is required in DAAST and is missing.",
            "DAAST-1.0-mediafile-audio-type (warning): the MediaFile type is video/mp4 on an audio creative.",
            "DAAST-1.0-videoclicks-element (warning): <VideoClicks> is a VAST element; DAAST uses <AdInteractions>. This is the tell that the tag was lifted from a video flow."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why this belongs in core, not a separate tool",
          "paragraphs": [
            "Ad ops teams do not deal with one format at a time. A single campaign can ship a VMAP schedule whose breaks wrap VAST 4.x creatives, while the audio line item delivers a DAAST tag. Asking people to remember which validator handles which format, and to paste tags into three different web tools, is how broken tags reach production.",
            "Putting all three formats behind one entry point removes that decision. You hand vastlint a document, it tells you what the document is, and it validates it against the right spec with consistent rule IDs and severities. Because the embedded-VAST check inside VMAP runs the same VAST chain, a wrapper problem two levels deep surfaces with a path that points straight at the break it lives in. One engine, one report format, three formats covered."
          ]
        },
        {
          "type": "list",
          "heading": "Where the same checks run",
          "items": [
            "CLI: validate VMAP and DAAST files in a pre-flight step or a git hook, same command you already use for VAST.",
            "Library: call validate() and branch on document_type; the result shape is identical across formats.",
            "CI: gate merges on a clean run so a malformed timeOffset or a DAAST tag with VAST leftovers never reaches a release.",
            "MCP server: an AI agent doing campaign QA can validate a VMAP playlist or an audio tag through the same tool surface it uses for VAST."
          ]
        },
        {
          "type": "cta",
          "heading": "Validate a VMAP or DAAST tag now",
          "paragraph": "Paste a VMAP playlist or a DAAST audio tag into the validator. It detects the document type and returns every issue with a rule ID, severity, and the exact fix, the same way it does for VAST.",
          "href": "/validate/",
          "label": "Open the validator"
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Video Multiple Ad Playlist (VMAP) 1.0 specification",
              "href": "https://www.iab.com/wp-content/uploads/2015/06/VMAPv1_0.pdf",
              "description": "The original IAB VMAP 1.0 PDF, published July 19, 2012. The grammar vastlint's VMAP rules are derived from.",
              "source": "IAB"
            },
            {
              "label": "Digital Audio Ad Serving Template (DAAST)",
              "href": "https://www.iab.com/guidelines/daast/",
              "description": "IAB's DAAST landing page, including the deprecation note pointing audio buyers to VAST 4.1 and above.",
              "source": "IAB"
            },
            {
              "label": "VAST 4.1 release: DAAST merged into VAST",
              "href": "https://www.iab.com/news/vast-4-1/",
              "description": "The November 2018 release that folded audio support into VAST via the adType attribute.",
              "source": "IAB"
            },
            {
              "label": "IAB: digital audio ad spend hits $8.4B in 2025",
              "href": "https://radioink.com/2026/04/16/iab-digital-audio-grew-10-in-2025-as-podcasts-near-3b/",
              "description": "IAB/PwC data on 2025 digital audio growth and podcast revenue, the reason legacy audio tags still circulate.",
              "source": "Radio Ink"
            }
          ]
        }
      ]
    },
    {
      "slug": "vastlint-vs-springserve-vast-tag-tester",
      "title": "vastlint vs SpringServe VAST Tag Tester",
      "description": "Paste the live URL at vastlint.org/tester/. SpringServe's tagtest is a player-style check for VAST and VMAP. vastlint owns the standards layer: public rules, hop-by-hop inspection, CLI and CI.",
      "publishedAt": "2026-06-11",
      "updatedAt": "2026-06-11",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "SpringServe",
        "VAST tester",
        "VAST validator",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "Paste the live VAST URL at https://vastlint.org/tester/. Free, no signup: fetch, preview, tracking. SpringServe's tag tester at tools.springserve.com/tagtest is a fast player-style check for VAST and VMAP: events, diagram, metadata. If the question is whether the tag does something in a player right now, it is a reasonable spot check. Wrapper hops are https://vastlint.org/inspect/.",
            "vastlint answers a different and earlier question: is this tag structurally compliant with the published IAB VAST specifications? It validates VAST 2.0 through 4.3 against public, spec-derived rules, splits the job into a validator for resolved XML, a tester for live URLs, and a wrapper-chain inspector, and ships the same rule engine as a CLI, library, and MCP server you can put in CI.",
            "For most debugging sessions the order matters more than the tool choice. Validate the XML against the standards first, then watch player behavior. Playback symptoms on top of structurally invalid XML are mostly noise."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use SpringServe tagtest when you want a quick player-style event check with a visual diagram of the request flow.",
            "Use SpringServe tagtest when the input is a VMAP document and you want to watch the break structure play out. vastlint's VMAP validation is on the public roadmap but has not shipped yet.",
            "Use vastlint when you need to know whether the tag is compliant with a specific VAST version, with a rule ID, severity, and spec reference for every issue.",
            "Use vastlint when the failure is somewhere inside a wrapper chain and you need hop-by-hop inspection instead of a single end-to-end result.",
            "Use vastlint when validation has to run outside a browser session: CLI, CI, server-side pipelines, or an AI agent calling the MCP server.",
            "Use both when the campaign is valuable: standards validation first, player-style behavior check second."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What SpringServe's tag tester shows on its public surface",
          "paragraphs": [
            "The public tool accepts VAST and VMAP input and reports a player view, the tags tested, the events that fired, a request-flow diagram, and tag metadata. That is genuinely useful for operational spot checks, especially when you want to see event firing without wiring up a test page yourself, and it is a natural fit for teams already working inside the SpringServe ecosystem.",
            "What the public page does not surface is the standards layer. No VAST version support matrix is published, there are no public rule-by-rule diagnostics, no documented methodology for what is checked and why, and no public path to embed the checks in your own pipeline. None of that means the tool is bad. It means the public surface is a tester, not a validation product."
          ]
        },
        {
          "type": "list",
          "heading": "Where vastlint closes the gap",
          "items": [
            "Public rule docs: every rule has its own page with the rule ID, why it fires, and a copyable XML fix.",
            "Published methodology: rules are derived from IAB XSD schemas where they exist and RFC 2119 normative prose where they do not, including VAST 4.3, which has no published XSD.",
            "Current version coverage: VAST 2.0, 3.0, 4.0, 4.1, 4.2, and 4.3 are all validated, with automatic version detection.",
            "Three separated surfaces: a validator for resolved XML, a tester for live URL fetches with creative preview and tracking visibility, and an inspector that unwraps wrapper chains hop by hop.",
            "Reusable engine: the same Rust core ships as a CLI, Go and npm packages, a VS Code extension, and an MCP server, so the check that ran in the browser also runs in CI and server-side systems."
          ]
        },
        {
          "type": "quote",
          "quote": "A player-style tester tells you what happened. A standards validator tells you what is wrong and which line to fix.",
          "attribution": "vastlint field note"
        },
        {
          "type": "code",
          "heading": "Recommended workflow when SpringServe is part of QA",
          "language": "text",
          "code": "# 1. Validate the resolved VAST XML in the vastlint validator\n# 2. If the tag is a live URL, unwrap each hop in the vastlint inspector\n# 3. Run the vastlint tester for creative preview and tracking visibility\n# 4. Fix structural issues first; every rule links to the exact XML fix\n# 5. Finish with a SpringServe player-style pass if the team wants event-level confirmation"
        },
        {
          "type": "list",
          "heading": "When vastlint is the better first choice",
          "items": [
            "The tag fails somewhere and you need the exact element, attribute, and spec reference rather than a playback symptom.",
            "You are trafficking VAST 4.3 or need consistent checks across all six VAST versions.",
            "Validation has to be repeatable: pre-commit, CI, or inline in an SSP, DSP, or ad-server pipeline.",
            "The chain involves multiple wrappers and you need to see which hop breaks.",
            "An AI agent or automated workflow needs a structured pass/fail with rule IDs, via the MCP server."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When SpringServe tagtest still earns a spot",
          "paragraphs": [
            "If your demand or supply partner runs SpringServe, testing in the same environment they use is a legitimate final check. The event view and request-flow diagram are quick to read, and the VMAP support covers a format vastlint does not validate yet.",
            "The mistake to avoid is treating a player-style pass as proof of standards compliance. A tag can play in one tester and still carry structural issues that fail in stricter players, CTV SDKs, or SSAI environments. Run the standards layer first and the player layer second."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "SpringServe Tag Tester",
              "href": "http://tools.springserve.com/tagtest",
              "description": "SpringServe's public tag testing tool: player view, tags tested, events, diagram, and metadata for VAST and VMAP input.",
              "source": "SpringServe"
            },
            {
              "label": "Best VAST validator tools in 2026",
              "href": "/blog/best-vast-validator-tools-2026/",
              "description": "The full comparison roundup: IAB Tech Lab, Google IMA, AdMeIn, SpringServe, AdServe, and vastlint.",
              "source": "Blog"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How vastlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/docs/validate-vast-xml/",
              "description": "How to choose between validating resolved XML and testing a live tag URL.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Run the standards layer first",
          "paragraph": "Validate the resolved XML against public, spec-derived rules before any player-style pass. Every issue comes back with a rule ID, severity, and the exact fix.",
          "href": "/validate/",
          "label": "Open the VAST tag validator"
        }
      ]
    },
    {
      "slug": "vastlint-vs-adserve-vast-inspector",
      "title": "vastlint vs AdServe VAST Inspector",
      "description": "AdServe's VAST Inspector is a capable player-style tester that plays the ad and pings tracking URLs, with advertised support through VAST 4.2. vastlint covers VAST 2.0–4.3 with public rule docs, a published methodology, hop-by-hop wrapper inspection, and an engine you can embed in CI. Here is how the two fit together.",
      "publishedAt": "2026-06-11",
      "updatedAt": "2026-06-11",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "AdServe",
        "VAST inspector",
        "VAST validator",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "AdServe's VAST Inspector at adserve.tv accepts a VAST tag URL or raw XML, including VPAID creatives, and runs it through a player that attempts to interpret the response, play the ad, and ping the tracking URLs. Its public page advertises support for linear, wrapper, ad pod, redirects, event tracking, click tracking, and measurement reports across VAST 2.0 through 4.2. As a playback-style check, that is a solid surface.",
            "vastlint approaches the same tag from the standards side. It validates VAST 2.0 through 4.3 against public, spec-derived rules, documents every rule with a copyable fix, separates validation, live-URL testing, and wrapper inspection into three tools, and ships the engine as a CLI, library, and MCP server for CI and server-side use.",
            "The name overlap is worth untangling: AdServe's “inspector” is a playback inspector: it watches the ad run. vastlint's inspector is a wrapper-chain inspector: it unwraps each redirect hop and validates every response on the way to the InLine. Those are different jobs, and most broken tags need the second one first."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use AdServe when you want to watch the ad actually play and see tracking pings fire in a browser session.",
            "Use AdServe when you are still maintaining legacy VPAID creatives and want a public player that will attempt to run them.",
            "Use vastlint when you need spec compliance with a rule ID, severity, and spec reference for every issue, including VAST 4.3, which AdServe's public page does not advertise.",
            "Use vastlint when the failure is inside a wrapper chain and you need to see exactly which hop breaks.",
            "Use vastlint when the check has to run outside a browser: CLI, CI, server-side pipelines, or AI agents via MCP.",
            "Use both on high-value campaigns: standards validation first, playback confirmation second."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What AdServe's inspector shows on its public surface",
          "paragraphs": [
            "The public page advertises a genuinely broad playback surface: linear and wrapper handling, ad pods, redirects, event tracking, click tracking, and measurement reports, with VAST support listed for 2.0, 3.0, and 4.0 through 4.2. The player-based approach means you see real interpretation behavior: the tool tries to play the ad and fire the trackers rather than just parsing the XML.",
            "What the public page does not surface is the layer underneath. Advertised version support stops at 4.2 rather than 4.3, there is no public rule-by-rule catalog or derivation methodology, no distinct wrapper-inspection workflow separate from playback, and no public path to embed the checks in CI or a server-side pipeline. As with most player-style testers, the public surface is the playback experience itself."
          ]
        },
        {
          "type": "list",
          "heading": "Where vastlint closes the gap",
          "items": [
            "VAST 4.3 coverage: 4.3 has no published IAB XSD, so vastlint derives its 4.3 rules from the normative spec prose and documents how.",
            "Public rule docs: every error links to a rule page with the reason it fires and a copyable XML fix.",
            "A dedicated wrapper-chain inspector: each redirect hop is fetched, parsed, and validated individually, so you see where the chain breaks instead of a single end-to-end outcome.",
            "VPAID handling that matches where the industry is: vastlint detects VPAID, flags it as deprecated, and routes you to the SIMID/OMID migration path rather than just playing the legacy creative.",
            "An embeddable engine: the same Rust core runs in the web tools, the CLI, Go and npm packages, and the MCP server, so validation is repeatable in CI and ad-serving pipelines."
          ]
        },
        {
          "type": "quote",
          "quote": "Playing the ad proves it played in that player today. Validating the tag proves what every spec-compliant player can expect from it.",
          "attribution": "vastlint field note"
        },
        {
          "type": "code",
          "heading": "Recommended workflow when AdServe is part of QA",
          "language": "text",
          "code": "# 1. Validate the resolved VAST XML in the vastlint validator\n# 2. If the tag is a live URL, unwrap each redirect hop in the vastlint inspector\n# 3. Run the vastlint tester for creative preview and tracking visibility\n# 4. Fix structural issues first; each one links to the exact XML fix\n# 5. Finish with an AdServe playback pass if you want to watch the ad run and ping trackers"
        },
        {
          "type": "list",
          "heading": "When vastlint is the better first choice",
          "items": [
            "You traffic VAST 4.3 or need one consistent rule set across all six VAST versions.",
            "A player rejected the tag and you need the exact element and spec reference, not a playback symptom.",
            "The tag redirects through multiple wrappers and you need hop-by-hop visibility.",
            "You are migrating VPAID creatives and need deprecation detection plus a documented migration path.",
            "Validation must be automated: pre-traffic checks in CI, inline checks in an SSP or ad server, or agent-driven checks over MCP."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When AdServe still earns a spot in the workflow",
          "paragraphs": [
            "A playback pass that pings real tracking URLs is a useful final confirmation, and AdServe's public surface covers a wide range of playback scenarios including ad pods and legacy VPAID. If your team wants to watch the creative run before sign-off, it is a reasonable place to do it.",
            "Just keep the layers in order. A tag that plays in one public tester can still fail in stricter players, CTV SDKs, or SSAI environments because of structural issues a playback session never exposes. Validate against the published standards first, then confirm playback."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "AdServe VAST Inspector",
              "href": "https://adserve.tv/vast-inspector/",
              "description": "AdServe's public inspector page, including its advertised VAST 2.0–4.2 support and playback, tracking, and reporting claims.",
              "source": "AdServe"
            },
            {
              "label": "Best VAST validator tools in 2026",
              "href": "/blog/best-vast-validator-tools-2026/",
              "description": "The full comparison roundup: IAB Tech Lab, Google IMA, AdMeIn, SpringServe, AdServe, and vastlint.",
              "source": "Blog"
            },
            {
              "label": "Inspect a VAST wrapper chain",
              "href": "/inspect/",
              "description": "vastlint's hop-by-hop wrapper-chain inspector: every redirect fetched, parsed, and validated.",
              "source": "Tool"
            },
            {
              "label": "VPAID is deprecated: migration guide",
              "href": "/docs/vpaid/",
              "description": "What replaced VPAID, how to detect it in a tag, and how to migrate to SIMID and OMID.",
              "source": "Docs"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How vastlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate before you press play",
          "paragraph": "Run the tag through spec-derived validation first. Every issue comes back with a rule ID, severity, and the exact fix. Then confirm playback wherever your team prefers.",
          "href": "/validate/",
          "label": "Open the VAST tag validator"
        }
      ]
    },
    {
      "slug": "agentic-buying-needs-a-harness",
      "title": "Agentic Buying Doesn't Fail at Intelligence. It Fails Without a Harness",
      "description": "Two-thirds of ad buyers are ramping up agentic AI while verification stays manual. The lesson from coding agents and from the IAB's own agentic roadmap is the same: autonomy only works inside a deterministic harness, and validators like vastlint are that layer for video delivery.",
      "publishedAt": "2026-06-11",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Agentic advertising",
      "tags": [
        "Agentic",
        "Standards",
        "Automation",
        "MCP"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Buying is going agentic faster than verification is",
          "paragraphs": [
            "The IAB's 2026 Outlook Study puts numbers on what every trading desk already feels: 96% of buyers are aware of agentic AI for ad buying, and 66% are increasing their focus on it for buying and campaign execution this year. At the same time, 40% of those buyers name understanding agentic AI as an investment challenge.",
            "Video is moving even faster. In the IAB's 2026 Digital Video Ad Spend & Strategy Report, two in three digital video buyers are already live (21%), testing (20%), or planning to use (25%) agentic AI for video campaigns, with another 28% actively investigating.",
            "So execution is being automated at speed. What is not being automated at the same speed is verification: the step that decides whether what the agent produced will actually deliver, play, and track. That gap is where agentic buying breaks."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What coding agents already proved about autonomy",
          "paragraphs": [
            "Software engineering went through this exact transition first, and the result was unambiguous: coding agents did not become useful because models got smarter in isolation. They became useful because they run inside a harness: a compiler, a type checker, a linter, a test suite, CI. Every action the agent takes gets deterministic, machine-readable feedback, and the agent iterates against that feedback until the work passes.",
            "Take the harness away and an LLM writing code is just producing plausible-looking text. Nobody ships that.",
            "A media-buying agent assembling a deal and trafficking a video tag is in the same position, except worse: there is no compiler for a VAST tag. XML that is well-formed can still reference a deprecated VPAID creative, omit a required Duration, carry an insecure tracker, or bury the media file four wrappers deep. The agent needs the same loop a coding agent gets (act, validate, repair, re-validate), and that loop requires a deterministic validator it can call as a tool."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The standards bodies are building the protocols. Protocols are not verification",
          "paragraphs": [
            "The industry's standards work confirms the direction. In January 2026, IAB Tech Lab released AAMP (Agentic Advertising Management Protocols) v1.0, an umbrella framework for agent-driven advertising that deliberately builds on existing standards: OpenRTB, AdCOM, OpenDirect, and VAST, wired together with modern agent protocols like the Model Context Protocol and Agent2Agent. Tech Lab's own framing is blunt: without speed, structure, security, and trust, there's no agentic advertising future worth having.",
            "A few months earlier, in October 2025, a consortium including Yahoo, PubMatic, Optable, Scope3, Swivel, and Triton Digital launched the Ad Context Protocol (AdCP), an open standard built on MCP that lets buyer and seller agents exchange context and orchestrate buys across platforms.",
            "Both efforts solve the communication problem: how agents discover inventory, negotiate, and transact. Neither one verifies that the payload changing hands is correct. When a human trafficker is removed from the loop and both sides of a transaction are machines, nobody is left to eyeball the tag. Protocol adoption makes payload validation more urgent, not less. It is the missing rung between agents that can transact and agents that can be trusted to."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Programmatic already showed what automation without verification costs",
          "paragraphs": [
            "We do not have to speculate about what happens when execution is automated and verification is not, because programmatic already ran the experiment. The ANA's Programmatic Transparency Benchmark found $26.8 billion in wasted global programmatic spend in its Q2 2025 report, up 34% from the roughly $20 billion its landmark 2023 study identified. The same research found the average campaign running across 44,000 websites when a few hundred would reach most of the audience.",
            "Programmatic automated the buying loop and left quality checking to quarterly reports and post-campaign audits. Agentic buying shortens the decision loop from hours to seconds. Run that loop without inline verification and the waste does not shrink. It compounds at machine speed."
          ]
        },
        {
          "type": "list",
          "heading": "What the harness layer has to provide",
          "items": [
            "Deterministic results: the same input produces the same findings every run, with stable rule IDs an agent can branch on.",
            "Machine-readable output: structured JSON and exit codes that can gate a pipeline, not prose a human has to interpret.",
            "Spec grounding: every rule traceable to a section of the IAB VAST, OMID, or SIMID specs, so a failure is a standards violation, not a vendor opinion.",
            "Availability everywhere agents run: as a CLI for pipelines, as native libraries inside ad servers, as a CI action, and as an MCP tool agents can call directly.",
            "Wrapper-chain resolution, so what gets validated is what the player will actually receive, not just the first hop.",
            "Bounded auto-repair: deterministic, low-risk fixes only, always followed by re-validation.",
            "One shared gate for humans and agents, so QA standards do not drift between the two."
          ]
        },
        {
          "type": "code",
          "heading": "The loop, concretely",
          "language": "bash",
          "code": "# deterministic gate inside an agentic workflow\nvastlint check tag.xml --format json --fail-on-warning\n\n# the agent gets structured findings, not prose:\n# {\"id\":\"VAST-2.0-inline-adsystem\",\"severity\":\"error\",\n#  \"path\":\"/VAST/Ad[0]/InLine\",\"spec_ref\":\"IAB VAST 2.0 §2.2.1\"}\n\n# bounded deterministic repair, then re-validate\nvastlint fix tag.xml --dry-run\nvastlint check tag.xml --format json"
        },
        {
          "type": "paragraphs",
          "heading": "Where vastlint sits in that stack",
          "paragraphs": [
            "Video is where the payload is most fragile and most expensive. The IAB projects U.S. digital video ad spend to surpass $80 billion in 2026, with CTV alone at $29.3 billion, and VAST is the delivery contract underneath nearly all of it.",
            "vastlint is the lint layer for that contract: 233 deterministic rules mapped to the IAB VAST, OMID, and SIMID specs, with stable rule IDs, NDJSON output, wrapper unwrapping, and a deliberately conservative fix mode. It runs as a CLI, as Go and Rust libraries, as a GitHub Action, and as a hosted MCP server: the same gate whether the caller is an ops analyst, a CI job, or a buying agent.",
            "To be clear about scope: payload validation is one slice of the harness, not the whole thing. Agentic buying will also need gates for brand safety, supply path, and pacing. But the creative delivery payload is the most compiler-like piece of the problem: fully specified by IAB standards, deterministically checkable. It is the slice you can put in front of an agent today."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "Agentic docs",
              "href": "/docs/agentic/",
              "description": "Where agentic workflows fit into the vastlint operating model.",
              "source": "Docs"
            },
            {
              "label": "MCP docs",
              "href": "/docs/mcp/",
              "description": "The hosted MCP surface: validation, rule catalog, wrapper inspection, and safe auto-fix as agent tool calls.",
              "source": "Docs"
            },
            {
              "label": "AdCP docs",
              "href": "/docs/adcp/",
              "description": "How validation integrates with Ad Context Protocol workflows.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML",
              "href": "/docs/validate-vast-xml/",
              "description": "Core validator behavior and the rule catalog the gate enforces.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Agentic Advertising and AI Initiatives (AAMP)",
              "href": "https://iabtechlab.com/standards/agentic-advertising-and-ai/",
              "description": "IAB Tech Lab's AAMP v1.0 framework: agentic protocols built on OpenRTB, AdCOM, OpenDirect, VAST, MCP, and A2A.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "2026 Outlook Study",
              "href": "https://www.iab.com/insights/2026-outlook/",
              "description": "Buyer adoption data: 96% awareness of agentic AI for buying, 66% increasing focus, 40% citing it as an investment challenge.",
              "source": "IAB"
            },
            {
              "label": "2026 Digital Video Ad Spend & Strategy Report",
              "href": "https://www.iab.com/insights/video-ad-spend-report-2026/",
              "description": "U.S. digital video spend surpassing $80B, CTV at $29.3B, and agentic AI adoption among video buyers.",
              "source": "IAB"
            },
            {
              "label": "Q2 2025 Programmatic Transparency Benchmark",
              "href": "https://www.ana.net/content/show/id/pr-2025-08-programmatictrans",
              "description": "$26.8B in annual wasted programmatic spend, up 34% from the 2023 study.",
              "source": "ANA"
            },
            {
              "label": "Ad Context Protocol: Introduction",
              "href": "https://docs.adcontextprotocol.org/docs/intro",
              "description": "The open, MCP-based standard for agent-to-agent media transactions launched in October 2025.",
              "source": "AdCP"
            },
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The canonical delivery contract every payload gate ultimately checks against.",
              "source": "IAB Tech Lab"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Put a gate in front of your agents",
          "paragraph": "The hosted MCP endpoint exposes validation, wrapper inspection, rule listing, and safe auto-fix: the same deterministic harness in agent workflows, CI, and human QA.",
          "href": "/docs/mcp/",
          "label": "View MCP docs"
        }
      ]
    },
    {
      "slug": "how-to-validate-omid-in-vast-tags",
      "title": "How to Validate OMID in VAST 4.1-4.3 Tags with VASTlint",
      "description": "OMID validation starts in the VAST XML long before the player runs OM SDK. Learn which VAST versions matter, what vastlint checks today, how the release channels differ, and how to validate OMID blocks from the web UI, CLI, npm package, or MCP.",
      "publishedAt": "2026-06-09",
      "updatedAt": "2026-06-09",
      "author": "Alex Sekowski",
      "readingTime": "10 min read",
      "heroKicker": "OMID validation",
      "tags": [
        "OMID",
        "Google IMA",
        "VAST 4.1",
        "Ad verification"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "OMID validation in VAST starts with the XML. If the Verification vendor is malformed, the JavaScriptResource is insecure, the same vendor is duplicated, or verification tracking is wired incorrectly, the measurement stack starts broken before the player has a chance to execute OM SDK.",
            "vastlint can catch the VAST-side OMID mistakes early in the web validator, CLI, npm package, Rust core, and MCP workflow. What it cannot do is prove runtime viewability or compliance by itself. IAB Tech Lab's OM SDK and Google's IMA docs are clear that actual measurement still depends on the player integration, supported access modes, and the measurement provider scripts that run at playback time."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What OMID is doing in the tag",
          "paragraphs": [
            "IAB Tech Lab positions OM SDK as the standard measurement layer for digital video, CTV, mobile, and web. The VAST side of that integration is the AdVerifications block: the tag tells the player which verification vendor resources exist, and the runtime exposes measurement signals through the OMID API once playback actually begins.",
            "Google IMA's OM SDK guide is a useful operational reference here. It says the HTML5 SDK automatically parses AdVerifications in VAST tags and sends viewability data to the specified measurement vendors. It also calls out the version split directly: VAST 4.1 and higher should use AdVerifications, while earlier versions can carry the same data inside Extension type=\"AdVerifications\" for compatibility."
          ]
        },
        {
          "type": "list",
          "heading": "Which VAST versions matter for OMID",
          "items": [
            "VAST 4.1 is where IAB Tech Lab explicitly introduces improved ad verification and ad creative measurement. In normal modern tags, that means AdVerifications and Verification blocks.",
            "VAST 4.2 keeps the same OMID model while adding SIMID on the interactivity side, which is why teams often think about SIMID and OMID together when replacing VPAID-era payloads.",
            "VAST 4.3 adds browserOptional on JavaScriptResource, so a validator that understands 4.3 should also know when that attribute is missing.",
            "If you still receive older VAST documents, some players and SDKs support OM verification via Extension type=\"AdVerifications\" instead of top-level AdVerifications. That compatibility path matters in real traffic, even if your trafficking policy prefers 4.1+."
          ]
        },
        {
          "type": "list",
          "heading": "What OMID XML validation can catch before playback",
          "items": [
            "Missing Verification vendor attributes or missing verification resources altogether.",
            "JavaScriptResource or ExecutableResource blocks that omit apiFramework or use a non-OMID value when the resource is clearly meant for OM measurement.",
            "HTTP verification resources that should be HTTPS in secure runtimes.",
            "Duplicate vendor identifiers inside the same AdVerifications block.",
            "Vendor identifiers that are too loose to be useful operationally, such as bare names instead of domain-qualified identifiers.",
            "Missing or empty VerificationParameters for OMID payloads that need runtime configuration.",
            "Verification tracking wired to the wrong event model instead of the verificationNotExecuted path used by VAST verification blocks.",
            "verificationNotExecuted tracking URLs that omit the [REASON] macro, which makes later debugging much weaker than it needs to be."
          ]
        },
        {
          "type": "code",
          "heading": "A minimal OMID block that should pass in VAST 4.3",
          "language": "xml",
          "code": "<AdVerifications>\n  <Verification vendor=\"measurement.example.com-omid\">\n    <JavaScriptResource apiFramework=\"omid\" browserOptional=\"true\"><![CDATA[https://cdn.measurement.example.com/omsdk/omid.js]]></JavaScriptResource>\n    <VerificationParameters><![CDATA[{\"campaign\":\"spring-launch\"}]]></VerificationParameters>\n    <TrackingEvents>\n      <Tracking event=\"verificationNotExecuted\"><![CDATA[https://tracker.example.com/omid?reason=[REASON]]]></Tracking>\n    </TrackingEvents>\n  </Verification>\n</AdVerifications>"
        },
        {
          "type": "paragraphs",
          "heading": "Why that example is version-specific",
          "paragraphs": [
            "The core shape there is VAST 4.1+: Verification vendor, verification resource, optional VerificationParameters, and verification tracking. The browserOptional attribute is the part that matters specifically to VAST 4.3 JavaScriptResource handling.",
            "If your player stack is older, the compatibility question is not just whether the XML is technically well-formed. It is whether the runtime expects AdVerifications directly or an Extension wrapper, and whether the player actually has OM SDK support on that platform."
          ]
        },
        {
          "type": "code",
          "heading": "A block that looks plausible but should be flagged",
          "language": "xml",
          "code": "<AdVerifications>\n  <Verification vendor=\"moat\">\n    <JavaScriptResource apiFramework=\"OMSDK\"><![CDATA[http://measurement.example.com/omid.js]]></JavaScriptResource>\n    <TrackingEvents>\n      <Tracking event=\"start\"><![CDATA[https://tracker.example.com/omid?reason=[REASON]]]></Tracking>\n      <Tracking event=\"verificationNotExecuted\"><![CDATA[https://tracker.example.com/omid]]></Tracking>\n    </TrackingEvents>\n  </Verification>\n  <Verification vendor=\"moat\">\n    <JavaScriptResource apiFramework=\"omid\"><![CDATA[https://measurement.example.com/secondary.js]]></JavaScriptResource>\n  </Verification>\n</AdVerifications>"
        },
        {
          "type": "list",
          "heading": "What the latest OMID rule set should complain about",
          "items": [
            "VAST-4.1-verification-vendor-format because a bare vendor name like moat is weak compared with a domain-qualified identifier such as company.com-omid.",
            "VAST-4.1-verification-duplicate-vendor because the same vendor appears twice in one AdVerifications block.",
            "VAST-4.1-js-resource-apiframework-value because an OM verification resource should declare apiFramework=\"omid\".",
            "VAST-4.1-js-resource-https because the first JavaScriptResource points at HTTP instead of HTTPS.",
            "VAST-4.1-verification-parameters because neither Verification includes non-empty VerificationParameters.",
            "A verification tracking event error because Tracking under Verification is not the same event set as Linear tracking; verificationNotExecuted is the allowed path here.",
            "VAST-4.1-verification-tracking-reason because the verificationNotExecuted tracker omits the [REASON] macro."
          ]
        },
        {
          "type": "list",
          "heading": "Which vastlint channel to use",
          "items": [
            "The web validator at vastlint.org/validate is the fastest manual check when ad ops or QA needs to paste a live tag and spot obvious OMID mistakes without installing anything.",
            "The current published npm package line is 0.4.23. It already catches the core AdVerifications shape: required vendor and resource attributes, apiFramework requirements, and the VAST 4.3 browserOptional warning.",
            "The deepest OMID coverage in the June 9 release line is in vastlint-core and the CLI at 0.4.24. That adds vendor format, duplicate-vendor detection, VerificationParameters guidance, HTTPS resource semantics, pre-4.1 Extension compatibility checks, and verificationNotExecuted tracking validation.",
            "If you are gating launches in CI, use the CLI or core first. If you are spot-checking tags with humans, the website and npm package are the easiest entry points. If you are wiring validation into agentic QA, the MCP surface is the right shape."
          ]
        },
        {
          "type": "code",
          "heading": "Use the CLI when OMID should block launch",
          "language": "sh",
          "code": "vastlint check omid-example.xml --format json\n\n# Gate on warnings too when OMID hygiene matters\nvastlint check omid-example.xml --fail-on-warning"
        },
        {
          "type": "code",
          "heading": "Use the npm package inside a web or Node pipeline",
          "language": "ts",
          "code": "import { validate } from 'vastlint';\n\nconst result = validate(xmlString);\n\nconst omidIssues = result.issues.filter((issue) =>\n  issue.id.includes('verification') ||\n  issue.id.includes('js-resource') ||\n  issue.id.includes('exec-resource') ||\n  issue.id.includes('browser-optional')\n);\n\nfor (const issue of omidIssues) {\n  console.log(issue.id, issue.severity, issue.message);\n}"
        },
        {
          "type": "code",
          "heading": "Use the hosted MCP tool in agent workflows",
          "language": "json",
          "code": "{\n  \"tool\": \"validate_vast\",\n  \"input\": {\n    \"xml\": \"<VAST version='4.3'><Ad id='omid-demo'><InLine><AdSystem>example-ad-server</AdSystem><AdTitle>OMID demo</AdTitle><AdServingId>omid-demo-serving-id</AdServingId><Impression><![CDATA[https://tracker.example.com/impression]]></Impression><Creatives><Creative><UniversalAdId idRegistry='unknown'>omid-demo</UniversalAdId><Linear><Duration>00:00:15</Duration><TrackingEvents><Tracking event='start'><![CDATA[https://tracker.example.com/start]]></Tracking><Tracking event='firstQuartile'><![CDATA[https://tracker.example.com/firstQuartile]]></Tracking><Tracking event='midpoint'><![CDATA[https://tracker.example.com/midpoint]]></Tracking><Tracking event='thirdQuartile'><![CDATA[https://tracker.example.com/thirdQuartile]]></Tracking><Tracking event='complete'><![CDATA[https://tracker.example.com/complete]]></Tracking></TrackingEvents><MediaFiles><MediaFile delivery='progressive' type='video/mp4' width='1280' height='720'><![CDATA[https://cdn.example.com/video.mp4]]></MediaFile></MediaFiles></Linear></Creative></Creatives><AdVerifications><Verification vendor='measurement.example.com-omid'><JavaScriptResource apiFramework='omid' browserOptional='true'><![CDATA[https://cdn.measurement.example.com/omid.js]]></JavaScriptResource><VerificationParameters><![CDATA[campaign=spring-launch]]></VerificationParameters></Verification></AdVerifications></InLine></Ad></VAST>\"\n  }\n}"
        },
        {
          "type": "paragraphs",
          "heading": "What OMID XML validation cannot prove",
          "paragraphs": [
            "This boundary matters. A valid AdVerifications block is necessary, but it is not the same thing as successful OM SDK measurement in the player. Google's IMA guide says the SDK parses AdVerifications and can apply access mode rules per vendor, which means runtime behavior still depends on the player and SDK configuration rather than XML alone.",
            "That is why the right operational split is: validate the XML before launch, then verify runtime measurement separately in the player or SDK environment you actually ship. vastlint handles the first job. OM SDK compliance and viewability outcomes still require the second."
          ]
        },
        {
          "type": "quote",
          "quote": "Validate the XML before you ask OM SDK to explain a runtime problem.",
          "attribution": "vastlint field note"
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "VAST validator",
              "href": "/validate/",
              "description": "Paste a full VAST tag into the live validator and inspect the verification issues before launch.",
              "source": "Tool"
            },
            {
              "label": "VAST 4.0 to 4.1 migration guide",
              "href": "/docs/vast-4-to-4-1/",
              "description": "Where AdVerifications, OMID resources, and the VAST 4.1 verification model actually enter the standard.",
              "source": "Docs"
            },
            {
              "label": "VAST 4.2 to 4.3 guide",
              "href": "/docs/vast-4-2-to-4-3/",
              "description": "Useful when you need the browserOptional context for OMID JavaScriptResource handling in VAST 4.3.",
              "source": "Docs"
            },
            {
              "label": "VPAID is deprecated",
              "href": "/docs/vpaid/",
              "description": "Why the forward path is standard playback for media, SIMID for interactivity, and OMID for measurement.",
              "source": "Docs"
            },
            {
              "label": "MCP docs",
              "href": "/docs/mcp/",
              "description": "How to expose VAST validation as a tool call in agentic ad-ops workflows.",
              "source": "Docs"
            },
            {
              "label": "Rule reference",
              "href": "/docs/rules/",
              "description": "Browse the current rule catalog and search for OMID-related verification rules by ID.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "IAB Tech Lab OM SDK",
              "href": "https://iabtechlab.com/standards/open-measurement-sdk/",
              "description": "The official OM SDK overview, platform coverage, developer guides, and compliance resources.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST standards",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The official VAST standards hub and version history, including the 4.1 and 4.3 context for verification and measurement changes.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Google IMA: Enable Open Measurement",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/omsdk",
              "description": "Useful runtime guidance on how AdVerifications are parsed, which VAST versions use AdVerifications directly, and how OMID access modes work in the HTML5 SDK.",
              "source": "Google IMA"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate an OMID tag now",
          "paragraph": "Paste a VAST 4.1-4.3 tag into the web validator, or move the same XML into the CLI if OMID issues should gate launch approval in CI.",
          "href": "/validate/",
          "label": "Open the validator"
        }
      ]
    },
    {
      "slug": "using-vastlint-go-in-ad-serving-components",
      "title": "Using vastlint-go in Ad Serving Components to Validate and Unwrap Programmatic VAST",
      "description": "If your Go ad server accepts VAST from programmatic demand, do not forward it blind. Validate every hop, unwrap wrappers safely, quarantine broken trackers and unsupported creatives, and reduce the compliance blind spots that leak revenue.",
      "publishedAt": "2026-06-07",
      "updatedAt": "2026-06-07",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Ad serving with Go",
      "tags": [
        "vastlint-go",
        "Ad server",
        "Programmatic demand",
        "Tracking pixels"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If your serving component receives VAST from DSPs, SSPs, exchanges, or reseller wrapper chains, the safest posture is to treat every response as untrusted input. Fetch the first hop, validate it in process with vastlint-go, unwrap only when the wrapper is structurally sound, and keep validating until you reach the final inline creative or a policy limit.",
            "That pattern does two jobs at once. It catches spec and hygiene failures before the player eats the loss, and it gives your ad server one deterministic place to enforce business policy: wrapper depth, HTTPS-only delivery, tracker sanity, supported interactivity, and minimum measurement requirements for the inventory class."
          ]
        },
        {
          "type": "list",
          "heading": "What breaks first when you relay demand-side VAST blindly",
          "items": [
            "A wrapper arrives without a usable VASTAdTagURI because the upstream macro resolved to empty text, so the chain stops before the creative ever resolves.",
            "Extra wrapper hops add latency and fragility long before anyone hits a formal maximum, which turns live delivery into soft no-fill and silent underdelivery.",
            "Impression, quartile, click, error, or verification URLs still point at HTTP or stale staging hosts, so secure runtimes block them or your reporting trail becomes noise.",
            "Each wrapper adds more trackers, and nobody can tell the difference between legitimate accumulation and accidental duplication, so billing and discrepancy reviews start from a bad inventory of beacons.",
            "The tag carries VPAID or browser-only verification assumptions into CTV, SSAI, or restricted runtimes that expect SIMID, OMID, or a safer fallback path.",
            "MediaFiles technically exist, but the MIME type, codec, bitrate, or asset profile does not line up with what the receiving runtime will actually select and render.",
            "Click and viewability expectations are copied from desktop web into runtimes where event coverage is partial, full-screen behavior differs, or measurement requires extra configuration."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Trackers are necessary, but they do not prove the ad was good",
          "paragraphs": [
            "A clean tracker layer matters because it is your audit trail. Broken Error URLs, duplicated quartile beacons, unresolved macros, or staging endpoints in production make later discrepancy work much harder than it needs to be.",
            "But a fired pixel is still only proof that some system made a request. Google IMA and OM documentation are explicit that viewability and verification depend on runtime conditions: a viewable and unobstructed container, supported feature coverage, valid verification resources, and the measurement stack that the player actually executes. Your serving component can keep the XML and measurement hooks clean before playback. It cannot prove viewability from XML alone."
          ]
        },
        {
          "type": "list",
          "heading": "What a Go serving component should enforce before the player sees the tag",
          "items": [
            "Validate every fetched VAST document in process with vastlint-go instead of waiting for the player to discover that the response was malformed.",
            "Own wrapper fetching in your application: set a depth cap, detect loops, normalize redirects, and stop the chain when the next hop is empty or unsafe.",
            "Apply URL policy across media, impressions, trackers, click destinations, and verification resources so HTTPS-only inventory does not depend on best-effort cleanup in the player.",
            "Keep an allowlist or denylist for MIME types, interactive frameworks, and verification models by inventory class, because web, mobile, SSAI, and CTV do not tolerate the same payloads.",
            "Record which partner or wrapper hop introduced each tracker so you can explain the final beacon stack instead of arguing about it after campaign launch.",
            "Quarantine or downgrade bad demand inside the same request path, then return a structured reason to the upstream partner or choose a fallback creative before revenue is lost."
          ]
        },
        {
          "type": "code",
          "heading": "A simple unwrap-and-validate loop in Go",
          "language": "go",
          "code": "package demand\n\nimport (\n  \"context\"\n  \"encoding/xml\"\n  \"errors\"\n  \"fmt\"\n  \"net/http\"\n  \"strings\"\n\n  vastlint \"github.com/aleksUIX/vastlint-go\"\n)\n\ntype vastDoc struct {\n  Ads []struct {\n    Wrapper *struct {\n      VASTAdTagURI string `xml:\"VASTAdTagURI\"`\n    } `xml:\"Wrapper\"`\n  } `xml:\"Ad\"`\n}\n\nfunc validateChain(ctx context.Context, client *http.Client, startURL string) error {\n  seen := map[string]struct{}{}\n  nextURL := startURL\n\n  for depth := 0; depth < 5; depth++ {\n    if _, ok := seen[nextURL]; ok {\n      return fmt.Errorf(\"wrapper loop: %s\", nextURL)\n    }\n    seen[nextURL] = struct{}{}\n\n    xmlBytes, err := fetchVAST(ctx, client, nextURL)\n    if err != nil {\n      return err\n    }\n\n    result, err := vastlint.ValidateWithOptions(xmlBytes, vastlint.Options{\n      MaxWrapperDepth: 5,\n      RuleOverrides: map[string]string{\n        \"VAST-2.0-mediafile-https\": \"error\",\n      },\n    })\n    if err != nil {\n      return err\n    }\n    if !result.Valid {\n      return fmt.Errorf(\"quarantine demand tag: %v\", result.Issues)\n    }\n\n    var doc vastDoc\n    if err := xml.Unmarshal(xmlBytes, &doc); err != nil {\n      return err\n    }\n\n    nextURL = \"\"\n    for _, ad := range doc.Ads {\n      if ad.Wrapper != nil && strings.TrimSpace(ad.Wrapper.VASTAdTagURI) != \"\" {\n        nextURL = strings.TrimSpace(ad.Wrapper.VASTAdTagURI)\n        break\n      }\n    }\n\n    if nextURL == \"\" {\n      return nil // final inline VAST is clean enough to hand to the player\n    }\n  }\n\n  return errors.New(\"wrapper depth exceeded\")\n}"
        },
        {
          "type": "paragraphs",
          "heading": "Why this protects revenue instead of just improving hygiene",
          "paragraphs": [
            "The operational win is timing. If you reject a bad demand response after the player times out, the revenue opportunity is already gone. If you reject it in your Go serving path, you still have a chance to serve a fallback, log the exact failing hop, and preserve evidence for the partner that sent the broken tag.",
            "That same path is where you can keep score. Stable rule IDs from vastlint-go let you trend partner quality, distinguish hard blockers from advisory issues, and stop treating every delivery dispute like a one-off mystery."
          ]
        },
        {
          "type": "list",
          "heading": "Quarantine signals worth treating as hard fail",
          "items": [
            "Missing or empty VASTAdTagURI on a wrapper hop.",
            "Wrapper loop, redirect cycle, or depth cap reached before the inline creative appears.",
            "Malformed XML, no usable InLine or Wrapper payload, or a version mismatch that breaks your target runtime.",
            "HTTP-only media or other secure-delivery violations on inventory where the player, browser, or CTV environment expects HTTPS.",
            "Unsupported interactive payloads for the receiving platform, especially when legacy VPAID assumptions are being pushed into environments that need SIMID or a non-interactive fallback.",
            "Broken, contradictory, or obviously duplicated measurement URLs when billing or reconciliation depends on those events.",
            "Verification or measurement payloads that look present in XML but cannot run in the actual destination environment you are serving."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Invisible ads are a policy problem, not just an XML problem",
          "paragraphs": [
            "If by invisible ads you mean stacked, hidden, or otherwise non-viewable playback, no validator can prove or disprove that from XML alone. That requires runtime measurement such as OM SDK, Active View, or other environment-specific verification signals, and those only work when the player and container are configured to expose real visibility data.",
            "What your serving component can do is stop forwarding tags that arrive with weak evidence: dead verification resources, no workable impression or error trail, mismatched media for the destination runtime, or wrapper chains so opaque that nobody can explain who injected which beacon. That does not replace viewability or anti-fraud controls, but it does remove a large class of sloppy demand that makes invisible-delivery disputes harder to unwind."
          ]
        },
        {
          "type": "quote",
          "quote": "Do not ask the player to be your first validator.",
          "attribution": "vastlint field note"
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "Best VAST XML Validator for Go",
              "href": "/docs/best-vast-validator-go/",
              "description": "Where to start if you want the Go binding itself, install instructions, and the minimal API surface.",
              "source": "Docs"
            },
            {
              "label": "Embedding vastlint in an SSP, DSP, or ad server",
              "href": "/docs/ad-server-integration/",
              "description": "Broader integration guidance for in-process validation, rule policy, latency, and ad-serving architecture.",
              "source": "Docs"
            },
            {
              "label": "How to Validate VAST Trackers Before Launch",
              "href": "/blog/how-to-validate-vast-trackers-before-launch/",
              "description": "A focused pass on impression, quartile, click, and error tracker hygiene across wrappers and live tag URLs.",
              "source": "Blog"
            },
            {
              "label": "Missing VASTAdTagURI: Why Wrapper Tags Fail",
              "href": "/docs/missing-vastadtaguri/",
              "description": "The fastest route to diagnosing wrapper hops that have no usable next target.",
              "source": "Docs"
            },
            {
              "label": "Common VAST errors",
              "href": "/docs/common-vast-errors/",
              "description": "A practical reference for malformed URLs, deprecated payloads, missing required elements, and other common delivery failures.",
              "source": "Docs"
            },
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Why wrapper chains lose money before they hit hard limits, and how to inspect each hop cleanly.",
              "source": "Guide"
            },
            {
              "label": "Tracking Pixels Won't Save You From CTV Fraud",
              "href": "/blog/tracking-pixels-wont-save-you-from-ctv-fraud/",
              "description": "Where tracker validation stops and runtime trust, viewability, and anti-fraud controls have to take over.",
              "source": "Blog"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "IAB Tech Lab VAST standards hub",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Current VAST version history, supporting resources, and the official standards landing page.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab SIMID",
              "href": "https://iabtechlab.com/simid/",
              "description": "Background on SIMID as the interactive standard that replaces VPAID for safer cross-platform use cases.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "The VAST CTV Addendum 2024 is Ready for Implementation",
              "href": "https://iabtechlab.com/vast-ctv-addendum-2024-ready-for-implementation/",
              "description": "Why ACIF, OM support, icons, and higher-resolution creative matter across modern TV-viewing environments.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Google IMA SDK support and compatibility",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/compatibility",
              "description": "Supported formats, partial event coverage, platform support, and feature differences that make player-specific QA necessary.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA SIMID support",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/simid-support",
              "description": "Practical details on which SIMID messages are supported and where interactivity still has runtime boundaries.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA Open Measurement",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/omsdk",
              "description": "How OM SDK parses AdVerifications, what access modes exist, and why measurement is a runtime concern rather than an XML-only check.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA Active View guide",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/viewability",
              "description": "Explains how viewability depends on a viewable and unobstructed ad container and how to verify measurement signals in the network layer.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA bitrate and media format guide",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/bitrates-formats",
              "description": "Why multiple media files, bitrate ceilings, and MIME preferences matter when the XML is valid but the chosen asset still fails in runtime.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA CORS for VAST servers",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/cors",
              "description": "A reminder that cross-origin delivery policy can break web VAST fetches even when the XML itself is fine.",
              "source": "Google IMA"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Need the production integration pattern?",
          "paragraph": "Use vastlint-go inside your serving path to validate each fetched VAST hop, then use the tester or inspector when you need to debug the live demand URL outside your application.",
          "href": "/docs/ad-server-integration/",
          "label": "Read the ad server integration guide"
        }
      ]
    },
    {
      "slug": "updated-vast-validator-for-the-iab-standard",
      "title": "Why We Built an Updated VAST Validator for the IAB Standard",
      "description": "VASTlint is an independent, next-generation validator and tester for teams that need broader VAST coverage, wrapper inspection, and automation while still respecting the role of the official IAB Tech Lab tools.",
      "publishedAt": "2026-06-02",
      "updatedAt": "2026-06-02",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Validator strategy",
      "tags": [
        "IAB Tech Lab",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "We built vastlint because the market needs an updated VAST validator and tester for the IAB standard: one that covers more of the modern workflow than the current public baseline, explains what failed, and can run inside browsers, CI, servers, and agent pipelines.",
            "This is not an official IAB Tech Lab product, not a rebrand of the IAB VAST Tag Validator, and not a claim of affiliation. It is an independent validator built against the published IAB Tech Lab VAST specifications, schemas, and related public materials."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What we mean by next-generation",
          "paragraphs": [
            "For us, next-generation does not mean replacing the standards owner. It means extending the public validation workflow so a team can move from live tag URL, to wrapper-chain inspection, to resolved XML validation, to fix guidance, to automation without switching mental models every step of the way.",
            "The official IAB Tech Lab validator and tester still matter. They are the standards-owner baseline and an important point of reference. But many production teams now need a wider operational surface: newer-version handling, explicit wrapper workflows, reusable APIs, and tooling that works outside a single browser session."
          ]
        },
        {
          "type": "list",
          "heading": "Where the official IAB tools still matter most",
          "items": [
            "Official status: they come from the standards owner, which matters for trust, internal sign-off, and standards-baseline checks.",
            "Reference value: they are the cleanest answer when a team asks for the standards body's own public validator or tester.",
            "Quick baseline use: they remain useful when you want an official first pass before you get into platform-specific or automation-heavy workflows.",
            "Ecosystem signaling: if you need the IAB Tech Lab standards hub, validator, tester, or adoption program, those should be linked directly rather than paraphrased through a third party."
          ]
        },
        {
          "type": "list",
          "heading": "Where vastlint goes wider on the public surface",
          "items": [
            "Version coverage: VASTlint validates VAST 2.0 through 4.3 and documents how the newer end of the standard is handled.",
            "Workflow coverage: it separates live URL testing, wrapper inspection, and resolved XML validation instead of forcing those jobs into one page.",
            "Rule transparency: it publishes rule references, methodology, and fix guidance so teams can understand why a tag failed instead of only seeing pass or fail.",
            "Automation: it runs as a web tool, CLI, npm package, Rust library, Go binding, and MCP endpoint for agent-based ad workflows.",
            "Operational debugging: it is designed for ad ops, CTV, SSAI, and platform troubleshooting, not only one-off browser checks."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The honest comparison",
          "paragraphs": [
            "The right framing is not official versus unofficial, winner takes all. The right framing is what problem are you solving right now. If you need the standards owner's public baseline, use the IAB Tech Lab tools. If you need a broader day-to-day validation and testing workflow for modern VAST operations, start with vastlint and cross-check with the official tools when that baseline matters.",
            "That is also why we avoid claiming that VASTlint is the IAB validator. It is not. A better description is that VASTlint is an updated validator and tester for the IAB VAST standard: independent, broader in workflow, and built for current implementation reality."
          ]
        },
        {
          "type": "list",
          "heading": "What we are explicitly not claiming",
          "items": [
            "We are not claiming IAB Tech Lab affiliation, endorsement, sponsorship, or trademark ownership.",
            "We are not claiming that passing VASTlint is the same thing as certification by the standards owner.",
            "We are not claiming that spec compliance alone guarantees playback in every SDK, player, DSP, SSP, or CTV environment.",
            "We are not claiming to replace platform-specific checks such as Google IMA, Roku RAF, or ad-server-specific QA."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why build it anyway",
          "paragraphs": [
            "Because modern teams need more than a point-in-time validator page. They need to inspect live tags, trace wrappers, validate the resolved XML, understand the exact failing rule, and then move the same logic into release gates, supply-path QA, and AI-assisted trafficking workflows.",
            "That is the gap vastlint tries to close. It builds on top of the published IAB Tech Lab VAST standard and related public materials, while adding the wider workflow that production ad-tech teams now need."
          ]
        },
        {
          "type": "quote",
          "quote": "This is not a rebrand of the official IAB tool. It is an independent update for teams that need broader coverage and a modern validation workflow.",
          "attribution": "vastlint field note"
        },
        {
          "type": "resources",
          "heading": "References and useful starting points",
          "items": [
            {
              "label": "IAB Tech Lab VAST standards hub",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Official VAST overview, version history, and standards references.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST GitHub repository",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast",
              "description": "Public VAST specification materials and supporting repository maintained by IAB Tech Lab.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST Tag Validator",
              "href": "https://tools.iabtechlab.com/resourcecenter/vastTagValidator",
              "description": "The official public validator page from the standards owner.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST Tag Tester",
              "href": "https://vasttester.iabtechlab.com/",
              "description": "The official public tester endpoint linked from the IAB Tech Lab VAST resources.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab Specification Adoption Program",
              "href": "https://tools.iabtechlab.com/adoption",
              "description": "Official adoption-program context from IAB Tech Lab if you need the standards body's own program surface.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB VAST validator guide",
              "href": "/guides/iab-vast-validator/",
              "description": "Our independent guide to validating tags against the IAB VAST standard without implying official affiliation.",
              "source": "Guide"
            },
            {
              "label": "vastlint methodology",
              "href": "/docs/methodology/",
              "description": "How VASTlint derives rules from VAST schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/validate/",
              "description": "Paste resolved XML and check it against the current vastlint rule set.",
              "source": "Tool"
            },
            {
              "label": "Test a live VAST tag URL",
              "href": "/tester/",
              "description": "Start from a live URL when the real problem is wrapper resolution and fetch-time behavior.",
              "source": "Tool"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Need the broader workflow, not just the baseline?",
          "paragraph": "Start with live URL testing or resolved XML validation in vastlint, then cross-check with the official IAB Tech Lab surfaces when you need the standards-owner baseline too.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "latest-vast-version",
      "title": "What Is the Latest VAST Version? VAST 4.3, the VAST 4.4 Draft, and the IAB CTV Addendum",
      "description": "The latest officially released IAB VAST version is still 4.3. A vast_4.4.xsd appeared in July 2026 but is marked DRAFT. Here is how 4.3, the 4.4 draft, the 2024 CTV Addendum, and real-world version support fit together without republishing the spec.",
      "publishedAt": "2026-05-27",
      "updatedAt": "2026-05-27",
      "author": "Alex Sekowski",
      "readingTime": "6 min read",
      "heroKicker": "VAST versions",
      "tags": [
        "VAST versions",
        "IAB Tech Lab",
        "CTV",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "The latest officially released IAB VAST version is 4.3. As of July 2026 there is still no published VAST 4.4 specification.",
            "That answer needs a footnote it did not need when this post went up. On 17 July 2026 a file called vast_4.4.xsd was merged into the IAB VAST repository, from a branch named 4.4Development. It is not a release yet: the schema's own annotation reads \"DRAFT for working group discussion\", so it is still being worked through. It landed alongside the CTV Ad Portfolio work, whose signaling guidance was finalised on 22 July and is ready to build against today.",
            "What changed after 4.3 is the VAST CTV Addendum 2024, published by IAB Tech Lab as a backwards-compatible addendum rather than a new core VAST version. Between that, the addendum, and now a draft 4.4 XSD, it is easy to see why teams searching for the latest VAST version get mixed signals."
          ]
        },
        {
          "type": "list",
          "heading": "The VAST version timeline you can cite",
          "items": [
            "VAST 2.0: 2008. The baseline for inline ads, wrappers, tracking, and companions.",
            "VAST 3.0: 2012. Added skippable ads, icons, and ad pods.",
            "VAST 4.0: 2016. Added mezzanine files, UniversalAdId, and stronger SSAI and CTV alignment.",
            "VAST 4.1: 2018. Added OMID verification, interactive creative files, and accessibility improvements.",
            "VAST 4.2: 2019. Clarified macros and conditional-ad behavior.",
            "VAST 4.3: December 2022. Formalized SIMID and fully removed VPAID from the version. Still the latest release.",
            "VAST CTV Addendum 2024: July 2024. Important, but not a new VAST core version.",
            "vast_4.4.xsd: July 2026. A working-group draft supporting the CTV Ad Portfolio. Adds video, duration and SIMID to NonLinear ads. Keep 4.2 or 4.3 in your production version attribute for now."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the IAB has officially published",
          "paragraphs": [
            "If you need the authoritative source, use the IAB Tech Lab VAST standards hub and the public VAST GitHub repository. Those are the right places to confirm whether a version is released, what the latest named version is, and whether a change shipped as a full specification update or as an addendum.",
            "The practical distinction matters. A new addendum can be operationally important without becoming the new answer to the question what is the latest VAST version. That is exactly where the CTV Addendum 2024 sits today."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the IAB VAST spec is still the harness for the ecosystem",
          "paragraphs": [
            "The reason VAST versions matter is not just XML syntax. The IAB Tech Lab VAST specification is the harness that keeps the video ad ecosystem interoperable. It gives ad servers, SSPs, DSPs, CTV apps, web players, SSAI vendors, and measurement providers a shared contract for what a video ad response contains, how wrappers resolve, where tracking belongs, and which interactive or verification mechanisms are valid in a given version.",
            "Without that harness, every buyer, seller, player, and measurement stack would need bespoke pairwise integrations. With it, a VAST tag generated in one system can be trafficked through another, inspected by a third, and played by a fourth. That is why the released IAB version still matters even when vendors add their own tooling and extensions around it."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why VASTlint is the harness for AI agents trafficking VAST",
          "paragraphs": [
            "AI agents do not consume standards prose the way humans do. They need an executable surface. That is where vastlint fits. The VAST spec defines the contract; vastlint turns that contract into machine-usable validation, structured rule IDs, fix guidance, and MCP-callable tools that an agent can use before trafficking a tag.",
            "In an agentic workflow, a planner agent, creative agent, trafficking agent, or QA agent can hand the final VAST tag to vastlint and get back a deterministic answer: version detected, errors, warnings, XPath locations, and spec references. In that sense, VASTlint is a harness for AI agents in the same way the IAB VAST spec is a harness for the broader market. It constrains behavior enough that autonomous systems can traffic tags without guessing what the protocol expects."
          ]
        },
        {
          "type": "list",
          "heading": "What that means in practice for agentic trafficking",
          "items": [
            "A trafficking agent can validate a tag before launch instead of learning from no-fill or playback failure after delivery starts.",
            "A QA agent can explain failures with rule IDs and spec references instead of vague natural-language guesses.",
            "An orchestrator can call validate_vast or validate_vast_url over MCP as a pre-trafficking or pre-approval step.",
            "Human traffickers and AI agents can share the same validation harness, which keeps the workflow consistent across UI, CI, and automated delivery pipelines."
          ]
        },
        {
          "type": "list",
          "heading": "What teams get wrong about VAST versions",
          "items": [
            "Treating the CTV Addendum 2024 as if it were VAST 4.4. It is not.",
            "Assuming the newest IAB VAST-related document is automatically the newest VAST core version.",
            "Planning migrations around rumors, issue trackers, or vendor marketing instead of the released IAB standard.",
            "Copying spec tables into internal docs when a short release-status summary plus links to IAB sources is enough.",
            "Picking a version based only on recency instead of player, SSAI, CTV, and partner support."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What version should you support in production",
          "paragraphs": [
            "For new supply-side or validation work, VAST 4.2 and 4.3 are the right default targets. They align better with modern CTV, measurement, and interactive requirements, and they avoid building new dependencies around VPAID-era behavior.",
            "That does not mean you can ignore older tags. In the long tail, VAST 3.0 is still common, and VAST 2.0 still appears in legacy systems. The right production posture is usually generate modern tags, accept older inbound tags, and validate by declared version instead of forcing every partner onto the newest release on day one."
          ]
        },
        {
          "type": "list",
          "heading": "Recommended support policy",
          "items": [
            "Generate VAST 4.2 or 4.3 for new campaigns and integrations.",
            "Accept VAST 3.0 and, where business requires it, VAST 2.0 from older partners.",
            "Handle the CTV Addendum 2024 when CTV disclosure, creative identity, or high-resolution workflows matter.",
            "Do not treat VAST 4.4 as available until IAB Tech Lab actually publishes it.",
            "Validate tags against the declared version so newer elements do not silently leak into older documents."
          ]
        },
        {
          "type": "quote",
          "quote": "The latest VAST-related document is not always the latest VAST version.",
          "attribution": "vastlint field note"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "A pause ad used to be a JPEG. VAST 4.4 changes that.",
              "href": "/blog/vast-4-4-draft-schema-ctv-ad-portfolio",
              "description": "What the July 2026 draft schema and the finalised CTV Ad Portfolio guidance change, and why the version attribute should stay where it is.",
              "source": "vastlint"
            },
            {
              "label": "IAB Tech Lab VAST standards hub",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Official VAST standards landing page from IAB Tech Lab.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST GitHub repository",
              "href": "https://github.com/InteractiveAdvertisingBureau/vast",
              "description": "Public repository for VAST specification materials and issue tracking.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Which VAST version should you use?",
              "href": "/docs/vast-versions/",
              "description": "Version-by-version guide covering VAST 2.0 through 4.3 and the CTV Addendum.",
              "source": "Docs"
            },
            {
              "label": "VAST 4.4 preview",
              "href": "/docs/vast-4-4/",
              "description": "What the next named VAST version is likely to add once it is released.",
              "source": "Docs"
            },
            {
              "label": "VAST validation in agentic ad delivery",
              "href": "/docs/agentic/",
              "description": "How vastlint exposes VAST validation to buyer, trafficking, and QA agents through MCP.",
              "source": "Docs"
            },
            {
              "label": "Validate a VAST tag",
              "href": "/validate/",
              "description": "Check which version a live tag declares and whether its XML matches that version.",
              "source": "Tool"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Need the full version-by-version breakdown?",
          "paragraph": "Use the main VAST versions guide for the release timeline, migration paths, and the operational differences between 2.0, 3.0, and 4.x.",
          "href": "/docs/vast-versions/",
          "label": "Open the VAST versions guide"
        }
      ]
    },
    {
      "slug": "best-vast-validator-tools-2026",
      "title": "Best VAST Validator Tools in 2026",
      "description": "VASTlint is the strongest starting point when you need current-version standards validation, live URL testing, wrapper inspection, and reusable automation. Here is how IAB Tech Lab, Google IMA, AdMeIn, SpringServe, AdServe, and schema-only validators compare on the public surface.",
      "publishedAt": "2026-05-24",
      "updatedAt": "2026-06-11",
      "author": "Alex Sekowski",
      "readingTime": "11 min read",
      "heroKicker": "Roundup",
      "tags": [
        "VAST validator",
        "VAST tester",
        "Ad ops",
        "CTV"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "For most ad-tech teams, VASTlint is the best place to start because it covers the operational layer first: current-version standards validation, live URL testing, wrapper inspection, public methodology, and embeddable automation.",
            "The rest of the public tools still matter, but usually for narrower reasons. The IAB Tech Lab validator matters as the official baseline from the standards owner. Google IMA Video Suite Inspector matters as an IMA HTML5 runtime debugger. AdMeIn, SpringServe, and AdServe matter as tester-style browser QA surfaces. Schema-only validators matter when all you need is a narrow structural baseline.",
            "That is why the right answer for serious teams is usually not one tool. It is the right order of tools. Start with standards validation and wrapper inspection. Then use runtime-specific or preview-specific testers when the destination environment requires them."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose",
          "items": [
            "Pick vastlint if you need VAST 2.0 through 4.3 coverage, public methodology, live URL testing, wrapper inspection, fix guidance, and reusable validation beyond a browser page.",
            "Pick the IAB Tech Lab validator if official status from the standards owner matters most.",
            "Pick Google IMA Video Suite Inspector if the real question is whether the tag behaves correctly in IMA HTML5.",
            "Pick AdMeIn, SpringServe, or AdServe if the team wants a tester-style browser QA surface and public preview-first workflows.",
            "Pick a schema-only validator if all you want is a narrow schema baseline and nothing more.",
            "Use more than one tool when the campaign matters enough that standards validation and runtime behavior should be checked separately."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The three jobs most teams mix together",
          "paragraphs": [
            "The biggest source of confusion in this category is that many teams ask one vague question: what is the best VAST validator? But the tools on the public market are usually optimized for one of three jobs, not all three.",
            "The first job is official or standards-owner baseline validation. The second is runtime or player preview, where the tool actually tries to render the ad, fire tracking, or show event behavior in a specific environment. The third is embeddable standards validation, where teams need a current rule set, wrapper-chain visibility, live URL testing, and a path into CI or server-side systems.",
            "Once you separate those jobs, the tool choices become much easier and much fairer."
          ]
        },
        {
          "type": "list",
          "heading": "What each tool is best understood as",
          "items": [
            "vastlint: an independent standards-first toolkit with validate, test, and inspect workflows plus public methodology and embeddable automation.",
            "IAB Tech Lab VAST Tag Validator: the official public baseline from the standards owner, with public support on its page for VAST 2.0, 3.0, and 4.1.",
            "Google IMA Video Suite Inspector: an IMA HTML5 runtime debugger, not a neutral validator for every downstream environment.",
            "AdMeIn VAST Tester: a compact tester-style public surface with browser QA, Google IMA-powered preview, and deeper analysis gated behind sign-in.",
            "SpringServe Tagtest: a player-style public tester for quick operational checks, not a public methodology-driven validation surface.",
            "AdServe VAST Inspector: a player-style tester that publicly advertises VAST support through 4.2 and focuses on playback, redirects, tracking, and measurement-style checks.",
            "schema-only validators: useful when all you want is schema validation, but narrow if you also need wrapper inspection, live URL testing, or prose-derived 4.3 rules."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where VASTlint is materially different",
          "paragraphs": [
            "The strongest mistake to avoid is giving competitors credit for generic QA capabilities that vastlint already exposes on its own public surfaces. vastlint already covers creative preview, click behavior, tracking visibility, metadata inspection, wrapper unwrapping, and creative parsing. So when another tool leads with preview, events, or wrapper visibility, that does not automatically make it broader.",
            "The real differences usually live elsewhere: official status, runtime specificity, public version coverage, whether deeper analysis is gated, whether methodology is public, and whether the validation path can be embedded in automation. That is where VASTlint is materially different from most public alternatives.",
            "It covers VAST 2.0 through 4.3, publishes how rules are derived from IAB XSD schemas and normative prose, separates validate, test, and inspect into distinct workflows, and ships as web, CLI, Rust, Go, npm, and MCP tooling."
          ]
        },
        {
          "type": "list",
          "heading": "Decision matrix in plain English",
          "items": [
            "Latest publicly advertised version support: VASTlint is strongest because its public positioning runs through VAST 4.3; IAB's public page stops at 4.1, while AdMeIn and AdServe publicly stop at 4.2.",
            "Public rule diagnostics and methodology: VASTlint is strongest because it exposes both publicly; most tester-style tools do not foreground a public rule catalog or derivation story.",
            "Live URL testing and wrapper inspection: VASTlint is strongest as a public workflow because it explicitly separates live tag testing and wrapper inspection instead of burying those tasks inside one tester surface.",
            "CI, server-side use, and self-hosting path: VASTlint is strongest because it is open source and embeddable instead of only being a hosted browser tool.",
            "Playback or runtime preview: Google IMA wins when IMA HTML5 is the actual runtime; tester-style browser tools like AdMeIn, SpringServe, and AdServe also fit here.",
            "Official affiliation: IAB Tech Lab is the clear winner because it is the standards owner. VASTlint is independent by design."
          ]
        },
        {
          "type": "quote",
          "quote": "Most VAST tools win one job. The useful stack is knowing which job you are actually hiring the tool to do.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Recommended order of operations",
          "paragraphs": [
            "If the input is a live ad tag from an exchange, SSP, or ad server, the first step should usually be standards validation and wrapper inspection, not a player preview. Resolve the live tag, inspect every wrapper hop, and validate the final XML before you ask whether a specific runtime likes what it sees.",
            "After that, move into the environment-specific or packaging-specific tool that matches your question. If stakeholders need the standards-owner baseline, cross-check with IAB Tech Lab. If the target runtime is IMA HTML5, use Google's inspector. If the team wants another public browser QA pass, use AdMeIn or another tester-style surface.",
            "That order prevents runtime noise from masking structural problems and keeps official baselines from being misused as a substitute for operational debugging."
          ]
        },
        {
          "type": "code",
          "heading": "Practical workflow for most teams",
          "language": "bash",
          "code": "# 1. Start with the live tag URL in vastlint tester\n# 2. Inspect the wrapper chain hop by hop in vastlint inspector\n# 3. Validate the resolved XML against current published VAST rules in vastlint validator\n# 4. If needed, cross-check with the IAB validator for the official baseline\n# 5. If needed, run a runtime-specific or tester-style tool such as Google IMA or AdMeIn\n# 6. Fix standards issues first, then fix runtime or preview-specific behavior"
        },
        {
          "type": "list",
          "heading": "Which tool should you start with",
          "items": [
            "Start with vastlint if you want the best all-around operational workflow for current VAST validation.",
            "Start with IAB Tech Lab if internal trust depends on official standards-owner affiliation.",
            "Start with Google IMA if the only question is IMA HTML5 playback behavior.",
            "Start with AdMeIn, SpringServe, or AdServe if the team wants a fast tester-style browser QA pass after structural validation.",
            "Start with a schema-only validator only if you explicitly want a narrow schema check and know that wrapper, live URL, and 4.3 methodology questions are out of scope."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Bottom line",
          "paragraphs": [
            "If you want the broadest practical workflow for standards-derived validation, current-version coverage, wrapper inspection, live URL testing, public methodology, and reusable automation, VASTlint is the strongest starting point.",
            "The rest of the field still has a place. The IAB validator is the official reference. Google's inspector is the right IMA-specific runtime check. AdMeIn and similar tools are useful when the team wants a compact tester surface. The useful comparison is not which tool wins every category. It is which tool wins the category you actually need next."
          ]
        },
        {
          "type": "resources",
          "heading": "Related comparisons and docs",
          "items": [
            {
              "label": "vastlint vs IAB Tech Lab VAST Tag Validator",
              "href": "/blog/vastlint-vs-iab-tech-lab-vast-tag-validator/",
              "description": "Head-to-head comparison between vastlint and the official IAB Tech Lab validator.",
              "source": "Blog"
            },
            {
              "label": "vastlint vs Google IMA Video Suite Inspector",
              "href": "/blog/vastlint-vs-google-ima-video-suite-inspector/",
              "description": "Head-to-head comparison focused on IMA runtime testing versus standards-first validation.",
              "source": "Blog"
            },
            {
              "label": "vastlint vs AdMeIn VAST Tester",
              "href": "/blog/vastlint-vs-admein-vast-tester/",
              "description": "Head-to-head comparison focused on tester packaging versus standards depth and workflow breadth.",
              "source": "Blog"
            },
            {
              "label": "vastlint vs SpringServe VAST Tag Tester",
              "href": "/blog/vastlint-vs-springserve-vast-tag-tester/",
              "description": "Player-style event checks and VMAP playout versus public standards validation and CI-ready tooling.",
              "source": "Blog"
            },
            {
              "label": "vastlint vs AdServe VAST Inspector",
              "href": "/blog/vastlint-vs-adserve-vast-inspector/",
              "description": "Playback inspection through VAST 4.2 versus spec-derived validation through 4.3 with hop-by-hop wrapper inspection.",
              "source": "Blog"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How VASTlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/validate/",
              "description": "Run a standards-derived XML compliance check against VAST 2.0 through 4.3.",
              "source": "Tool"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Start with the standards layer",
          "paragraph": "Validate the XML, test the live tag, and inspect the wrapper chain before you move into runtime-specific or preview-first tools.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "vastlint-vs-iab-tech-lab-vast-tag-validator",
      "title": "vastlint vs IAB Tech Lab VAST Tag Validator",
      "description": "Live VAST URL goes to the vastlint tester. SIMID handshake goes to the IAB-style workbench. Resolved XML goes to the validator. The IAB Tech Lab validator is the official baseline. Here is when to use each.",
      "publishedAt": "2026-05-24",
      "updatedAt": "2026-09-05",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "IAB Tech Lab",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If your team needs the best day-to-day validation workflow, start with vastlint. Split the click: a live VAST URL goes to the tester, wrapper hops go to the inspector, a SIMID handshake or IAB sample creative goes to the IAB-style workbench, and resolved XML goes to the validator.",
            "If the question is what the standards owner itself exposes publicly, the IAB Tech Lab VAST Tag Validator is the right official reference point. That is its real differentiator. It is the validator publicly presented by the group that publishes the VAST specification.",
            "Most serious teams should treat these as complementary. Use vastlint for the operational workflow and current-version coverage. Use the IAB validator when the official baseline itself matters to the discussion. The IAB-style workbench on iab-tech-lab-vast-tester.vastlint.org is an independent fork, not an IAB Tech Lab product."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use vastlint tester when your input is a live VAST URL: fetch, preview, tracking, clicks.",
            "Use the inspector when the chain is the question: 302, 303, wrapper depth, hop that went empty.",
            "Use the IAB-style VAST tester for SIMID studio and IAB sample creatives. It is an independent fork, not an official IAB Tech Lab product.",
            "Use vastlint validator when you already hold resolved XML and need current-version coverage beyond the IAB page's publicly advertised 2.0, 3.0, and 4.1 support.",
            "Use vastlint when you need public rule explanations, public methodology, or a workflow that extends into CI, automation, or server-side systems.",
            "Use the IAB Tech Lab validator when the most important question is what the standards owner publicly validates.",
            "Use both when you want the operational workflow first and an official baseline cross-check second."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why VASTlint is the stronger starting point",
          "paragraphs": [
            "VASTlint is the stronger starting point when the team needs an operational validator that still begins from the published VAST standards baseline, then carries that coverage forward through VAST 4.3. That matters because the public IAB page advertises support through 4.1, while modern teams still have to handle 4.2 details and 4.3 tags.",
            "It also surfaces the three jobs teams actually need in practice: validate resolved XML, test a live VAST URL, and inspect a wrapper chain hop by hop. That is a clearer day-to-day workflow than a single validator-first page, and it makes repeated QA and debugging easier.",
            "That is the practical split. VASTlint is the stronger operational workflow for current-version handling, public methodology, wrapper debugging, and reusable automation. The IAB validator remains the official baseline reference when standards-owner affiliation matters."
          ]
        },
        {
          "type": "list",
          "heading": "The public-surface gaps vastlint closes",
          "items": [
            "Public positioning around VAST 2.0 through 4.3, not only the versions publicly advertised on the IAB validator page.",
            "A public methodology explaining how rules are derived from IAB VAST XSD schemas where available and from RFC 2119 normative prose where schemas stop.",
            "An explicit public story for VAST 4.3, including why 4.3 checks must be prose-derived because no published IAB XSD exists.",
            "Three separate workflows instead of one validator-first surface: validator for resolved XML, tester for live URLs and creative preview, and inspector for wrapper-chain debugging, metadata, and tracking counts.",
            "Public rule references and fix-oriented diagnostics that can be cited internally during debugging and approvals.",
            "An open-source, embeddable validation path for web, CLI, Rust, Go, npm, and MCP workflows."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the IAB tool is publicly optimized for",
          "paragraphs": [
            "The public IAB Tech Lab page is explicit about what makes the validator important: it was developed by the IAB Tech Lab team. That official status is meaningful. If an internal stakeholder asks which public validator comes directly from the standards owner, this is the strongest answer.",
            "The same public page advertises support for VAST 2.0, 3.0, and 4.1, and it lists a broad set of checks around inline linear, inline non-linear, companions, wrappers, click tracking, event tracking, mezzanine files, VPAID separation, ready-to-serve media files, conditional ads, Universal AdID, ad verification, and viewable impressions.",
            "That makes the IAB validator a credible public baseline. But the public surface is validator-oriented. It is not clearly presented as a broader toolkit with separate live URL testing, wrapper inspection, and embeddable validation paths."
          ]
        },
        {
          "type": "list",
          "heading": "What official status changes on the public surface",
          "items": [
            "It is the public validator presented by the standards owner, which is a trust signal no independent tool can duplicate.",
            "It gives teams a direct standards-owner baseline when stakeholders want to see what the IAB itself exposes publicly.",
            "It is a useful reference point for teams that want to stay close to the public framing and terminology used by the specification owner.",
            "It can be a strong cross-check when procurement, compliance, or partner conversations care about official affiliation.",
            "It keeps the comparison anchored to the standard body rather than to a player vendor or commercial tester."
          ]
        },
        {
          "type": "quote",
          "quote": "The IAB validator is the official baseline. VASTlint is the current-version workflow teams actually operate with.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Use them in this order",
          "paragraphs": [
            "If the starting point is a live ad tag from an exchange, ad server, or SSP, the first job is to fetch that URL in the vastlint tester. If the player printed 302 or 303, inspect the wrapper chain hop by hop. If the creative is SIMID, open the IAB-style workbench for the handshake. Then validate the resolved XML against a current public rule set.",
            "Once the resolved XML is structurally sound, the IAB validator can become useful as an additional official reference point, especially when the tag falls inside the version range the IAB page publicly advertises. At that point, the question is no longer does this tag work at all. The question is does this already-debugged tag line up with the official public baseline as well.",
            "That sequence keeps the operational debugging first and the standards-owner cross-check second. It avoids using an official validator as a substitute for current-version troubleshooting, wrapper inspection, SIMID studio, or automation-friendly validation."
          ]
        },
        {
          "type": "code",
          "heading": "Recommended workflow when official baseline matters",
          "language": "bash",
          "code": "# 1. Live tag URL: vastlint.org/tester/\n# 2. Wrapper hops: vastlint.org/inspect/\n# 3. SIMID handshake or IAB samples: iab-tech-lab-vast-tester.vastlint.org (independent fork)\n# 4. Resolved XML: vastlint.org/validate/\n# 5. If stakeholders want the standards-owner baseline, cross-check with the IAB validator where its public version coverage applies"
        },
        {
          "type": "list",
          "heading": "When VASTlint is the better first choice",
          "items": [
            "You need coverage that includes VAST 4.2 and 4.3, not only versions publicly advertised through 4.1.",
            "You need a public explanation of how 4.3 rules are derived without a published IAB XSD.",
            "You are starting from a live VAST URL or a redirecting wrapper chain, not just a final XML payload.",
            "You need rule-level diagnostics, public fix guidance, and methodology you can cite internally.",
            "You want one validation workflow that can move into CI, server-side systems, or automated QA.",
            "You need an open-source toolchain rather than a single public validator surface."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When the IAB validator should still be in the workflow",
          "paragraphs": [
            "The IAB validator should still be in the workflow when official status itself carries weight. If a buyer, publisher, legal reviewer, or internal approver wants to know what the standards owner exposes publicly, the IAB tool is the right reference point.",
            "That is the fair comparison. The IAB validator is not interesting because it outclasses vastlint on operational coverage. It is interesting because it is the official public baseline from the specification owner. VASTlint is stronger when the first question is current-version validation, 4.3 methodology, wrapper debugging, and reusable tooling.",
            "If you want a more inspectable community implementation in the same orbit, the author also maintains a public IAB-style VAST tester at iab-tech-lab-vast-tester.vastlint.org with source on GitHub. Treat it as a community fork, not as an official IAB Tech Lab property. Use it for SIMID studio and IAB sample creatives. Live URLs still start on vastlint.org/tester/."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "IAB Tech Lab VAST Tag Validator",
              "href": "https://iabtechlab.com/software/vast-tag-validator/",
              "description": "The IAB Tech Lab's public VAST validator page, including its official positioning and advertised support for VAST 2.0, 3.0, and 4.1.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab VAST standards",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The standards hub for VAST specifications published by IAB Tech Lab.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB VAST validator guide",
              "href": "/guides/iab-vast-validator/",
              "description": "vastlint's guide to what the official IAB validator is useful for and where operational workflows still need more than an official baseline.",
              "source": "Guide"
            },
            {
              "label": "IAB-style VAST tester (SIMID studio)",
              "href": "https://iab-tech-lab-vast-tester.vastlint.org/",
              "description": "Independent fork for SIMID handshake QA and IAB sample creatives. Not an official IAB Tech Lab property.",
              "source": "Community"
            },
            {
              "label": "VAST tag tester",
              "href": "/tester/",
              "description": "Fetch a live VAST URL, preview creative, inspect tracking and click URLs.",
              "source": "Tool"
            },
            {
              "label": "VAST inspector",
              "href": "/inspect/",
              "description": "Walk wrapper hops when the chain is the question.",
              "source": "Tool"
            },
            {
              "label": "VAST-Tester fork source",
              "href": "https://github.com/aleksUIX/VAST-Tester",
              "description": "GitHub repository for the author's public VAST-Tester fork.",
              "source": "GitHub"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How VASTlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/docs/validate-vast-xml/",
              "description": "How to choose between validating resolved XML and testing a live tag URL.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Start with the live tag URL",
          "paragraph": "Fetch the live VAST URL on the tester. Walk hops on the inspector. Open the IAB-style workbench for a SIMID handshake. Paste resolved XML into the validator. Use the official IAB validator as a reference point when official baseline matters.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "vastlint-vs-admein-vast-tester",
      "title": "vastlint vs AdMeIn VAST Tester",
      "description": "vastlint matches AdMeIn on preview, tracking, metadata, unwrapping, and creative inspection, and is stronger for public standards depth, VAST 4.3 coverage, methodology, and CI-friendly validation. AdMeIn mainly changes the packaging with a compact single-page tester. Here is where each fits.",
      "publishedAt": "2026-05-24",
      "updatedAt": "2026-05-24",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "AdMeIn",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If your immediate job is to validate the tag against a public, standards-derived rule set, inspect wrappers, preview creatives, parse metadata, and keep the workflow reusable outside a browser session, VASTlint is the stronger first tool. It already covers preview, tracking, wrapper unwrapping, creative parsing, and rule-level diagnostics without depending on a gated tester surface.",
            "AdMeIn is still a credible public option when the team specifically wants a compact single-page tester-style experience. It packages browser preview, metadata, tracking, and wrapper visibility into one page, but that packaging is not a capability moat over vastlint.",
            "The cleanest workflow for teams that test aggressively is to use vastlint first for the standards layer, then use AdMeIn if one more browser-preview pass helps. That keeps structural debugging separate from player-style preview debugging."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use vastlint if you want the same core QA signals plus stronger standards coverage and a clearer split between tester, inspector, and validator.",
            "Use vastlint when you need public standards-derived validation before you trust any preview environment.",
            "Use vastlint when your input is a live VAST URL with redirects and you need to separate validation, testing, and wrapper inspection into clearer steps.",
            "Use AdMeIn if the team prefers a single tester-style page.",
            "Use AdMeIn after that if the team wants a second visual QA pass with playback-style feedback.",
            "Use vastlint if you need public rule docs, a public methodology, or a workflow that extends into CI, CLI, server-side systems, or automated QA.",
            "Use both if the campaign is valuable enough that standards compliance and browser preview should be checked separately."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why VASTlint is the stronger starting point",
          "paragraphs": [
            "VASTlint is the stronger starting point when the team wants a public, standards-derived answer before it leans on any tester UX. It already covers preview, tracking, wrapper unwrapping, creative parsing, metadata inspection, and rule-level diagnostics without depending on a gated single-page surface.",
            "It also keeps the workflow reusable outside the browser session: test a live tag URL, inspect every wrapper hop, and validate the resolved XML against a public methodology that explains where the rules come from. That is a cleaner first step than starting inside a preview environment influenced by a specific playback stack.",
            "That is the practical split. VASTlint is stronger on standards depth, 4.3 coverage, methodology, and reusable automation. AdMeIn still has value when the team wants a compact tester-style page after that."
          ]
        },
        {
          "type": "list",
          "heading": "The public-surface gaps vastlint closes",
          "items": [
            "Public positioning around VAST 2.0 through 4.3, including the specific 4.3 methodology story where no published IAB XSD exists.",
            "A public methodology page explaining how rules are derived from IAB VAST XSD schemas, RFC 2119 normative prose, and related standards.",
            "Public rule references and fix-oriented diagnostics rather than a preview-first surface with gated deeper analysis.",
            "The same practical QA surface and more: validator for resolved XML, tester for live URLs and creative preview, and inspector for wrapper hops, metadata, tracking counts, and creative parsing.",
            "An open-source path that extends beyond browser use into CLI, Rust, Go, npm, and MCP workflows.",
            "A neutral standards-first baseline that is not tied to a Google IMA-powered preview environment."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What AdMeIn is publicly optimized for",
          "paragraphs": [
            "On its public page, AdMeIn positions the tool as a VAST Tag Tester and Inspector that accepts both VAST tag URLs and VAST XML. It promises live video ad playback, metadata, tracking events, wrapper-chain visibility, and validation-oriented checks. That framing is useful for operators who want a compact QA console, but it is not unique coverage: vastlint also exposes preview, creative metadata, tracking, wrapper unwrapping, and validation across its dedicated surfaces.",
            "The page also says its ad previews are powered by the Google IMA SDK. That matters because it tells you the experience is not a neutral abstract validator. It is a browser preview environment that is already anchored to a specific playback stack.",
            "AdMeIn also publicly advertises support for VAST 2.0, 3.0, 4.0, 4.1, and 4.2, plus VMAP 1.0 support. That makes it look broad enough for many current workflows, especially teams whose day-to-day work is still dominated by preview and trafficking QA rather than standards analysis."
          ]
        },
        {
          "type": "list",
          "heading": "What AdMeIn changes on the public surface",
          "items": [
            "A more compact single-page public QA workflow that keeps URL input, XML input, preview, metadata, events, and wrapper-oriented views together.",
            "A tester-style entry point that may feel simpler to first-time manual users than moving between dedicated validator, tester, and inspector pages.",
            "Public VMAP positioning in addition to VAST testing, which is useful when teams are debugging break scheduling as well as tag structure.",
            "A Google IMA-powered preview environment for teams that explicitly want that runtime in the loop.",
            "A public page that leads with tester UX rather than standards methodology or rule documentation."
          ]
        },
        {
          "type": "quote",
          "quote": "AdMeIn is packaged like a tester. vastlint already covers the same core QA ground and more.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Use them in this order",
          "paragraphs": [
            "If you start with a preview-first tool, it is easy to blur together multiple problems: the XML itself, wrapper-chain issues, and the behavior of the preview runtime. That often produces noisy debugging because the team starts attributing every failure to the player environment before they have verified the tag structurally.",
            "A cleaner sequence is to start with the live tag in vastlint tester, inspect the wrapper chain in vastlint inspector, validate the resolved XML in vastlint validator, and only then move into AdMeIn if you want an additional browser preview or tracking-event pass.",
            "That order keeps standards validation separate from visual QA. It also means that if AdMeIn surfaces a playback or tracking issue later, the team already knows whether the underlying tag passed a public standards baseline first."
          ]
        },
        {
          "type": "code",
          "heading": "Recommended workflow when AdMeIn is part of QA",
          "language": "bash",
          "code": "# 1. Start from the live VAST URL in vastlint tester\n# 2. Inspect each wrapper hop in vastlint inspector\n# 3. Validate the resolved XML against public standards-derived rules in vastlint validator\n# 4. If the team wants a browser preview and event-oriented QA pass, run the same tag in AdMeIn\n# 5. Fix structural issues first, then fix preview or playback issues"
        },
        {
          "type": "list",
          "heading": "When VASTlint is the better first choice",
          "items": [
            "You need a public standards-based answer before anyone logs in to a gated QA surface.",
            "You need current public positioning that includes VAST 4.3, not only versions publicly advertised through 4.2.",
            "You need methodology you can cite internally when someone asks why a rule exists or how the validator derives it.",
            "You need one validator that can move from browser QA into CI, ad-server checks, or automated workflows.",
            "You need a clearer separation between live URL fetches, wrapper inspection, and final XML validation.",
            "You want a neutral baseline before debugging any preview environment that is already tied to a player stack."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When AdMeIn still earns a spot in the workflow",
          "paragraphs": [
            "AdMeIn still makes sense when the team wants a fast single-page tester UX or wants another browser surface alongside vastlint. But the capability gap is smaller than the page framing suggests: vastlint already covers preview, metadata, tracking, wrapper unwrapping, and creative parsing in its own tester and inspector flows.",
            "That is the fair comparison. AdMeIn is mostly a packaging and entry-point difference. VASTlint is stronger when the first question is standards coverage, rule explainability, wrapper unwrapping, creative parsing, and reusable validation outside a browser session."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "AdMeIn VAST Tester",
              "href": "https://admein.io/vast-tester",
              "description": "AdMeIn's public VAST tester and inspector page, including its preview, metadata, wrapper, and tracking-oriented claims.",
              "source": "AdMeIn"
            },
            {
              "label": "Google IMA SDK VAST validator guide",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "vastlint's guide to Google IMA runtime constraints and troubleshooting, useful because AdMeIn says its previews are powered by Google IMA SDK.",
              "source": "Guide"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How VASTlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/docs/validate-vast-xml/",
              "description": "How to choose between validating resolved XML and testing a live tag URL.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate first, preview second",
          "paragraph": "Resolve the live tag, inspect the wrappers, and validate the XML before you move into a preview-oriented QA tool. That gives the team a cleaner debugging signal from the start.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "vastlint-vs-google-ima-video-suite-inspector",
      "title": "vastlint vs Google IMA Video Suite Inspector",
      "description": "Live VAST URL goes to the vastlint tester. SIMID handshake goes to the IAB-style workbench. Then, if IMA HTML5 is the runtime, run the same tag in Google's Video Suite Inspector. Here is when to use each.",
      "publishedAt": "2026-05-24",
      "updatedAt": "2026-09-05",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "Google IMA",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If your question is whether the tag is structurally compliant with the published VAST standards before you get into player-specific behavior, VASTlint is the better first tool. Split the click: live URL to the tester, wrapper hops to the inspector, SIMID handshake to the IAB-style workbench, resolved XML to the validator.",
            "If the remaining question is how that tag behaves inside Google's IMA HTML5 playback environment, Google's Video Suite Inspector is the right runtime-specific check. Its public workflow is explicit: paste a VAST tag or VAST response, run the ad, watch the player, and inspect what happens inside the IMA HTML5 stack.",
            "Most serious teams should use both. Fetch and unwrap the tag in vastlint first. Then, if Google IMA HTML5 is one of your real target runtimes, run the resolved tag through Google's inspector as the final environment-specific check."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use vastlint tester when the input is a live tag URL: fetch, preview, tracking, clicks.",
            "Use the inspector when the chain is the question.",
            "Use the IAB-style VAST tester for SIMID studio. Independent fork, not an IAB Tech Lab product. Google's inspector is still the IMA HTML5 runtime check.",
            "Use vastlint when you need standards-derived validation against published IAB VAST rules before you troubleshoot a specific player or SDK.",
            "Use vastlint if you need public rule references, public methodology, or an embeddable workflow for CI, ad servers, SSPs, DSPs, or QA automation.",
            "Use Google IMA Video Suite Inspector when you need to know how the tag behaves inside the IMA HTML5 runtime specifically."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why VASTlint is the stronger starting point",
          "paragraphs": [
            "VASTlint is the stronger starting point when the question is standards compliance before runtime behavior. It validates against the published VAST rules, publishes its methodology, and is not tied to a single player or SDK.",
            "It also separates the three jobs teams usually need in practice: validate XML, test a live URL, and inspect wrapper chains. That gives you a neutral baseline before player-specific behavior or event logs start adding noise.",
            "That is the practical split. VASTlint is the standards-first layer for current-version validation, public rule docs, wrapper debugging, and reusable automation. Google's Video Suite Inspector remains the runtime-specific check when IMA HTML5 is the real target environment."
          ]
        },
        {
          "type": "list",
          "heading": "The public-surface gaps vastlint closes",
          "items": [
            "A public methodology explaining how rules are derived from published IAB VAST XSD schemas where available and RFC 2119 normative prose where schemas stop.",
            "Clear current-positioning around VAST 2.0 through 4.3, including the important detail that VAST 4.3 has no published IAB XSD and must be handled as a prose-derived ruleset.",
            "Three separate workflows instead of one player tester: validator for XML compliance, tester for live URL fetches, creative preview, and click behavior, and inspector for wrapper-chain debugging, metadata, and tracking counts.",
            "Public rule references and fix-oriented diagnostics instead of relying on a runtime-oriented event log as the first debugging step.",
            "An open-source, embeddable validation path for CLI, Rust, Go, npm, and MCP workflows, not just a browser-based inspector.",
            "A neutral standards-first layer you can run before Google IMA, Roku, Samsung, LG webOS, tvOS, ad servers, or buyer-specific QA."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What Google's tool is actually built for",
          "paragraphs": [
            "The public IMA HTML5 Video Suite Inspector page is very clear about its purpose. It asks for a VAST ad tag or VAST ad response, then tells you that its video player will attempt to interpret the response, play the ad, and ping the tracking URLs. The page shows the exact artifacts operators care about during runtime testing: player output, events, and companions. vastlint can also surface preview, tracking, click behavior, and wrapper details, so the distinction is not generic QA visibility. The distinction is that Google's tester is anchored to the IMA HTML5 runtime itself.",
            "That makes it a useful operational tool when IMA HTML5 is the destination environment. If a trafficking team wants to know whether an ad will load in the IMA HTML5 stack, whether companions display there, or whether tracking fires during playback there, the inspector is doing the right job. It is a runtime-oriented debugger, not a broader capability lead over a standards-first toolkit.",
            "That strength is also its boundary. It is centered on IMA HTML5 behavior, not on being a neutral, public, standards-first validation layer for every downstream environment."
          ]
        },
        {
          "type": "list",
          "heading": "What Google adds when IMA HTML5 is the target runtime",
          "items": [
            "A public runtime check inside the IMA HTML5 environment itself, rather than a neutral cross-runtime baseline.",
            "Direct confirmation of how IMA HTML5 interprets the tag once the SDK actually tries to play it, render companions, and fire tracking.",
            "Direct alignment with the Google IMA HTML5 SDK docs, sample tags, and related implementation guides.",
            "Useful for debugging player-side problems that only appear once IMA HTML5 actually tries to interpret and render the ad.",
            "A natural final check when your production runtime is Google IMA HTML5."
          ]
        },
        {
          "type": "quote",
          "quote": "Google's inspector tells you how IMA behaves. vastlint already covers the core QA surface before that runtime check starts.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Use them in this order",
          "paragraphs": [
            "The operational mistake is to treat these as mutually exclusive substitutes. They solve adjacent problems, not identical ones. If the tag comes from a live ad server URL, fetch it in the vastlint tester. If the player printed 302 or 303, inspect hops. If the creative is SIMID, open the IAB-style workbench for the handshake, then still run IMA if IMA is the player.",
            "Once the resolved tag is structurally sound, Google's inspector becomes much more valuable. At that point you are no longer asking a vague question like does this tag work. You are asking the sharper question does this standards-valid tag behave the way I expect in IMA HTML5.",
            "That sequence produces better debugging. It prevents player-specific noise from masking simple XML problems and prevents standards validation from being confused with runtime compatibility."
          ]
        },
        {
          "type": "code",
          "heading": "Recommended workflow when Google IMA is your target runtime",
          "language": "bash",
          "code": "# 1. Live tag URL: vastlint.org/tester/\n# 2. Wrapper hops: vastlint.org/inspect/\n# 3. SIMID handshake: iab-tech-lab-vast-tester.vastlint.org (independent fork)\n# 4. Resolved XML: vastlint.org/validate/\n# 5. If Google IMA HTML5 is the destination runtime, run the same resolved tag in Video Suite Inspector"
        },
        {
          "type": "list",
          "heading": "When VASTlint is the better first choice",
          "items": [
            "You need a neutral standards-first answer before anyone argues about player quirks.",
            "You are starting from a live VAST URL with wrappers and redirects, not a final XML payload.",
            "You need rule-level diagnostics, public fix guidance, and methodology you can cite internally.",
            "You want to validate tags in CI, inside an ad server, or inside an automated QA pipeline.",
            "You need an open-source workflow that can live outside a browser session.",
            "You need one baseline validator before comparing behavior across multiple SDKs or players."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When Google's inspector should be the final check",
          "paragraphs": [
            "If Google IMA HTML5 is the actual production runtime, Google's inspector should still be in the workflow. Its value is not that it replaces standards validation or outclasses broad QA features. Its value is that it shows you what the IMA environment does with the tag after you already know the underlying XML is sound.",
            "That is the fair comparison. Google's tool is excellent at IMA runtime testing. VASTlint is better as the standards-derived front door into the whole debugging process and already covers the generic preview, tracking, click, and wrapper-debugging layer before you ever open IMA."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "IMA HTML5 Video Suite Inspector",
              "href": "https://googleads.github.io/googleads-ima-html5/vsi/",
              "description": "Google's public inspector for testing how a VAST ad response behaves in the IMA HTML5 environment.",
              "source": "Google"
            },
            {
              "label": "IMA HTML5 support and compatibility",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/compatibility",
              "description": "Google's compatibility matrix and caveats for browsers, platforms, events, frameworks, and media features.",
              "source": "Google"
            },
            {
              "label": "Enable VPAID 2 JavaScript creatives",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/vpaid2js",
              "description": "Google's documentation describing VPAID 2 support boundaries and caveats in IMA HTML5.",
              "source": "Google"
            },
            {
              "label": "Review SIMID support",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/simid-support",
              "description": "Google's documentation describing the SIMID messages and behaviors IMA HTML5 supports or does not support.",
              "source": "Google"
            },
            {
              "label": "IAB-style VAST tester (SIMID studio)",
              "href": "https://iab-tech-lab-vast-tester.vastlint.org/",
              "description": "Independent workbench for SIMID handshake QA. Not an IAB Tech Lab product. Use this before you argue about IMA SIMID message support.",
              "source": "Community"
            },
            {
              "label": "VAST tag tester",
              "href": "/tester/",
              "description": "Fetch a live VAST URL, preview creative, inspect tracking and click URLs.",
              "source": "Tool"
            },
            {
              "label": "Google IMA SDK VAST validator guide",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "vastlint's guide to the Google IMA SDK requirements, caveats, and troubleshooting flow.",
              "source": "Guide"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How VASTlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Fetch the live tag before you debug the player",
          "paragraph": "Start with the live tag URL on the tester, unwrap hops on the inspector, and use the IAB-style workbench for a SIMID handshake. Then move into Google IMA runtime testing with a cleaner signal.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "how-the-tracking-pixel-ecosystem-actually-works",
      "title": "How the Tracking Pixel Ecosystem Actually Works",
      "description": "Tracking pixels are not one thing. They sit inside a larger measurement and identity system that spans VAST, VMAP, ad registries, anti-fraud tooling, server-side beaconing, and public tracker catalogs. This is the practical map.",
      "publishedAt": "2026-05-22",
      "updatedAt": "2026-05-22",
      "author": "Alex Sekowski",
      "readingTime": "9 min read",
      "heroKicker": "Tracking pixel ecosystem",
      "tags": [
        "Tracking pixels",
        "VAST",
        "VMAP",
        "Measurement"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "A tracking pixel is the visible tip of a bigger system",
          "paragraphs": [
            "People talk about tracking pixels as if they were a single product category. They are not. A tracking pixel is usually just a URL call or beacon that records an event somewhere in the delivery chain: impression, quartile, click, completion, viewability, or a platform-specific diagnostic event.",
            "What matters in practice is the ecosystem around that URL. The pixel sits inside ad-serving specs such as VAST, break-planning formats such as VMAP, ad-server macros, measurement SDKs, server-side beaconing systems, creative identity registries, and anti-fraud layers that decide whether the event should be trusted.",
            "If you only look at the beacon itself, you miss the market structure that makes pixels valuable or misleading. The useful question is not just did the pixel fire. It is who generated it, under which standard, for which event, and whether the rest of the chain gives that event any credibility."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Where pixels show up in the ad stack",
          "paragraphs": [
            "In video and CTV, the canonical home for event tracking is VAST. The standard defines impression URLs, tracking events, error URLs, click paths, verification resources, and the XML structure that tells a player or intermediary what should be called and when.",
            "For multi-break programming, VMAP sits one level above that. Google Ad Manager describes VMAP as a standard way to define multiple ad breaks, where each break contains VAST ad tag URIs. The player or IMA SDK then requests each ad, follows redirects, chooses media, and fires the related tracking events. That is one reason troubleshooting often feels like debugging a call graph instead of a single tag.",
            "Outside video, similar beacon patterns exist across web analytics, affiliate attribution, email open tracking, fraud detection, and retail media measurement. The mechanics are comparable even when the transport or event names differ. A pixel is usually a very small reporting interface into a much larger workflow."
          ]
        },
        {
          "type": "list",
          "heading": "The main actor groups in the pixel ecosystem",
          "items": [
            "Publishers and app owners, who expose inventory and need impression, completion, and revenue reporting.",
            "Ad servers and SSPs, which traffic tags, apply macros, redirect requests, and often originate part of the measurement chain.",
            "DSPs and buyers, which need event callbacks for pacing, attribution, optimization, and fraud review.",
            "Measurement and verification vendors, which layer on viewability, attention, OM SDK, brand-safety, or invalid-traffic signals.",
            "Identity and registry providers, which help map the creative or transaction to a shared identifier instead of a vendor-local label.",
            "Privacy, browser, and platform gatekeepers, which increasingly decide which beacons are allowed to exist, persist, or remain trustworthy."
          ]
        },
        {
          "type": "code",
          "heading": "The pixel layer is usually simple XML hiding a complex chain",
          "language": "xml",
          "code": "<InLine>\n  <Impression><![CDATA[https://tracker.example.com/imp?cb=[CACHEBUSTING]]]> </Impression>\n  <Creatives>\n    <Creative>\n      <Linear>\n        <TrackingEvents>\n          <Tracking event=\"start\"><![CDATA[https://tracker.example.com/start?id=[ADID]]]> </Tracking>\n          <Tracking event=\"firstQuartile\"><![CDATA[https://tracker.example.com/q1?id=[ADID]]]> </Tracking>\n          <Tracking event=\"complete\"><![CDATA[https://tracker.example.com/complete?id=[ADID]]]> </Tracking>\n        </TrackingEvents>\n      </Linear>\n    </Creative>\n  </Creatives>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "Registries matter because pixels need shared identity",
          "paragraphs": [
            "One reason the ecosystem gets messy is that the same creative, campaign, or placement can be named differently at every hop. That is why registries and shared identifiers matter. In VAST this often appears as UniversalAdId with an idRegistry field, which tells downstream systems which identifier namespace they are looking at.",
            "A concrete example is AD-ID, which describes itself as the advertising industry's ad registry. Whether or not every workflow uses AD-ID directly, the idea is important: pixels become more useful when the event can be reconciled to a recognized creative identity instead of an SSP-specific label or a spreadsheet nickname.",
            "Without a shared registry or stable identifier, tracking becomes a stitching problem. Teams spend time debating whether two beacon trails refer to the same creative rather than analyzing performance or fraud."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why the market keeps moving away from browser-era assumptions",
          "paragraphs": [
            "The tracking-pixel ecosystem used to feel like a browser problem: drop a beacon, set a cookie, collect events, optimize. That picture is incomplete now. CTV, mobile apps, SSAI, privacy controls, and anti-fraud expectations have all changed what a pixel can realistically prove.",
            "IAB Tech Lab's VAST CTV Addendum 2024 is a good marker of that shift. It ties modern CTV implementation to ACIF support, Open Measurement, higher-resolution creative, and better compatibility across real TV environments. That is not just a formatting update. It reflects a market where the event log needs stronger operational context.",
            "The result is a more layered ecosystem. Pixels still matter, but they now sit beside ad registration, authenticated supply-path metadata, SDK measurement, device-level signals, and server-side reporting systems."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Client-side versus server-side beaconing changes the trust model",
          "paragraphs": [
            "A lot of teams still imagine the player firing every tracking URL directly. That still happens, but it is no longer the only model. Google Ad Manager's trafficking documentation explicitly distinguishes server-side beaconing, including an impression-pinging entity signal and the value ipe=ssb when the server sends impression beacons.",
            "That changes how you interpret the data. A server-originated beacon can improve reliability in some environments and make certain workflows possible in SSAI or constrained-player contexts. It also means a fired beacon may tell you more about infrastructure behavior than about what happened on a specific device surface.",
            "This is why modern measurement conversations are increasingly about layered evidence. The pixel is still useful, but now you also need to know whether the event came from the device, the player SDK, a server-side intermediary, or a verification partner."
          ]
        },
        {
          "type": "quote",
          "quote": "The pixel is the message. The ecosystem is the proof model.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Public tracker catalogs help explain the outside edge of the market",
          "paragraphs": [
            "If you want to understand how large and fragmented the beacon universe has become, public tracker catalogs are useful even when they are not ad-tech standards. Disconnect's tracker-protection repository, for example, maintains a categorized services.json dataset spanning categories such as Advertising, Analytics, Social, ConsentManagers, Anti-fraud, and multiple fingerprinting-related groups.",
            "That kind of public catalog is not a canonical registry for ad operations. It is better thought of as a market map compiled from the privacy and tracker-protection side. But it makes one thing very clear: the modern pixel ecosystem extends far beyond classic ad servers. The same page or app experience can involve advertising, analytics, attribution, consent, anti-fraud, and fingerprinting vendors all emitting or interpreting related signals.",
            "For operators, that means governance matters. The question is no longer only which tracking URL to place in the tag. It is which classes of trackers are entering the environment, which of them are essential, and how many of them can still be defended under privacy and performance constraints."
          ]
        },
        {
          "type": "list",
          "heading": "What a healthy pixel strategy looks like in 2026",
          "items": [
            "Keep VAST and VMAP event wiring clean so each event has a clear owner and reason to exist.",
            "Prefer stable creative identifiers and registries where available so event reconciliation is possible across vendors.",
            "Document whether critical beacons are client-side, SDK-mediated, or server-side beaconed.",
            "Treat verification, OM SDK, and anti-fraud signals as complementary evidence rather than assuming a fired pixel settles the question.",
            "Review third-party trackers as part of supply-path governance, not just implementation QA.",
            "Assume that privacy controls, browser limits, and app-platform changes will continue to narrow which historical pixel habits remain viable."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The practical takeaway",
          "paragraphs": [
            "The tracking pixel ecosystem works because simple event URLs are cheap, interoperable, and easy to distribute. It becomes confusing because those same URLs are asked to carry too much meaning on their own.",
            "If you want cleaner reporting, better fraud review, and fewer debates between buyers, sellers, and verification partners, the fix is not more pixels by default. The fix is better structure around them: standards-compliant tags, explicit measurement ownership, stable identifiers, and a realistic understanding of which systems are actually generating the evidence.",
            "That is the real market now. Pixels are still everywhere. They are just no longer the whole story."
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "VAST standards overview",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "IAB Tech Lab overview of VAST and the current family of video ad-serving specifications.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST CTV Addendum 2024 ready for implementation",
              "href": "https://iabtechlab.com/vast-ctv-addendum-2024-ready-for-implementation/",
              "description": "IAB Tech Lab summary of the CTV addendum, including ACIF, Open Measurement, high-resolution creative, and DSA icon support.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Create and use VMAP ad rules",
              "href": "https://support.google.com/admanager/answer/4539582",
              "description": "Google Ad Manager documentation explaining VMAP, multi-break structures, and how players request VAST ads and tracking events.",
              "source": "Google Ad Manager"
            },
            {
              "label": "AD-ID",
              "href": "https://www.ad-id.org/",
              "description": "The advertising industry's creative ID registry and naming system for campaign assets.",
              "source": "AD-ID"
            },
            {
              "label": "Disconnect tracking protection services catalog",
              "href": "https://github.com/disconnectme/disconnect-tracking-protection/blob/master/services.json",
              "description": "Public categorized tracker catalog spanning advertising, analytics, social, consent, anti-fraud, and fingerprinting groups.",
              "source": "Disconnect"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Inspect the chain behind the pixel",
          "paragraph": "Load a live tag, unwrap the redirects, and review the impression, quartile, click, error, and verification URLs before they become a reporting argument later.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "tracking-pixels-wont-save-you-from-ctv-fraud",
      "title": "Tracking Pixels Won't Save You From CTV Fraud",
      "description": "A tracking pixel can confirm that a URL fired. In 2026, that is no longer the same thing as proving a real CTV impression happened. Recent IAB Tech Lab guidance makes the gap harder to ignore.",
      "publishedAt": "2026-05-20",
      "updatedAt": "2026-05-20",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Fraud and measurement",
      "tags": [
        "Ad fraud",
        "CTV",
        "Tracking pixels",
        "OM SDK"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "The old habit is to trust the pixel",
          "paragraphs": [
            "For years, a lot of video troubleshooting ended with the same question: did the impression pixel fire? If it did, teams moved on. If it did not, they dug into the tag. That habit made sense when the main problem was whether a browser or player called the URL it was given.",
            "That is not the whole problem anymore, especially in CTV. A fired pixel can prove that some system made a request. It does not, by itself, prove that a real TV app rendered a real ad on a real device for a real viewer.",
            "That distinction matters more in 2026 because the anti-fraud conversation in CTV has moved away from simple beacon counting and toward attested device signals, signed server-to-server messages, and clearer supply-path identity."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why this is suddenly a live issue again",
          "paragraphs": [
            "IAB Tech Lab's January 2026 standards update made the shift explicit. Its recommendation to implement OM SDK for CTV with Device Attestation is not just a measurement feature release. It is a response to device spoofing and weak trust signals in streaming environments.",
            "The same CTV Programmatic Guide is even more direct. It separates classic transparency tools such as ads.txt, sellers.json, SupplyChain, and ads.cert from the measurement layer, and then calls out Device Attestation as the answer to spoofed device claims. In other words: the ecosystem is treating a pixel fire as one signal among several, not as the final word.",
            "If you are still evaluating premium CTV delivery with a browser-era mindset, you are probably over-trusting logs that were never designed to settle fraud questions on their own."
          ]
        },
        {
          "type": "list",
          "heading": "What a pixel can tell you, and what it cannot",
          "items": [
            "It can tell you that a URL was requested at a point in the delivery chain.",
            "It can help you detect missing events, malformed macros, HTTPS drift, duplicate beacons, and broken partner wiring.",
            "It cannot prove that the device identity in the request was genuine.",
            "It cannot prove that the screen was on, the app was authentic, or the ad was actually viewable in a CTV runtime.",
            "It cannot tell you whether a server-side intermediary fabricated or replayed the beacon.",
            "It cannot replace signed transport, supply-path transparency, or attested measurement signals."
          ]
        },
        {
          "type": "code",
          "heading": "A modern tag still needs clean pixels, but not only pixels",
          "language": "xml",
          "code": "<InLine>\n  <Impression><![CDATA[https://tracker.example.com/imp?cb=[CACHEBUSTING]]]></Impression>\n  <Creatives>\n    <Creative>\n      <Linear>\n        <Duration>00:00:15</Duration>\n        <TrackingEvents>\n          <Tracking event=\"start\"><![CDATA[https://tracker.example.com/start]]></Tracking>\n          <Tracking event=\"complete\"><![CDATA[https://tracker.example.com/complete]]></Tracking>\n        </TrackingEvents>\n        <MediaFiles>\n          <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n            <![CDATA[https://cdn.example.com/ads/spot-15s.mp4]]>\n          </MediaFile>\n        </MediaFiles>\n      </Linear>\n    </Creative>\n  </Creatives>\n  <AdVerifications>\n    <Verification vendor=\"measurement.example\">\n      <JavaScriptResource apiFramework=\"omid\"><![CDATA[https://verification.example.com/omid.js]]></JavaScriptResource>\n    </Verification>\n  </AdVerifications>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "VAST is still where the weak signals leak in",
          "paragraphs": [
            "None of this makes VAST hygiene less important. It makes it more important. Fraud review gets worse when the tag is already sloppy. HTTP trackers, duplicated impressions, inconsistent quartile URLs, dead verification resources, and wrapper chains that hide who is calling what all make the evidence harder to trust.",
            "A bad tag creates two problems at once. First, it can directly break delivery or measurement. Second, it muddies the audit trail when someone later asks whether the discrepancy was fraud, a player issue, or just careless trafficking.",
            "That is why pixel QA and anti-fraud work should not sit in separate buckets anymore. If the tracker layer is noisy, your fraud analysis starts from compromised data."
          ]
        },
        {
          "type": "quote",
          "quote": "A pixel tells you a request happened. It does not tell you the impression was trustworthy.",
          "attribution": "vastlint field note"
        },
        {
          "type": "list",
          "heading": "What to review before you trust the measurement",
          "items": [
            "Validate every impression, quartile, error, click, and verification URL in the trafficked VAST, not just the sample XML from the vendor deck.",
            "Remove duplicate or contradictory trackers so one playback event does not create a noisy measurement trail.",
            "Require HTTPS everywhere, including tracking and verification resources, because mixed-content failures still create false debugging trails.",
            "Ask the seller or platform whether OM SDK for CTV is implemented and whether Device Attestation is part of the measurement path.",
            "Check whether server-to-server hops that matter to your reporting use signed protocols such as ads.cert Authenticated Connections.",
            "Reconcile campaign performance against post-IVT or post-SIVT numbers when the buying agreement supports that distinction, rather than treating raw counts as final truth."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "The practical takeaway for ad ops teams",
          "paragraphs": [
            "Do not throw away pixels. You still need them, and you still need them to be clean. They remain one of the fastest ways to catch broken tags, missing macros, vendor misfires, and partner regressions before a campaign burns budget.",
            "But stop treating a fired pixel as a complete answer to fraud or quality questions in CTV. The recent standards work is pushing the market toward a layered trust model: transparent seller identity, authenticated transport, and attested measurement on the device side. That is the right model because the fraud is no longer limited to malformed XML. It lives in the claims around the XML too.",
            "If your workflow only inspects whether the beacon fired, you are checking the easiest signal to fake and ignoring the ones the industry is finally standardizing to trust."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "VAST tag testing",
              "href": "/docs/vast-tag-testing/",
              "description": "How to inspect impression, quartile, click, and verification URLs before launch.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML",
              "href": "/docs/validate-vast-xml/",
              "description": "The baseline XML, URL, and tracking checks that should happen before trafficking.",
              "source": "Docs"
            },
            {
              "label": "Common VAST errors",
              "href": "/docs/common-vast-errors/",
              "description": "The low-level mistakes that often turn a fraud investigation into a measurement mess.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Resolve to Update Your Tech Lab Standards in 2026",
              "href": "https://iabtechlab.com/resolve-to-update-your-tech-lab-standards-in-2026/",
              "description": "IAB Tech Lab's 2026 standards note highlighting OM SDK for CTV with Device Attestation as a priority.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "CTV Programmatic Guide",
              "href": "https://iabtechlab.com/standards/advanced-tv/ctv-programmatic-guide/",
              "description": "The current guide mapping CTV fraud, measurement, ads.txt, sellers.json, ads.cert, and Device Attestation to specific use cases.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Ads.cert",
              "href": "https://iabtechlab.com/standards/ads-cert/",
              "description": "Overview of authenticated server-to-server protocols for origin authentication and tamper resistance in advertising flows.",
              "source": "IAB Tech Lab"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Inspect the tracker layer before someone argues about fraud",
          "paragraph": "Use the inspector to unwrap the live chain, review every tracking URL, and clean up obvious evidence problems before the campaign goes into market.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "ctv-has-graduated-your-vast-tags-need-to-grow-up-too",
      "title": "CTV Has Graduated. Your VAST Tags Need to Grow Up Too",
      "description": "A recent IAB Tech Lab note on CTV maturity is the right cue for ad ops teams: if connected TV is now infrastructure, VAST tags have to carry production-grade metadata, measurement, and latency discipline.",
      "publishedAt": "2026-05-12",
      "updatedAt": "2026-05-12",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "CTV maturity",
      "tags": [
        "CTV",
        "VAST 4.3",
        "SSAI",
        "Live streaming"
      ],
      "featured": false,
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Maturity changes the QA bar",
          "paragraphs": [
            "In a recent IAB Tech Lab article, Brad Pipkin argues that CTV has moved from naming debates into implementation, measurement, and live-event execution. That framing matters for anyone shipping VAST tags because the failures that remain are less about whether XML loads and more about whether the tag behaves predictably across SSAI, verification, and device-specific playback.",
            "When a channel matures, tolerance for ambiguous signaling drops. Buyers want consistent classification, sellers need interoperable delivery, and measurement partners expect richer metadata than a bare-bones inline creative.",
            "That means a VAST tag built for browser-era QA is no longer enough for premium streaming inventory in 2026."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What CTV maturity means inside the tag",
          "paragraphs": [
            "The recent IAB piece points to VAST 4.3, OpenRTB 2.6, AdCOM, OM SDK for CTV, and live-event guidance as part of the stack that turns definitions into systems. In practice, VAST is where several of those expectations become concrete: asset signaling, verification behavior, SSAI support, and the metadata the player and measurement layer depend on.",
            "The VAST standards page tells the same story in version-history form. The current CTV addendum is not cosmetic. It explicitly calls out ACIF support for ad registration, icons that support DSA compliance, and the need for higher-resolution creative on larger screens. That is the difference between a tag that merely parses and a tag that is ready for modern TV inventory.",
            "If your tag still relies on thin metadata, deep wrapper chains, legacy interactivity, or media assets chosen for web convenience instead of device reliability, you are carrying pre-maturity assumptions into a mature environment."
          ]
        },
        {
          "type": "list",
          "heading": "The fields and behaviors worth tightening now",
          "items": [
            "Prefer VAST 4.x or 4.3 responses when the supply path supports them, especially for SSAI and modern measurement expectations.",
            "Include UniversalAdId and other creative metadata that make cross-platform reporting and traceability easier.",
            "Keep wrapper chains short enough for real CTV latency budgets, not just spec-maximum hop counts.",
            "Require HTTPS across media, tracking, error, and verification URLs.",
            "Provide creative assets that are actually sized and encoded for large-screen playback, not just browser-safe defaults.",
            "Ship at least one CTV-safe MP4 rendition and provide mezzanine coverage where premium or SSAI paths expect it.",
            "Audit interactive assumptions so SIMID or native controls are used where appropriate and legacy VPAID dependencies are removed.",
            "Check pod and live-event behavior explicitly because concurrency stress exposes weak redirects and slow third-party beacons first."
          ]
        },
        {
          "type": "code",
          "heading": "A cleaner starting point for a modern CTV creative",
          "language": "xml",
          "code": "<InLine>\n  <Creatives>\n    <Creative sequence=\"1\" adId=\"spring-launch\">\n      <UniversalAdId idRegistry=\"Ad-ID\">ABCD1234000H</UniversalAdId>\n      <Linear>\n        <Duration>00:00:15</Duration>\n        <MediaFiles>\n          <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\" bitrate=\"4500\">\n            <![CDATA[https://cdn.example.com/ads/spring-launch-15s.mp4]]>\n          </MediaFile>\n          <Mezzanine delivery=\"streaming\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n            <![CDATA[https://cdn.example.com/ads/spring-launch-master.mp4]]>\n          </Mezzanine>\n        </MediaFiles>\n      </Linear>\n    </Creative>\n  </Creatives>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "The partner questions are now technical questions",
          "paragraphs": [
            "The new buyer guide from IAB Tech Lab and the WFA is useful because it turns CTV diligence into a standards checklist. Buyers are told to ask whether providers actually support the standards they claim to support, from OM SDK to the Forecasting API, and whether they can signal what counts as live inventory accurately.",
            "Translate that into VAST review and the implications are direct. You need to know whether measurement survives the real playback path, whether the provider distinguishes live from VOD correctly, whether pod behavior and forecasting match how the campaign will be sold, and whether the ad formats they promise are backed by a creative package your tag can actually deliver.",
            "That is a better editorial lens for VAST QA in 2026: stop asking only whether the XML is valid and start asking whether the tag matches the transaction, the measurement plan, and the player environment the provider is putting in market."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Live streaming is where shortcuts surface",
          "paragraphs": [
            "The same IAB post highlights live streaming as the place where CTV starts meeting broadcast-level expectations. It calls out fill rates, latency risk, forecasting, bandwidth pressure, and ad pod execution as the new pressure points. That is exactly where VAST shortcuts become expensive.",
            "A long wrapper chain, slow verification call, or missing high-quality asset may be tolerated in low-volume QA and then fail under live concurrency.",
            "If you sell sports, tentpole entertainment, or premium news, treat live-event traffic as a separate launch class. The acceptable tag is the one that resolves quickly, measures cleanly, and renders on the real device mix under pressure."
          ]
        },
        {
          "type": "quote",
          "quote": "CTV maturity does not demand fancier XML. It demands fewer hidden assumptions between request, response, player, and measurement.",
          "attribution": "vastlint operations note"
        },
        {
          "type": "list",
          "heading": "A publish-today review before the next campaign goes live",
          "items": [
            "Resolve the full wrapper chain and record actual hop count and per-hop latency.",
            "Confirm final media choices against the device classes you actually serve, not just desktop playback.",
            "Ask the provider how it signals live inventory, where OM measurement runs, and what standards-based features are active on the real playback path.",
            "Review verification, tracking, and error URLs for HTTPS and partner stability.",
            "Make sure creative IDs and metadata match how the campaign will be measured downstream.",
            "Re-run the check on the trafficked line item, not only the partner sample tag."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Why practical redirect budgets matter more on TV devices and during live events.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Google IMA SDK",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "How one of the most common player stacks interprets wrappers, media files, and runtime events.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Roku RAF",
              "href": "/guides/vast-roku-raf/",
              "description": "Roku-specific delivery assumptions that often expose weak VAST chains first.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Amazon Fire TV",
              "href": "/guides/vast-amazon-fire-tv/",
              "description": "Fire TV runtime and format details that matter once CTV traffic becomes operationally strict.",
              "source": "Guide"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the tag before CTV traffic does it for you",
          "paragraph": "Run the validator for a fast XML pass, then inspect the full wrapper chain so live-event and device-specific failures show up before launch day.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "why-ctv-vast-tags-fail-after-qa",
      "title": "Why CTV VAST Tags Still Fail After QA",
      "description": "The tags that pass a quick validator pass in the browser but still collapse on real TV devices usually break on wrapper depth, codec assumptions, HTTPS drift, or missing mezzanine expectations. This is the checklist that catches the expensive misses.",
      "publishedAt": "2026-05-10",
      "updatedAt": "2026-05-11",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "CTV delivery",
      "tags": [
        "CTV",
        "SSAI",
        "VAST QA",
        "Wrapper chains"
      ],
      "featured": false,
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Passing validation is not the same as passing delivery",
          "paragraphs": [
            "A normal XML validator can tell you whether the tag is structurally valid. It cannot tell you whether the fourth wrapper in a chain times out on a Samsung panel, whether the MP4 is encoded in a way a Roku box will reject, or whether a buyer-side HTTPS check will silently zero-fill the impression.",
            "That is why CTV failures often look random in launch week. The tag technically works, but the player environment is stricter than the test harness you used before trafficking.",
            "The IAB Tech Lab's recent VAST 4.3 and CTV addendum work is a good reminder that connected TV is not just browser video on a bigger screen. Resolution expectations, measurement behavior, asset handling, and device runtimes all matter more."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why browser QA misses TV-specific breakpoints",
          "paragraphs": [
            "Desktop validation usually happens on fast office networks, modern browsers, and player stacks that tolerate redirect latency. Real CTV traffic lands on constrained consumer networks, device SDKs with tighter wrapper budgets, and native playback engines that are much less forgiving about codecs and HTTPS drift.",
            "That gap explains why a tag can pass basic QA on Friday and underdeliver on Monday. The XML did not change. The execution environment did."
          ]
        },
        {
          "type": "list",
          "heading": "The failures that show up first in production",
          "items": [
            "Wrapper chains that resolve eventually on a desktop connection but exceed the practical hop budget on a TV device.",
            "Media files that are legal VAST but not a CTV-safe encoding profile for the device or SDK in play.",
            "HTTP tracking and creative URLs that survive QA but are blocked when the device runtime enforces HTTPS only.",
            "VPAID or other interactive assumptions that still appear in a third-party response long after the receiving platform stopped accepting them.",
            "Missing mezzanine or incomplete metadata in environments that expect a richer asset package for SSAI or premium CTV delivery.",
            "Player-specific requirements such as Roku RAF measurement handling or Google IMA wrapper limits that were never exercised in the original test harness."
          ]
        },
        {
          "type": "quote",
          "quote": "Most CTV outages are not caused by a broken root document. They are caused by a chain of individually small assumptions that only fail when the real device is in the loop.",
          "attribution": "vastlint field note"
        },
        {
          "type": "code",
          "heading": "A safer media section for premium TV inventory",
          "language": "xml",
          "code": "<Linear>\n  <Duration>00:00:15</Duration>\n  <MediaFiles>\n    <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1920\" height=\"1080\" bitrate=\"4500\">\n      <![CDATA[https://cdn.example.com/ads/brand-15s-h264-aac.mp4]]>\n    </MediaFile>\n    <Mezzanine delivery=\"streaming\" type=\"video/mp4\" width=\"1920\" height=\"1080\">\n      <![CDATA[https://cdn.example.com/ads/brand-15s-master.mp4]]>\n    </Mezzanine>\n  </MediaFiles>\n</Linear>"
        },
        {
          "type": "list",
          "heading": "A practical CTV preflight before launch",
          "items": [
            "Resolve the full wrapper chain and count real hops, not just the redirects visible in the first partner handoff.",
            "Confirm that every URL in the chain is HTTPS, including impressions, errors, click trackers, and companion assets.",
            "Verify that at least one MP4 H.264 asset is available for device classes that do not tolerate web-oriented encodes.",
            "Check whether the receiving stack expects mezzanine, higher-resolution creative, or extra metadata for SSAI and premium CTV paths.",
            "Reject any path that still depends on VPAID when the destination is tvOS, Fire TV, Roku, webOS, or another CTV runtime.",
            "Test on the actual player class that will serve the campaign, not just a browser inspector or desktop sample app."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Match QA to the actual receiving stack",
          "paragraphs": [
            "Before launch, validate the raw XML, then inspect the live wrapper chain, then check the receiving player class. Google IMA on web, Google IMA on tvOS, Roku RAF, and server-side stitched playback each fail differently.",
            "For example, Google IMA commonly makes teams think in terms of a four-hop wrapper ceiling, while Roku RAF forces a second conversation about practical timeout budgets, measurement beacons, and how ads are rendered in the actual device runtime.",
            "If the campaign matters, your launch gate should be player-specific, not just schema-specific. That is the difference between catching the expensive misses early and learning about them from underdelivery after launch."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Platform wrapper limits, followAdditionalWrappers behavior, and why extra hops quietly kill delivery.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Google IMA SDK",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "What IMA expects across web, mobile, and CTV, including wrapper limits and VPAID policy.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Roku RAF",
              "href": "/guides/vast-roku-raf/",
              "description": "Roku-specific constraints around wrapper timing, media formats, and tracking behavior.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Apple tvOS",
              "href": "/guides/vast-apple-tvos/",
              "description": "How tvOS behaves when playback runs through the Google IMA SDK for tvOS.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Amazon Fire TV",
              "href": "/guides/vast-amazon-fire-tv/",
              "description": "Fire TV format, HTTPS, and runtime assumptions that often cause launch-week regressions.",
              "source": "Guide"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The official IAB Tech Lab overview and version history for VAST, including VAST 4.3.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST CTV Addendum 2024",
              "href": "https://iabtechlab.com/wp-content/uploads/2024/07/VAST-CTV-Addendum-2024-FINAL.pdf",
              "description": "The CTV addendum covering newer creative expectations, device-oriented support, and CTV-specific updates.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Integrating the Roku Advertising Framework",
              "href": "https://developer.roku.com/en-gb/docs/developer-program/advertising/integrating-roku-advertising-framework.md",
              "description": "Roku's guide to client-side and server-side ad insertion, tracking, and RAF-specific implementation details.",
              "source": "Roku Developer"
            },
            {
              "label": "Set up the IMA SDK",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/get-started",
              "description": "Google's IMA setup guide and runtime model for requesting ads, managing ad playback, and handling events.",
              "source": "Google IMA"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Run the tag before it burns a week of delivery",
          "paragraph": "Use the validator for a fast structural check, then use the inspector to follow every wrapper hop and spot the CTV-specific breakpoints before the campaign goes live.",
          "href": "/inspect/",
          "label": "Inspect a wrapper chain"
        }
      ]
    },
    {
      "slug": "vast-4-3-launch-checklist-for-gam-and-ima",
      "title": "A VAST 4.3 Launch Checklist for Google Ad Manager and IMA",
      "description": "If the tag is going through GAM and the final playback path is IMA, most launch mistakes happen in the handoff: wrapper depth, parameter hygiene, HTTPS assets, and assumptions about deprecated interactive formats.",
      "publishedAt": "2026-05-08",
      "updatedAt": "2026-05-11",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "GAM + IMA",
      "tags": [
        "Google Ad Manager",
        "IMA SDK",
        "VAST 4.3",
        "Launch QA"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Treat GAM as one more wrapper in your budget",
          "paragraphs": [
            "Teams still lose time by counting only the third-party wrappers they can see. In many trafficking setups, GAM adds its own wrapper layer before the IMA SDK resolves the rest of the chain. That means your practical budget is smaller than the tag owner thinks it is.",
            "If you hand off a tag that already depends on several redirects, you are choosing latency and risk before the player ever sees an inline creative.",
            "That is the operational reason to inspect the full path as it will run in production, not just the vendor-supplied URL in isolation."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Parameter hygiene is part of delivery, not paperwork",
          "paragraphs": [
            "Google Ad Manager's own help docs separate required parameters from programmatic and recommended parameters for a reason. Missing values like correlator, description_url, env, gdfp_req, iu, output, sz, unviewed_position_start, and url are not documentation trivia. They shape whether the request is understood correctly and whether measurement and policy expectations are met.",
            "For programmatic and OTT traffic, parameters like plcmt, vpa, vpmute, ott_placement, omid_p, and vid_d become part of launch quality too. Teams often call a tag valid while still shipping a request that is incomplete for the actual inventory type.",
            "If the last mile is Google IMA, the runtime contract matters as much as the URL. IMA needs a correctly sized ad container, sane lifecycle handling, and ad requests that match the player context you are actually shipping."
          ]
        },
        {
          "type": "list",
          "heading": "What to verify before launch",
          "items": [
            "The request will stay within a four-hop total wrapper budget once GAM is included.",
            "Every asset and tracking URL is HTTPS and resolves cleanly from the target environment.",
            "The media files are native video assets, not legacy VPAID dependencies hiding in the chain.",
            "UniversalAdId and other VAST 4.x metadata are present where downstream buying and reporting expect them.",
            "The request parameters are correct for the actual platform, especially when the destination is CTV or app inventory.",
            "The destination player handles pause, resume, resize, and non-linear behavior the way IMA expects instead of leaving those cases to chance.",
            "The final inspected chain is the same one your operators think they trafficked."
          ]
        },
        {
          "type": "code",
          "heading": "A cleaner request shape for web or CTV trafficking",
          "language": "text",
          "code": "https://pubads.g.doubleclick.net/gampad/ads?\n  env=instream&\n  gdfp_req=1&\n  iu=/6062/example/video&\n  output=xml_vast4&\n  sz=1920x1080&\n  description_url=https%3A%2F%2Fpublisher.example%2Fshows%2Fdemo&\n  url=https%3A%2F%2Fpublisher.example%2Fepisode%2F123&\n  unviewed_position_start=1&\n  plcmt=1&\n  vpa=auto&\n  vpmute=0&\n  omid_p=example-player&\n  correlator=1234567890"
        },
        {
          "type": "paragraphs",
          "heading": "Remember the IMA runtime contract",
          "paragraphs": [
            "Google's own IMA guidance is clear on the operating model: keep one AdsLoader for the lifecycle of the page or app view, build the AdDisplayContainer correctly, listen for ADS_MANAGER_LOADED and AD_ERROR, and wire CONTENT_PAUSE_REQUESTED and CONTENT_RESUME_REQUESTED so content playback behaves correctly around ad breaks.",
            "That sounds basic, but it is where many launches still regress. A perfect VAST response cannot save an integration that never resizes the AdsManager, mishandles non-linear ads, or starts playback outside the user-action constraints of the platform.",
            "This is also why browser-only validation is not enough. The URL shape, the VAST payload, and the receiving runtime have to agree."
          ]
        },
        {
          "type": "list",
          "heading": "Where teams still regress on VAST 4.x",
          "items": [
            "Serving VPAID through a path that ultimately lands on mobile or CTV IMA where it is blocked anyway.",
            "Assuming GAM parameters can be copied between web, app, and OTT without checking the implementation-specific requirements.",
            "Leaving UniversalAdId, OMID context, or measurement-related metadata inconsistent across trafficking variants.",
            "Treating it loads in the browser sample player as equivalent to a real production validation step.",
            "Skipping a final wrapper inspection after the trafficked line item is actually live."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "VAST XML for Google Ad Manager",
              "href": "/guides/vast-google-ad-manager/",
              "description": "GAM wrapper behavior, parameter coverage, and trafficking-specific VAST guidance.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Google IMA SDK",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "The player-side expectations that determine whether a trafficked tag will actually render.",
              "source": "Guide"
            },
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Why GAM should be counted as part of your real redirect budget.",
              "source": "Guide"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "VAST ad tag parameters for web",
              "href": "https://support.google.com/admanager/answer/10655276",
              "description": "Google Ad Manager's required, programmatic, and recommended parameters for web VAST implementations.",
              "source": "Google Ad Manager"
            },
            {
              "label": "Set up the IMA SDK",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/get-started",
              "description": "Google's reference workflow for building the ad container, AdsLoader, AdsManager, and playback lifecycle.",
              "source": "Google IMA"
            },
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The official spec landing page and version history for VAST 2.0 through 4.3.",
              "source": "IAB Tech Lab"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate before trafficking",
          "paragraph": "Use the main validator for a fast pass over the XML before the tag reaches GAM or the IMA SDK, then keep the inspector for the final wrapper-chain check.",
          "href": "/validate/",
          "label": "Open the validator"
        }
      ]
    },
    {
      "slug": "reduce-wrapper-chain-revenue-loss-before-launch",
      "title": "How to Reduce Wrapper-Chain Revenue Loss Before Launch",
      "description": "Wrapper chains do not fail only when they hit a hard limit. They lose money earlier through latency, redirect fragility, and inconsistent tracking behavior. A shorter chain is not just cleaner engineering. It is better economics.",
      "publishedAt": "2026-05-05",
      "updatedAt": "2026-05-11",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Wrapper chains",
      "tags": [
        "Wrapper chains",
        "Revenue recovery",
        "Latency",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Four hops is not the real threshold",
          "paragraphs": [
            "Ad teams often talk about wrapper depth as if there is a single safe line. In reality, commercial damage starts before the formal limit. Each additional hop adds one more network dependency, one more timeout surface, and one more place where tracking can diverge from the final inline response.",
            "By the time the player returns a visible error, the chain has already been leaking opportunity.",
            "This is why the formal wrapper maximum in a spec or SDK should be treated as the cliff edge, not the planning target."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why wrapper chains leak money before they fail",
          "paragraphs": [
            "Every redirect adds latency to time-to-first-frame. On consumer networks and CTV devices that extra second or two is enough to lower fill, increase abandonment, or push the impression into a timeout bucket that never becomes revenue.",
            "Extra hops also make outages harder to attribute. When one partner in the middle of the chain starts returning intermittent 5xx responses, the publisher usually feels it first as underdelivery, not as a neat root-cause report.",
            "Even when the ad finally resolves, longer chains create more opportunities for impression, click, and quartile tracking to drift from the final rendered asset. That affects reporting confidence and partner trust."
          ]
        },
        {
          "type": "list",
          "heading": "What a shorter chain buys you",
          "items": [
            "Faster time-to-first-frame for video ad playback.",
            "Less variance across consumer networks, especially on connected TV devices.",
            "Fewer third-party outages that manifest as unexplained underdelivery.",
            "Cleaner debugging because the failing partner is easier to isolate.",
            "Better odds that impression, click, and quartile tracking remain consistent across the chain."
          ]
        },
        {
          "type": "code",
          "heading": "A simple partner review frame",
          "language": "text",
          "code": "If this partner adds another redirect, ask three questions:\n1. Does it add unique demand or measurement value?\n2. Can the same result be achieved in one hop less?\n3. Has the final chain been tested on the actual receiving player?"
        },
        {
          "type": "list",
          "heading": "What to instrument before launch",
          "items": [
            "Total wrapper depth and which partner owns each hop.",
            "Time spent resolving each redirect, not just the total time at the end.",
            "Final media MIME type, bitrate, and dimensions so player compatibility issues surface early.",
            "Any 3xx, 4xx, or 5xx behavior in intermediate redirects that would be invisible in a one-pass validator.",
            "Tracking URLs that downgrade to HTTP or point to brittle third-party domains.",
            "Whether the trafficked line item changes the chain shape relative to the vendor sample URL."
          ]
        },
        {
          "type": "quote",
          "quote": "Wrapper depth is not just a spec issue. It is a compounding risk multiplier across latency, uptime, and reporting confidence.",
          "attribution": "vastlint operations note"
        },
        {
          "type": "paragraphs",
          "heading": "When to accept another redirect anyway",
          "paragraphs": [
            "Some extra hops are commercially justified. A redirect that genuinely adds incremental demand, critical measurement, or marketplace access may be worth keeping. But it should be defended with evidence, not habit.",
            "The right operating rule is simple: every extra hop has to earn its place. If it cannot explain the revenue or control value it adds, cut it before launch rather than debugging it after underdelivery shows up in pacing."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "A deeper look at wrapper structure, platform limits, and debugging strategy.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Google Ad Manager",
              "href": "/guides/vast-google-ad-manager/",
              "description": "Useful if GAM is one of the layers consuming part of your real wrapper budget.",
              "source": "Guide"
            },
            {
              "label": "VAST XML for Google IMA SDK",
              "href": "/guides/vast-google-ima-sdk/",
              "description": "How one of the most common player stacks behaves when chains get too deep or too slow.",
              "source": "Guide"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The spec family behind wrapper behavior, inline responses, and version history.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VAST ad tag parameters for web",
              "href": "https://support.google.com/admanager/answer/10655276",
              "description": "Helpful for spotting request-shape issues that compound wrapper-chain problems in live delivery.",
              "source": "Google Ad Manager"
            },
            {
              "label": "Set up the IMA SDK",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/get-started",
              "description": "Useful for understanding how the player side handles ad loading, lifecycle events, and failures.",
              "source": "Google IMA"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Follow the whole chain, not just the first response",
          "paragraph": "Paste a VAST URL into the inspector and walk every hop before the campaign launches. That is where the hidden loss usually lives.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "how-to-validate-vast-trackers-before-launch",
      "title": "How to Validate VAST Trackers Before Launch",
      "description": "Tracker validation is not just opening a pixel URL in a browser. This is the practical pre-launch review for impression, quartile, click, and error trackers across wrappers, macros, HTTPS, and player context.",
      "publishedAt": "2026-06-05",
      "updatedAt": "2026-06-05",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "Tracker validation",
      "tags": [
        "Tracking pixels",
        "VAST QA",
        "Ad ops",
        "Wrapper chains"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "Validating trackers means confirming that the right URL is wired to the right playback event in the live VAST response, with valid syntax, HTTPS, sane macros, and no environment drift. Opening one pixel URL in a browser or running curl against it is not enough. That only tells you an endpoint responds.",
            "The public docs around VAST and VMAP make the control flow clear: the player or player SDK follows redirects, fetches VAST, chooses media, and responds with tracking events. That is why serious tracker QA starts from the live tag and the real wrapper chain, not from a vendor slide deck or a trafficker's spreadsheet."
          ]
        },
        {
          "type": "list",
          "heading": "What a clean tracker layer should prove before launch",
          "items": [
            "Every Impression, Tracking, ClickThrough, ClickTracking, and Error URI is syntactically valid and HTTPS-safe for the target environment.",
            "Event coverage matches the actual measurement plan: impression, start, quartiles, complete, click, and error where the buyer, seller, or verification workflow expects them.",
            "Macros are either supported by the serving stack or already resolved before the tag goes live.",
            "The trackers point at the right owner and environment, so staging domains, old campaign IDs, or mixed vendors are not hiding in the XML.",
            "Wrapper-added trackers are understood and expected, instead of being mistaken for accidental duplication.",
            "Error paths exist on wrappers, with [ERRORCODE] where appropriate, so failed chains leave evidence instead of silence."
          ]
        },
        {
          "type": "code",
          "heading": "A tracker block should be specific, not merely present",
          "language": "xml",
          "code": "<InLine>\n  <Impression><![CDATA[https://tracker.example.com/imp?cb=[CACHEBUSTING]]]></Impression>\n  <Error><![CDATA[https://tracker.example.com/error?code=[ERRORCODE]&cb=[CACHEBUSTING]]]></Error>\n  <Creatives>\n    <Creative>\n      <Linear>\n        <TrackingEvents>\n          <Tracking event=\"start\"><![CDATA[https://tracker.example.com/start?id=[ADID]]]></Tracking>\n          <Tracking event=\"firstQuartile\"><![CDATA[https://tracker.example.com/q1?id=[ADID]]]></Tracking>\n          <Tracking event=\"complete\"><![CDATA[https://tracker.example.com/complete?id=[ADID]]]></Tracking>\n        </TrackingEvents>\n        <VideoClicks>\n          <ClickThrough><![CDATA[https://brand.example.com/landing]]></ClickThrough>\n          <ClickTracking><![CDATA[https://tracker.example.com/click?id=[ADID]]]></ClickTracking>\n        </VideoClicks>\n      </Linear>\n    </Creative>\n  </Creatives>\n</InLine>"
        },
        {
          "type": "paragraphs",
          "heading": "Start with the live tag, not the sample XML",
          "paragraphs": [
            "This is where teams waste time. The XML attached to an email is rarely the exact response the player will see in production. Ad servers append macros, wrappers add their own Impression and Error URLs, and VMAP or SDK-driven flows request child VAST tags at playback time.",
            "If you validate only the sample inline snippet, you can miss the URLs that actually fire in market. The practical unit of review is the trafficked tag URL, the resolved XML, and the full wrapper chain that sits between them."
          ]
        },
        {
          "type": "list",
          "heading": "The checks that catch most tracker problems quickly",
          "items": [
            "Malformed URLs: missing protocol, illegal spaces, broken escaping, or query strings that will fail once the player tries to request them.",
            "HTTP drift: trackers or click destinations that still use HTTP in an HTTPS-only workflow.",
            "Unresolved or unsupported macros: placeholder tokens that the current ad server or SDK will not replace.",
            "Duplicate or contradictory events: two copies of the same vendor beacon for one event, or mixed staging and production endpoints for the same campaign.",
            "Missing wrapper error tracking: no Error URL means no useful evidence when a redirect chain fails or times out.",
            "Thin event coverage: tags that technically parse but omit events the reporting workflow depends on."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Wrapper chains change the tracker count",
          "paragraphs": [
            "Wrapper chains are where tracker validation stops being a simple checklist. Each wrapper can contribute its own Impression, Error, and TrackingEvents URLs. By the time the inline ad resolves, the player can be holding a stack of trackers from every hop plus the final creative.",
            "That means four impression URLs in a multi-hop chain may be correct, while two nearly identical start trackers from the same vendor may be sloppy trafficking. Validation is not about minimizing the number of pixels by default. It is about distinguishing expected accumulation from accidental noise."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Error tracking deserves first-class QA",
          "paragraphs": [
            "A lot of teams review impression and quartile trackers carefully, then treat Error as optional. That is backwards. When a wrapper chain breaks, the Error URL is often the only structured clue you get.",
            "If wrappers do not carry an Error URL with the [ERRORCODE] macro, chain failures become underdelivery with no audit trail. That is one of the cheapest fixes to catch before launch and one of the most expensive omissions to discover after launch."
          ]
        },
        {
          "type": "list",
          "heading": "A practical pre-launch workflow",
          "items": [
            "Paste the live tag URL into the tester first so you can review resolved tracking URLs, click paths, HTTP drift, and obvious macro issues in one place.",
            "Use the inspector on any wrapped response so you can see hop count, accumulated trackers, and which party added which beacon.",
            "Validate the resolved XML separately to catch malformed URIs, empty elements, and spec-level issues that get buried inside wrapper debugging.",
            "Run one player-specific check on the real receiving stack, because browser validation does not prove the same tracker behavior on CTV, mobile SDKs, or SSAI paths.",
            "Save the final tracker inventory with ownership notes so measurement disputes do not start with guesswork later."
          ]
        },
        {
          "type": "quote",
          "quote": "A tracker is valid when the right system fires the right URL for the right event in the right environment.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Validation is wiring QA, not proof of trust",
          "paragraphs": [
            "This is the line that keeps the article distinct from fraud conversations. Validating trackers tells you whether the measurement layer is wired coherently before launch. It does not by itself prove that the eventual impression was trustworthy.",
            "But that distinction is exactly why tracker validation matters. If the tracker layer is malformed, duplicated, or missing error instrumentation, every later conversation about pacing, discrepancies, or fraud starts from noisy evidence."
          ]
        },
        {
          "type": "resources",
          "heading": "Related guides on vastlint",
          "items": [
            {
              "label": "VAST tag testing",
              "href": "/docs/vast-tag-testing/",
              "description": "How to test a live VAST tag, inspect trackers, review click paths, and catch macro or HTTPS issues before trafficking.",
              "source": "Docs"
            },
            {
              "label": "Common VAST errors",
              "href": "/docs/common-vast-errors/",
              "description": "Reference for malformed Impression, Tracking, ClickThrough, and MediaFile URLs, along with other common schema mistakes.",
              "source": "Docs"
            },
            {
              "label": "VAST Wrapper Chains: How They Work, Limits & Debugging",
              "href": "/guides/vast-wrapper-chains/",
              "description": "Why wrappers accumulate trackers and why missing wrapper error URLs turn delivery failures into blind spots.",
              "source": "Guide"
            },
            {
              "label": "Validate VAST XML",
              "href": "/docs/validate-vast-xml/",
              "description": "A focused XML pass for resolved tags when you need the spec-level answer fast.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Official VAST standards overview and version history for the XML format that carries impression, tracking, click, and error metadata.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "VMAP for video ad insertion",
              "href": "https://support.google.com/admanager/answer/4539582",
              "description": "Google Ad Manager documentation describing how players request VAST ads, follow redirects, choose media, and respond with tracking events.",
              "source": "Google Ad Manager"
            },
            {
              "label": "Set up the IMA SDK",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/get-started",
              "description": "Google's player-side ad lifecycle guide, useful for understanding why runtime-specific tracker QA still matters after schema validation.",
              "source": "Google IMA"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Inspect the tracker chain before launch",
          "paragraph": "Start with the live URL, unwrap the wrappers, and review every impression, quartile, click, and error tracker before they become a reporting problem.",
          "href": "/inspect/",
          "label": "Inspect a live VAST URL"
        }
      ]
    },
    {
      "slug": "vpaid-is-deprecated-stop-treating-it-like-a-fallback",
      "title": "VPAID Is Deprecated. Stop Treating It Like a Fallback",
      "description": "IAB positions VPAID as deprecated and replaced by SIMID, while Google's own docs limit VPAID 2 JavaScript support to the IMA HTML5 SDK. In 2026, VPAID is a legacy compatibility mode, not a real fallback strategy for CTV, mobile, or SSAI.",
      "publishedAt": "2026-06-05",
      "updatedAt": "2026-06-05",
      "author": "Alex Sekowski",
      "readingTime": "8 min read",
      "heroKicker": "VPAID migration",
      "tags": [
        "VPAID",
        "SIMID",
        "CTV",
        "SSAI"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If a VAST tag still uses VPAID, treat it as a legacy web-HTML5 compatibility path, not as a neutral fallback you can safely carry into every runtime. The forward path is standard media for playback, SIMID for interactivity, and OMID for measurement.",
            "That is not just vastlint opinion. The IAB Tech Lab VAST standards page labels VPAID deprecated and replaced with SIMID, the SIMID standard page explains that SIMID and OMID are the focused replacements for VPAID's old combined role, and Google's IMA docs say the HTML5 SDK is the only IMA SDK that supports VPAID 2 JavaScript creatives."
          ]
        },
        {
          "type": "list",
          "heading": "What the public record says now",
          "items": [
            "IAB Tech Lab's VAST standards hub links VPAID as deprecated and replaced with SIMID.",
            "IAB Tech Lab's SIMID page says the industry is replacing VPAID with OMID for measurement and SIMID for interactivity.",
            "The same SIMID page positions SIMID as better aligned with mobile, SSAI, OTT devices, and live streaming, not just browser playback.",
            "Google's IMA HTML5 documentation says only the IMA HTML5 SDK supports VPAID 2 JavaScript creatives.",
            "Google's IMA SIMID documentation separately documents SIMID 1.1 support, which is a strong signal about where the runtime story is moving."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why fallback is the wrong mental model",
          "paragraphs": [
            "A fallback is supposed to broaden compatibility. VPAID does the opposite now. It depends on a browser-like JavaScript execution model, specific SDK behavior, and looser security assumptions than modern CTV, mobile, and SSAI stacks are willing to allow.",
            "That is why VPAID still creates false confidence. A tag can look fine in desktop HTML5 QA and still be the wrong package for the environments that actually matter to a campaign. If the real delivery path includes native mobile SDKs, CTV apps, or server-side stitching, VPAID is not a safety net. It is the risk."
          ]
        },
        {
          "type": "list",
          "heading": "Where VPAID fails first",
          "items": [
            "SSAI: there is no client-side JavaScript runtime at insertion time, so the interactive layer cannot execute the way VPAID expects.",
            "CTV and OTT: native TV players do not expose the browser DOM and shared player context VPAID was built around.",
            "Mobile SDKs: Google's public docs say the IMA HTML5 SDK is the only IMA SDK platform that supports VPAID 2 JavaScript creatives.",
            "Security-sensitive web players: even where VPAID still runs, Google's docs emphasize secure iframe handling, proxy video elements, and compatibility caveats."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Even Google treats VPAID like a narrow compatibility mode",
          "paragraphs": [
            "Google's IMA HTML5 guide does not read like a broad endorsement of VPAID as the future. It reads like a compatibility document. You must explicitly set VPAID mode, the SDK documents security differences between secure and insecure iframe behavior, and it warns creative authors about proxy-element constraints.",
            "At the same time, Google publishes a separate SIMID support guide that documents the SIMID messages IMA HTML5 does and does not support. That is the more useful signal. The ecosystem is not expanding VPAID's footprint. It is documenting how newer secure interaction models behave in real runtimes."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What the replacement stack looks like in practice",
          "paragraphs": [
            "The modern split is simpler than the VPAID era. Keep playback in a normal MediaFile. Put interactive behavior in a SIMID InteractiveCreativeFile. Put verification in AdVerifications with OMID-compatible resources. That separation gives the player control over media, keeps the interactive code sandboxed, and works much better with SSAI, CTV, and stricter platform security.",
            "IAB's SIMID page makes the design goal explicit: separate the interactive layer from the media asset so publishers keep control of the stream and can support use cases like SSAI and live streaming without handing the whole runtime to ad code."
          ]
        },
        {
          "type": "code",
          "heading": "A healthier replacement pattern",
          "language": "xml",
          "code": "<MediaFiles>\n  <MediaFile delivery=\"progressive\" type=\"video/mp4\" width=\"1280\" height=\"720\">\n    <![CDATA[https://cdn.example.com/ads/preroll.mp4]]>\n  </MediaFile>\n  <InteractiveCreativeFile type=\"text/html\" apiFramework=\"SIMID\">\n    <![CDATA[https://cdn.example.com/ads/interactive-layer.html]]>\n  </InteractiveCreativeFile>\n</MediaFiles>\n<AdVerifications>\n  <Verification vendor=\"measurement.example\">\n    <JavaScriptResource apiFramework=\"omid\" browserOptional=\"true\">\n      <![CDATA[https://measurement.example/omid.js]]>\n    </JavaScriptResource>\n  </Verification>\n</AdVerifications>"
        },
        {
          "type": "list",
          "heading": "A pragmatic policy for teams still receiving VPAID tags",
          "items": [
            "Treat VPAID as an explicit legacy exception, not as the default fallback layer in new trafficking.",
            "If a partner insists on VPAID, document the exact runtime where it is still expected to work, usually desktop HTML5, and do not silently assume mobile, CTV, or SSAI compatibility.",
            "Require a standard playback MediaFile alongside any interactive layer so the campaign is not entirely dependent on executable ad code.",
            "Validate for apiFramework=\"VPAID\", missing MP4 fallback, and missing SIMID or OMID replacements before launch approval.",
            "Run runtime-specific QA after standards validation, because a tag that is structurally clean can still fail inside a particular SDK."
          ]
        },
        {
          "type": "quote",
          "quote": "In 2026, VPAID is not a fallback strategy. It is a legacy compatibility exception.",
          "attribution": "vastlint field note"
        },
        {
          "type": "resources",
          "heading": "Sources and further reading",
          "items": [
            {
              "label": "IAB Tech Lab VAST standards hub",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "Official VAST standards overview, version history, and supporting resources. Links VPAID as deprecated and replaced with SIMID.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "IAB Tech Lab SIMID standard",
              "href": "https://iabtechlab.com/standards/simid/",
              "description": "Official SIMID overview explaining the SIMID and OMID split and the focus on mobile, SSAI, OTT, and live streaming.",
              "source": "IAB Tech Lab"
            },
            {
              "label": "Google IMA HTML5: Enable VPAID 2 JavaScript creatives",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/vpaid2js",
              "description": "Google's current VPAID support guide, including the note that only the IMA HTML5 SDK supports VPAID 2 JavaScript creatives.",
              "source": "Google IMA"
            },
            {
              "label": "Google IMA HTML5: Review SIMID support",
              "href": "https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/simid-support",
              "description": "Google's SIMID support guide for IMA HTML5, including supported and unsupported messages.",
              "source": "Google IMA"
            },
            {
              "label": "VPAID deprecated migration guide",
              "href": "/guides/vast-vpaid-migration/",
              "description": "vastlint's migration checklist for replacing VPAID with SIMID, OMID, and standard playback files.",
              "source": "Guide"
            },
            {
              "label": "SIMID explained",
              "href": "/docs/simid/",
              "description": "Reference on SIMID, InteractiveCreativeFile, sandboxing, and the SIMID versus VPAID model.",
              "source": "Docs"
            },
            {
              "label": "VPAID deprecated explainer",
              "href": "/docs/vpaid/",
              "description": "Reference on how VPAID appears in VAST tags, why it is deprecated, and what replaces it.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Check whether a live tag still depends on VPAID",
          "paragraph": "Start with the live URL or resolved XML and catch deprecated VPAID patterns before the campaign hits mobile, CTV, or SSAI traffic.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "mcp-preflight-for-ad-ops-teams",
      "title": "Why Ad Ops Teams Should Preflight VAST with MCP Before Launch",
      "description": "If AI agents are touching campaign setup, creative QA, or partner approvals, they need a deterministic VAST gate. MCP is useful here because it turns validation into a repeatable machine step instead of another manual checklist.",
      "publishedAt": "2026-05-02",
      "updatedAt": "2026-05-11",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Agentic ad ops",
      "tags": [
        "MCP",
        "Ad ops",
        "Automation",
        "Preflight QA"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Manual QA does not scale with agentic workflows",
          "paragraphs": [
            "The moment a team starts using AI for campaign setup, tag review, or launch prep, the old human-only QA path becomes a bottleneck. You need one deterministic place where the system can ask: does this tag pass spec validation, does this URL unwrap correctly, and what issues need to be fixed before delivery?",
            "That is exactly the job a focused MCP tool should do.",
            "The broader MCP ecosystem describes the protocol as an open standard for connecting AI applications to external systems and tools. In ad operations, that matters because VAST validation should be a reliable tool call in the workflow, not a browser tab someone remembers to open when launch pressure is high."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why MCP fits preflight better than ad hoc scripts",
          "paragraphs": [
            "One-off scripts are easy to start and hard to operationalize. They tend to return inconsistent formats, hide assumptions in code that only one person understands, and break the moment the workflow moves from a local machine into a shared agentic environment.",
            "An MCP surface makes the validation step explicit. The tool name, input shape, rule identifiers, and output structure become part of the operating model. That is what lets multiple agents, operators, or automation layers use the same gate with predictable behavior."
          ]
        },
        {
          "type": "list",
          "heading": "What a useful preflight step returns",
          "items": [
            "A pass or fail result that can gate the workflow automatically.",
            "Structured rule IDs and locations so an agent or operator knows what to repair.",
            "Wrapper-chain inspection for third-party URLs, not just raw XML blobs.",
            "Optional auto-fix for deterministic cleanup before a human reviews the final payload.",
            "A consistent summary that can be written into tickets, approval records, or campaign metadata.",
            "Enough detail to separate spec violations from platform-fit issues such as wrapper depth or deprecated creative types."
          ]
        },
        {
          "type": "code",
          "heading": "The shape of the check is simple",
          "language": "json",
          "code": "{\n  \"tool\": \"validate_vast_url\",\n  \"input\": {\n    \"url\": \"https://ads.example.com/vast?placement=pre-roll\",\n    \"max_depth\": 4\n  }\n}"
        },
        {
          "type": "paragraphs",
          "heading": "Where to place the gate in your workflow",
          "paragraphs": [
            "The most useful place to run this check is before the tag reaches trafficking and again before launch approval. The first pass catches bad partner payloads early. The second pass confirms that the live line item still resolves the way your team thinks it does.",
            "Once VAST QA becomes a tool call instead of an ad hoc browser habit, launch quality gets easier to measure. Every agent, trader, or ops analyst is working against the same rule set and the same response format."
          ]
        },
        {
          "type": "list",
          "heading": "A pragmatic rollout plan",
          "items": [
            "Start with validation and wrapper inspection as a non-blocking advisory step.",
            "Promote obvious hard failures to blocking conditions once the team trusts the output.",
            "Write rule IDs and summaries into launch tickets so partner remediation is faster.",
            "Keep safe auto-fix limited to deterministic cleanup rather than opinionated rewriting.",
            "Use the same MCP surface in human workflows and agent workflows so QA drift does not appear between them."
          ]
        },
        {
          "type": "resources",
          "heading": "Related docs on vastlint",
          "items": [
            {
              "label": "MCP docs",
              "href": "/docs/mcp/",
              "description": "How the hosted MCP surface exposes VAST validation, rule catalog, wrapper inspection, and safe auto-fix.",
              "source": "Docs"
            },
            {
              "label": "AdCP docs",
              "href": "/docs/adcp/",
              "description": "Governance and protocol context for integrating validation into ad-creative workflows.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML",
              "href": "/docs/validate-vast-xml/",
              "description": "The core validator behavior and how teams can use it as a first gate before workflow automation.",
              "source": "Docs"
            },
            {
              "label": "Agentic docs",
              "href": "/docs/agentic/",
              "description": "Background on where agentic workflows fit into the broader vastlint operating model.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "resources",
          "heading": "Authoritative references",
          "items": [
            {
              "label": "What is the Model Context Protocol (MCP)?",
              "href": "https://modelcontextprotocol.io/introduction",
              "description": "The official introduction to MCP and why standardized tool access matters for AI applications.",
              "source": "Model Context Protocol"
            },
            {
              "label": "Digital Video Ad Serving Template (VAST)",
              "href": "https://iabtechlab.com/standards/vast/",
              "description": "The canonical VAST spec overview that your preflight step should ultimately be checking against.",
              "source": "IAB Tech Lab"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "See the MCP surface",
          "paragraph": "The hosted MCP endpoint exposes validation, wrapper inspection, rule listing, and safe auto-fix so preflight can become a standard part of campaign automation.",
          "href": "/docs/mcp/",
          "label": "View MCP docs"
        }
      ]
    },
    {
      "slug": "vastlint-vs-adplayer-pro-vast-inspector",
      "title": "vastlint vs AdPlayer.Pro VAST Inspector",
      "description": "vastlint validates VAST XML against a public, standards-derived rule set with wrapper unwrapping, creative parsing, and CI-friendly output. AdPlayer.Pro's VAST Inspector is a browser preview tool built to show whether a tag plays in their player, not whether it complies with the spec. Here is where each fits.",
      "publishedAt": "2026-07-03",
      "updatedAt": "2026-07-03",
      "author": "Alex Sekowski",
      "readingTime": "7 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "AdPlayer.Pro",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "If the job is to check whether a VAST document complies with the IAB specification, resolve a wrapper chain, and get rule-level diagnostics you can act on, vastlint is the tool for that job. It validates against a public, standards-derived rule set, unwraps redirects, parses creatives and tracking, and produces output that works the same in a browser, a CI pipeline, or an MCP-connected agent.",
            "AdPlayer.Pro's VAST Inspector answers a narrower question: does this tag play in AdPlayer.Pro's own video player. It accepts a VAST, VPAID, Google IMA, or Freewheel tag, runs it through their player, and shows a live preview plus a raw event log. That is useful as a playback smoke test, but it is not a spec compliance check.",
            "The two tools are not really competing on the same axis. vastlint tells you if the tag is correct. AdPlayer.Pro's inspector tells you if the tag plays in their player. Teams that only run the second check are trusting the player to surface problems that are actually XML-level."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use vastlint if you need to know whether the VAST XML itself complies with the spec, not just whether it happens to play.",
            "Use vastlint if you need wrapper-chain resolution with visibility into every hop, not just the final playable result.",
            "Use vastlint if you want rule-level output you can paste into a bug report, a PR check, or an agent workflow.",
            "Use AdPlayer.Pro's inspector if you specifically want to see the tag rendered inside their player as a playback sanity check.",
            "Use AdPlayer.Pro's inspector if you're evaluating AdPlayer.Pro itself as a player or ad server vendor.",
            "Use both if you want a structural validation pass and a separate player-rendering pass, in that order."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why vastlint is the stronger starting point",
          "paragraphs": [
            "vastlint is built around the question every ad-ops or engineering team eventually has to answer: does this tag comply with the spec, and if not, exactly which rule does it break and how do you fix it. That means validating the XML against rules derived from the published IAB VAST XSD schemas and normative prose, across VAST 2.0 through 4.3, and surfacing findings with fix guidance rather than a pass/fail player result.",
            "It also separates the concerns that a preview-only tool collapses into one step: test a live tag URL, inspect each wrapper hop on its own, and validate the resolved XML independently. That separation matters because a tag can play successfully in a permissive player while still violating the spec in ways that break stricter players, SSAI stitchers, or downstream measurement.",
            "That's the practical split. vastlint is stronger on spec compliance, wrapper visibility, and reusable output. AdPlayer.Pro's inspector is stronger as a quick playback check inside one specific player."
          ]
        },
        {
          "type": "list",
          "heading": "The gaps vastlint closes",
          "items": [
            "Rule-level validation against a public, standards-derived methodology, not a player-passes-or-it-doesn't result.",
            "Wrapper-chain inspection that shows every hop, not just the final resolved ad.",
            "Coverage through VAST 4.3, including the parts of the spec no published IAB XSD covers directly.",
            "Output built for reuse: CLI, CI checks, npm packages, and MCP tools, not just a browser session.",
            "A validation surface that isn't anchored to any single player's playback behavior."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What AdPlayer.Pro's inspector is actually built for",
          "paragraphs": [
            "AdPlayer.Pro's public VAST Inspector page frames itself around testing \"your VAST, VPAID or Google IMA video ad tag\" or checking AdPlayer.Pro's own player against sample VAST and VMAP tags, with Freewheel also mentioned in the page's metadata. The workflow is a client selector (VAST or Google IMA), a choice between a sample tag or a pasted custom tag, a Test Ad button, an embedded player, and an event log.",
            "There is no visible rule catalog, no spec version claims, no wrapper-hop breakdown, and no XML diagnostics on the page itself. It is, functionally, a demo surface for AdPlayer.Pro's own video player and ad server product, not a standards-validation tool. That framing is consistent with the rest of the site, which is a commercial video ad server and white-label platform with the inspector as one of several lead-generation pages alongside a stream tester.",
            "That's a reasonable thing for a player vendor to build. It answers \"will this tag work in our player,\" which matters if you're evaluating AdPlayer.Pro specifically. It doesn't answer \"is this tag spec-compliant,\" which is a different, and for most ad-ops workflows, prior, question."
          ]
        },
        {
          "type": "list",
          "heading": "What AdPlayer.Pro's inspector is useful for",
          "items": [
            "A quick check that a tag renders and plays inside AdPlayer.Pro's own player.",
            "A side-by-side look at VAST, VPAID, and Google IMA sample tags if you're evaluating their player.",
            "A raw event log for the specific playback session, useful for debugging that player's own event firing.",
            "Sample VAST and VMAP tags if you just need something to click through quickly."
          ]
        },
        {
          "type": "quote",
          "quote": "A tag that plays isn't the same as a tag that's correct. AdPlayer.Pro checks the first. vastlint checks the second.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Use them in this order",
          "paragraphs": [
            "Starting from a player preview makes it easy to conflate two different failure modes: an XML-level spec violation and a player-specific playback quirk. If a tag fails in AdPlayer.Pro's inspector, you don't yet know whether the XML is wrong or the player is just stricter or more permissive than whatever will run it in production.",
            "The cleaner sequence is to validate the XML in vastlint first, resolve the wrapper chain, and confirm the tag is spec-compliant before ever loading it into a specific player's preview. If you still want a playback sanity check afterward, whether in AdPlayer.Pro's inspector or your own production player, you're now testing player behavior against a tag you already know is correct.",
            "That order keeps the two questions separate, which is the whole point: spec compliance is a property of the XML, and playback behavior is a property of the player."
          ]
        },
        {
          "type": "code",
          "heading": "Recommended workflow when AdPlayer.Pro's inspector is part of QA",
          "language": "bash",
          "code": "# 1. Validate the VAST XML (or live tag URL) in vastlint against the public rule set\n# 2. Inspect the wrapper chain hop by hop in vastlint\n# 3. Fix any spec violations vastlint surfaces\n# 4. Only then load the tag into AdPlayer.Pro's inspector (or your production player) as a playback check\n# 5. Treat player-specific playback issues as separate from XML-level spec issues"
        },
        {
          "type": "list",
          "heading": "When vastlint is the better first choice",
          "items": [
            "You need to know if the tag is spec-compliant, not just whether one specific player can render it.",
            "You need wrapper-chain visibility instead of a single collapsed playback result.",
            "You need output that plugs into CI, a CLI, or an agent workflow instead of a manual browser session.",
            "You need a validation surface that isn't tied to any one vendor's player.",
            "You want to separate XML correctness from playback behavior before you start debugging either one."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When AdPlayer.Pro's inspector still earns a spot",
          "paragraphs": [
            "AdPlayer.Pro's inspector is worth using when you're specifically evaluating AdPlayer.Pro's player or ad server, or when you want one more concrete playback pass after the tag has already cleared spec validation. It is not a substitute for that validation step. It doesn't claim to check the tag against the IAB VAST specification, and it doesn't surface rule-level diagnostics.",
            "That's the fair comparison. AdPlayer.Pro built a demo tool for their own player. vastlint built a validator for the spec. Use the second one first."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "AdPlayer.Pro VAST Inspector",
              "href": "https://adplayer.pro/developer/vast_inspector",
              "description": "AdPlayer.Pro's public VAST/VPAID/Google IMA tag tester page, built around their own player preview and event log.",
              "source": "AdPlayer.Pro"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How vastlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/docs/validate-vast-xml/",
              "description": "How to choose between validating resolved XML and testing a live tag URL.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the spec before you trust the player",
          "paragraph": "Resolve the wrapper chain and validate the XML against the public rule set before loading the tag into any single player's preview. That keeps XML correctness and playback behavior as separate, debuggable problems.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    },
    {
      "slug": "vastlint-vs-test-a-tag",
      "title": "Test a Tag vs vastlint: VAST Tester Alternative",
      "description": "Paste the live URL at vastlint.org/tester/. Test a Tag is a free preview for HTML, MRAID, VAST, and VMAP. It does not validate against the spec. vastlint checks XML against public IAB rules and inspects wrapper hops.",
      "publishedAt": "2026-07-03",
      "updatedAt": "2026-08-29",
      "author": "Alex Sekowski",
      "readingTime": "6 min read",
      "heroKicker": "Tool comparison",
      "tags": [
        "Test A Tag",
        "VAST validator",
        "VAST tester",
        "Ad ops"
      ],
      "published": true,
      "body": [
        {
          "type": "paragraphs",
          "heading": "Short answer",
          "paragraphs": [
            "Paste the live VAST URL at https://vastlint.org/tester/. Free, no signup: fetch, preview, tracking. Test A Tag is a small, free, no-signup utility for HTML, MRAID, VAST, VAST URI, VMAP, or VMAP URI preview in an isolated frame. It does not validate against the IAB spec. Wrapper hops are https://vastlint.org/inspect/.",
            "vastlint answers a different question. It checks whether the VAST XML itself complies with the IAB specification, rule by rule, across VAST 2.0 through 4.3, and it can walk a wrapper chain hop by hop instead of only showing the final rendered result. Test A Tag has no rule engine, no error or warning output, and no wrapper-chain view.",
            "They're not really substitutes. Test A Tag is a fast, disposable preview and sharing tool. vastlint is a compliance checker. A tag can render fine in Test A Tag's preview frame and still violate the spec in ways that only show up against a stricter player or an SSAI stitcher downstream."
          ]
        },
        {
          "type": "list",
          "heading": "The fastest way to choose between them",
          "items": [
            "Use vastlint if you need to know whether the VAST XML complies with the spec, not just whether it renders.",
            "Use vastlint if you need to see every wrapper hop on its own, not just the final resolved creative.",
            "Use vastlint if you want rule IDs and fix guidance you can paste into a ticket or a PR check.",
            "Use Test A Tag if you just want to paste something (HTML, MRAID, VAST, or VMAP) and see it render, no signup, no setup.",
            "Use Test A Tag if you want to stash a handful of tags locally or send a colleague a pre-loaded link.",
            "Use both if the tag matters: validate the XML in vastlint first, then use Test A Tag for a quick throwaway render or to hand a link to someone else."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "Why vastlint is the stronger starting point",
          "paragraphs": [
            "vastlint starts from the spec, not the player. It validates VAST XML against rules derived from the published IAB VAST XSD schemas and normative prose, across VAST 2.0 through 4.3, and reports findings with a rule ID, severity, and fix guidance rather than a render-or-doesn't-render result.",
            "It also separates concerns that a single preview box collapses together: test a live tag URL, inspect each wrapper hop independently, and validate the resolved XML on its own. A tag can look fine in an isolated preview frame while still being structurally invalid in ways that break a stricter SDK, an SSAI stitcher, or downstream reporting.",
            "That's the practical split. vastlint is stronger on spec compliance, wrapper visibility, and output you can act on. Test A Tag is stronger as a zero-friction way to eyeball a creative."
          ]
        },
        {
          "type": "list",
          "heading": "The gaps vastlint closes",
          "items": [
            "Rule-level validation against a public, standards-derived methodology, not just a render-or-doesn't render result.",
            "Wrapper-chain inspection showing every hop, not a single collapsed preview.",
            "Coverage through VAST 4.3, with a documented approach for the parts no published IAB XSD covers directly.",
            "Findings with a rule ID, severity, and fix guidance instead of no error reporting at all.",
            "Output built for reuse: CLI, CI checks, npm packages, and an MCP server, not only a browser tab."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "What Test A Tag is actually built for",
          "paragraphs": [
            "Test A Tag's own description is direct about its scope: a service \"designed to preview creatives and ad tags directly on various browsers,\" supporting HTML5, MRAID, and video tags (VAST and VMAP), relying on Google's IMA SDK for video. It's framed explicitly as a convenience tool built to make previewing creatives \"a little easier for the already overworked adops professional,\" not as a validator.",
            "The interface is a single textarea that auto-detects whatever you paste, a preview tab with a reload button (useful for tags with frequency caps that need a fresh ad call), and a Stash tab. The Stash is plain browser localStorage, capped at 20 entries, device-specific, and gone if the browser data is cleared. The Share button encodes the pasted creative into a URL so someone else's session opens with it pre-loaded.",
            "There's no signup, no support, and by its own disclaimer, no warranty: it's a free side tool, not a supported product. That also means there's nothing to validate against; it's rendering what you gave it, not checking it against anything."
          ]
        },
        {
          "type": "list",
          "heading": "What Test A Tag is useful for",
          "items": [
            "A zero-setup way to paste a creative or tag and see it render, with automatic format detection across HTML, MRAID, VAST, and VMAP.",
            "Reloading a tag quickly to test frequency-capped or fresh-ad-call behavior.",
            "Keeping a short local list of frequently used test tags without an account.",
            "Sending a colleague a link that opens with the exact same creative pre-loaded, without them needing to paste anything."
          ]
        },
        {
          "type": "quote",
          "quote": "Test A Tag tells you it rendered. vastlint tells you why it did, or why it shouldn't have.",
          "attribution": "vastlint field note"
        },
        {
          "type": "paragraphs",
          "heading": "Use them in this order",
          "paragraphs": [
            "If the first thing you do with a new tag is paste it into a preview frame, a passing render can quietly stand in for a compliance check it never performed. That's fine for a disposable creative you're eyeballing once, but it's a bad habit for anything going into a live campaign, an SSAI break, or a partner integration.",
            "The cleaner order is to validate the VAST XML in vastlint first, resolve any wrapper chain hop by hop, and fix whatever the rule engine flags. Once the tag is known to be spec-compliant, Test A Tag is a fine place to do a quick visual pass or hand a colleague a working link.",
            "That ordering keeps \"is this XML correct\" and \"does this render for me right now\" as separate questions, which is the point: one is a property of the document, the other is a property of a specific preview session."
          ]
        },
        {
          "type": "code",
          "heading": "Recommended workflow when Test A Tag is part of QA",
          "language": "bash",
          "code": "# 1. Validate the VAST XML (or live tag URL) in vastlint against the public rule set\n# 2. Inspect the wrapper chain hop by hop in vastlint\n# 3. Fix any spec violations vastlint surfaces\n# 4. Paste the tag into Test A Tag for a quick visual render, or share a pre-loaded link with a colleague\n# 5. Treat a passing Test A Tag preview as a render check, not a compliance check"
        },
        {
          "type": "list",
          "heading": "When vastlint is the better first choice",
          "items": [
            "You need to know if the tag is spec-compliant, not just whether it renders in one preview frame.",
            "You need wrapper-chain visibility instead of a single collapsed preview result.",
            "You need rule IDs, severity, and fix guidance you can act on or paste into a ticket.",
            "You need output that plugs into CI, a CLI, or an agent workflow instead of a manual browser tab.",
            "The tag is going into a real campaign, not just being eyeballed once."
          ]
        },
        {
          "type": "paragraphs",
          "heading": "When Test A Tag still earns a spot",
          "paragraphs": [
            "Test A Tag is genuinely useful when you want the lowest-friction way to glance at a creative, reload it a few times, or send someone a working link without asking them to paste anything. Its own scope is narrow by design: preview, stash, share. It doesn't claim to check anything against the IAB VAST specification, and it has no error or warning output to speak of.",
            "That's the fair comparison. Test A Tag built a fast preview tool. vastlint built a validator for the spec. Use the second one first, and keep the first one around for the quick look afterward."
          ]
        },
        {
          "type": "resources",
          "heading": "Sources and related docs",
          "items": [
            {
              "label": "Test A Tag",
              "href": "https://test-a-tag.com",
              "description": "Test A Tag's public preview tool for HTML, MRAID, VAST, and VMAP creatives and tags.",
              "source": "Test A Tag"
            },
            {
              "label": "Rule derivation methodology",
              "href": "/docs/methodology/",
              "description": "How vastlint derives rules from IAB XSD schemas, normative prose, and related standards.",
              "source": "Docs"
            },
            {
              "label": "Validate VAST XML online",
              "href": "/docs/validate-vast-xml/",
              "description": "How to choose between validating resolved XML and testing a live tag URL.",
              "source": "Docs"
            }
          ]
        },
        {
          "type": "cta",
          "heading": "Validate the spec before you trust the render",
          "paragraph": "Resolve the wrapper chain and validate the XML against the public rule set before treating any preview render as a pass. That keeps spec compliance and visual QA as separate, debuggable steps.",
          "href": "/tester/",
          "label": "Test a live VAST tag URL"
        }
      ]
    }
  ]
}
