DEV Community

Aleksander Sekowski
Aleksander Sekowski

Posted on

A Companion With No Width Is Not a 300x250. The Player Cannot Match It.

A publisher page exposes a 300x250 slot. The VAST player walks <Companion> elements and keeps the first whose width and height match that slot. A Companion with a JPEG and no dimensions is not a 300x250. It is a banner the player cannot name.

Trafficking often pastes <StaticResource> and skips the attributes. The video plays. The slot stays empty. If CompanionAds is required="all", some players also drop the linear.

That is not a CDN miss. The image URL can 200. The match never ran.

Width and height are how the slot matches

VAST requires width and height on every <Companion>. The spec does not default them from the image file. The player is not required to HEAD the JPEG to learn 300 by 250. If the attributes are missing, the match set is empty.

IAB display still clusters on a small set of sizes. 300x250 is the default mid-page rectangle. 728x90 is the desktop leaderboard. 160x600 is the wide skyscraper. 320x50 is the mobile banner. One size is not enough if you traffic both desktop and mobile.

A copyable block that a player can actually match:

<CompanionAds required="none">
  <Companion width="300" height="250">
    <StaticResource creativeType="image/jpeg">
      <![CDATA[https://cdn.example.com/300x250.jpg]]>
    </StaticResource>
  </Companion>
  <Companion width="728" height="90">
    <StaticResource creativeType="image/jpeg">
      <![CDATA[https://cdn.example.com/728x90.jpg]]>
    </StaticResource>
  </Companion>
</CompanionAds>
Enter fullscreen mode Exit fullscreen mode

The broken form looks present in a text editor:

<CompanionAds required="all">
  <Companion>
    <StaticResource creativeType="image/jpeg">
      <![CDATA[https://cdn.example.com/banner.jpg]]>
    </StaticResource>
  </Companion>
</CompanionAds>
Enter fullscreen mode Exit fullscreen mode

There is a resource. There is no size. There is no slot.

I maintain vastlint, an open source VAST linter. On that second snippet it reports VAST-2.0-companion-dimensions. Severity is warning, because the XSD leaves the attributes optional while the prose requires them. The player still has nothing to match.

$ vastlint check companion.xml
companion.xml  VAST 4.2
  warning  Companion is missing width or height. Required by spec, optional in XSD.
           VAST-2.0-companion-dimensions
Enter fullscreen mode Exit fullscreen mode

--fail-on-warning is how you make that a launch gate.

The size list, and why one rendition is not enough, is on VAST companion sizes. The XML checklist is How to Validate Companion Ads.

required=all is a kill switch for the linear

required on <CompanionAds> is all, any, or none.

none keeps the video if the banner misses. any wants at least one companion to render. all means every companion in the block has to be usable, and a miss can take down the break.

An empty Companion plus required="all" is how a missing banner becomes a missing ad. That is the failure mode on companion ads not showing.

Most CTV runtimes ignore companions. Do not set required="all" for a CTV-only tag unless the platform documents companion support.

Wrappers can drop the banner you QA'd

CompanionAds on the inline you pasted is not proof the player received it. A wrapper hop can omit companions. followCompanions on a Wrapper is the flag that says whether to keep them. If the live chain drops the block, the page slot stays blank and your fixture still looks fine. QA the document at the bottom of the chain, not the first URL in the ticket.

Paste checks the document you have. A live tag URL still has to unwrap. Use the VAST tester for the fetch and preview. Use the inspector when the player printed 303 or the banner vanished after a hop.

The OpenRTB side can be clean the whole time. imp.video and bid.adm can pass a bid-stream linter while the VAST inside is a wrapper that returns no ads, or a companion with no width. That split is A spec-valid video bid can still fill with empty VAST.

CompanionClickThrough is a click tracker

The banner has its own click URL. It should 302 until the landing page. It should not be the Impression pixel with a different cache buster. If you are debugging the collector rather than the XML, impression pixels vs click trackers is the slot contract.

What to run

  1. Paste resolved XML. Catch missing width/height and empty Companion before you blame the page.
  2. Fetch the live URL in the tester. Confirm the companions that survived the chain.
  3. If a hop ate them, walk the chain in the inspector.
  4. Ship more than one IAB size. Then look at the page slot. Size mismatch after valid XML is trafficking, not schema.

Top comments (0)