Why Serving Video Ads for SSAI Is Harder Than It Looks
Server-side ad insertion (SSAI) has become the default way to deliver ads in streaming TV. Instead of the player pausing the show, fetching an ad and switching to it, a server stitches the ad directly into the video stream. The viewer gets one continuous stream, ad blockers have nothing to block, and devices that could never run an ad player still show ads.
From the outside, it looks simple: the ad server returns a VAST file, and the ad appears in the stream. In practice, a lot has to go right between those two steps, and most of it lands on the ad-stitching server. If you produce, traffic or serve video ads, understanding that work is the difference between an ad that plays and an ad that silently never runs.
A VAST file is a recipe, not a video
VAST, the IAB Tech Lab standard for video ad responses, does not contain the ad itself. It contains links to media files, plus tracking URLs, identifiers and instructions. For a client-side player, that is enough: pick a media file that suits the device and play it.
A stitching server cannot do that. It is not choosing a file to hand to a player; it is splicing the ad into a stream that is already encoded a certain way. The ad has to match that stream.
The stream sets the rules
A streaming show is encoded as a ladder of renditions: the same video at several resolutions and bitrates, cut into short segments, so the player can switch quality as bandwidth changes. To splice an ad into that stream cleanly, the ad needs a matching rendition for every rung of the ladder, with compatible codecs, frame rates and audio settings, cut into segments that line up with the content.
The ready-to-serve MP4 files in a typical VAST response were never made for that. They are built for players to download and play directly, at whatever resolution and bitrate the agency chose. When the ad's encoding does not match the content's, devices can stall, show black frames or glitch the audio at the transition between show and ad.
So the stitching server transcodes the ad into its own formats. To do that well, it needs a good source.
Enter the mezzanine file
VAST 4 added a dedicated element for this: <Mezzanine>, a link to the raw, high-quality master file of the ad. The specification is explicit about its role:
- A mezzanine file is required in ad-stitched executions. A stitching server may reject a VAST response that does not include one (VAST error 406), or one that does not meet the required specification (error 411).
- It is a source for transcoding, and should never be used for direct playback.
- It goes alongside, not instead of, the ready-to-serve files: VAST 4 asks for three ready-to-serve renditions (high, medium and low quality) for players that play files directly.
Transcoding from a high-quality master, rather than from an already-compressed delivery file, avoids stacking one generation of compression artifacts on top of another. That matters on a living-room TV.
The first impression is usually lost
Transcoding takes time, far longer than a stitching server can wait during an ad break. The VAST 4 specification describes what happens when a stitching server sees a creative for the first time:
- The server receives a VAST response and looks up the creative's unique identifier.
- If it has never seen that creative, it downloads the mezzanine file and starts transcoding.
- The ad is skipped and the next available ad plays instead. The server reports VAST error 407: the mezzanine is being downloaded and transcoded, which the specification notes "may take several hours."
- On later requests, the server recognizes the identifier and stitches in the transcoded version it already has.
That is why the unique creative identifier matters so much. In VAST 4 it lives in <UniversalAdId>, which is required for linear ads, and stitching services use it to manage their cache of transcoded files. The specification adds a rule that is easy to miss: if a creative changes in any way, it should get a new identifier. Reuse an old ID for a new cut of the ad and a stitcher may keep serving the old version. Give the same ad a new ID with every campaign and it goes through the skipped-while-transcoding cycle again.
Timing, wrappers and live breaks
Ad responses often arrive through a chain of wrappers: one server's VAST response points to another server, which points to another, before the real ad (the "InLine" response) appears. A stitching server has to follow that chain, the same way a client-side player would, inside a tight time budget, because the break is coming whether the ads are ready or not.
Live streams add another twist. In a live sports broadcast, every viewer reaches the ad break at the same moment, so the stitching server has to make a large burst of ad requests at once, resolve them and assemble a personalized stream for each viewer, all before the break starts. Ads that arrive too late, or whose durations do not fit the break, are dropped or replaced with filler.
Tracking from a server
In client-side ad serving, the player fires the impression and quartile tracking URLs itself. With SSAI, the player may not know an ad is playing at all, so the stitching server often fires tracking on the viewer's behalf. To the ad server, that looks like a huge number of impressions all coming from one machine, which is exactly what invalid traffic looks like.
VAST 4 addresses this with HTTP headers that describe the real viewer rather than the server. Stitching providers must send X-Device-IP and X-Device-User-Agent with their tracking requests, should pass along details like the viewer's language when available, and may still send the older X-Forwarded-For header, which is now deprecated.
There is a further catch: IAB measurement guidelines, developed with the Media Rating Council, favor counting impressions based on events from the viewer's device rather than on what a server sent. The specification itself notes that once an ad is stitched into the stream, the stitching service "may have little or no control over ad play," and that impressions should be counted by the player whenever possible.
Interactivity has to be designed for it
Stitching sends pixels, not code. An ad format that needs to run its own code in the player cannot ride along inside the video stream. That ruled out VPAID, the older interactive standard, entirely: VPAID ads control their own video, and with SSAI there is no separate ad video to control.
VAST 4 handles this by keeping interactive components in their own element, separate from the media files, so a stitcher can use the video while the player handles the interactive layer. That is the model behind SIMID, which we covered in What Is SIMID?: the player keeps control of the stream, and the interactive layer runs alongside it. Where a device cannot run an interactive layer at all, a QR code on screen can hand the experience to the viewer's phone.
A checklist for SSAI-ready video ads
If your ads run on streaming TV, a few habits prevent most SSAI failures:
- Always include a mezzanine file that meets the IAB Digital Video Ad Format Guidelines, plus three ready-to-serve renditions.
- Set a stable
<UniversalAdId>, and give a new ID to every changed version of the creative, and only to changed versions. - Traffic creatives early. The first request for a new creative will usually be skipped while it is transcoded, so get it into stitching systems before the campaign needs it to deliver.
- Deliver exact durations. A spot that is a fraction of a second over its slot can be cut or rejected.
- Keep wrapper chains short, so stitching servers can resolve your ad in time.
- Plan interactivity around the player, using SIMID or on-screen QR codes rather than formats that need to control the video.
SSAI has made streaming ads smoother for viewers. Getting the plumbing right is what lets your ads be part of it.
Want help making your video ads work across streaming, CTV and the web? Get in touch.