We would like to outline how the Protected Audience API can be used to support video (instream audio/video advertising) when there are multiple sellers (i.e. exchanges).
In the Protected Audience API, a top level seller can include other sellers in the Protected Audience auction as “component auctions” (or component sellers). These component sellers should be able to:
- Run their own Protected Audience auction with their buyers, and submit their winning bid to the top-level auction.
- Receive Fenced Frame Reporting tracking events about the Protected Audience auction.
Protected Audience API for Instream Video proposes the flow when there is only a single seller. This doc builds on that proposal to enable component sellers.
To collaboratively create a renderUrl
that delivers a video ad and tracks video events, each participant in the auction should do the following:
- Buyer
- The buyer should join ad interest groups with
renderUrl
that contain seller macros and buyer’s ad URL. The seller macros allow sellers to insert seller’s VAST wrapper URLs. The buyer’s ad URL should return the VAST ad.
- The buyer should join ad interest groups with
- Component seller
- A component seller should provide its component auction configuration to the top-level seller. This configuration should contain a macro replacement map that will be used to inject component seller’s wrapper VAST URL to the
renderUrl
.
- A component seller should provide its component auction configuration to the top-level seller. This configuration should contain a macro replacement map that will be used to inject component seller’s wrapper VAST URL to the
- Top-level seller
- The top-level seller should construct the final
auctionConfig
, including any configuration provided by the component seller. - It should provide the top-level seller's wrapper VAST URL to the Protected Audience Integrator.
- The top-level seller should construct the final
To pull this together, a component seller, a top-level seller, a publisher or a third-party video SDK provider, needs to perform the integration with Protected Audience on the publisher’s website. More specifically, this PA Integrator should:
- Run a PA API auction using the
auctionConfig
provided by the top-level seller. - Coordinate video playback between the content video player and the winning PA ad.
- This coordination is achieved through an HTML shim that will run inside the PA APIs rendering frame.
- The HTML shim should:
- Contain a video player to play VAST video ads.
- Support a VAST extension for triggering Fenced Frame reporting APIs
- Receive user interaction events (such as play, pause) from outside of the iframe as
postMessage
s and play / pause the video ad accordingly. - Receive events (such as video progress events) from the video ad player and forward them outside of the iframe through
postMessages
- Perform macro expansion on the winning PA ad URN, in order to provide (1) the URL to its HTML shim and (2) the top-level sellers VAST URL.
The following walkthrough is meant as an illustration of one possible flow that can be used to support component-seller in PA video. We would like industry’s feedback on the feasibility of this flow, as well as our alternatives explored below. Feel free to raise questions and suggestions as GitHub issues.
The following walkthrough illustrates a flow where the top-level seller fulfills the role of integrating Protected Audience API with the content video player.
To store an interest group to a browser, a buyer should construct its Protected Audience video creatives’ renderUrl
s as follow:
- Buyer creates a Buyer Ad URL that would return a video ad as a VAST document. For example:
https://buyer.com/?video_ad=123
- Buyer creates a
renderUrl
using the following template. Buyer should replace[[URL_ENCODED_BUYER_AD_URL]]
with a URL encoded Buyer Ad URL.
https://${seller_video_url}/?${seller_video_query_params}[[URL_ENCODED_BUYER_AD_URL]]
For example:
https://${seller_video_url}/?${seller_video_query_params}https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
-
Before ad serving, the top-level seller, who is acting as the PA Integrator, will host an endpoint for their HTML Shim.
- If an independent video ad player provider is acting as the PA Integrator, it would need to host its own HTML Shim, since their requirements for coordination may be unique.
-
When a user visits the publisher page (and before ad request), a component seller would need to opt-in to the PAAPI auction to participate.
- The component seller can provide its
componentAuction
’s config to the top-level seller. - Component seller’s
componentAuction
’s config should contain adeprecatedRenderURLReplacements
that will be used to replace${seller_video_query_params}
with the following template: [[URL_ENCODED_COMPONENT_SELLER_URL]]
is a URL-encoded URL pointing to the component seller’s VAST server. The component seller’s VAST server should return a VAST document that contains the Fenced Frame Reporting tracking events.
- The component seller can provide its
${wrapper_prefix}[[URL_ENCODED_COMPONENT_SELLER_URL]]${seller_video_query_params}
For example, component seller can pass the following componentAuction
’s config:
// Example component seller's URL
// https://component-seller-url/ad/vast.xml?ad_url=
// Example API:
adsRequest.setProtectedAudienceAuctionConfigValue({
'componentAuctions': [{
'seller': 'https://www.some-other-ssp-1.com',
'deprecatedRenderURLReplacements': {
"${seller_video_query_params}": "${wrapper_prefix}https%3A%2F%2Fcomponent-seller-url%2Fad%2Fvast.xml%3Fad_url%3D${seller_video_query_params}"
}
}]
});
- The top-level seller merges the component seller’s auction config into their own
auctionConfig.
- The top-level seller, acting as the PA Integrator, uses this merged configuration when calling
runAdAuction()
.
navigator.runAdAuction({
...
'componentAuctions': /* auctionConfig from component seller */
...
],
});
- If a video ad wins the component auction, the winning
renderUrl
may be the following:
https://${seller_video_url}/?${seller_video_query_params}https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
- With
deprecatedRenderURLReplacements
in the component seller’s auction config, the browser inserts the component seller’s render URL to therenderUrl
by replacing the macro${seller_video_query_params}
with component seller’s macro. The effective URL from therunAdAuction()
may look like the following:
https://${seller_video_url}/?
${wrapper_prefix}
https%3A%2F%2Fcomponent-seller-url%2Fad%2Fvast.xml%3Fad_url%3D
${seller_video_query_params}https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
-
The top-level seller, acting as the PA Integrator, expands the macro
${seller_video_query_params}
by usingdeprecatedReplacedInURN()
using the following template:${wrapper_prefix}[[URL_ENCODED_TOP_LEVEL_SELLER_URL]]${seller_video_query_params}
[[URL_ENCODED_TOP_LEVEL_SELLER_URL]]
is a URL-encoded URL pointing to the top-level seller’s VAST server. The top-level seller’s VAST server should return a VAST document that contains the Fenced Frame Reporting tracking events. For example, the top-level seller may have a URL like:
https://top-level-seller-url.com/wrapper.xml?adTag=123
- After URL encoding, it becomes:
https%3A%2F%2Ftop-level-seller-url.com%2Fwrapper.xml%3FadTag%3D123
- After performing the macro expansion, the URN may now reference a URL that looks like:
https://${seller_video_url}? ${wrapper_prefix} https%3A%2F%2Fcomponent-seller-url-1%2Fad%2Fvast.xml%3FadTag%3D ${wrapper_prefix} https%3A%2F%2Ftop-level-seller-url.com%2Fwrapper.xml%3FadTag%3D123 ${seller_video_query_params}https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
-
The top-level seller, acting as the PA Integrator, uses
deprecatedReplacedInURN()
to replace the macros:${seller_video_url}
- The URL for the Video Ad Player’s HTML shim. For example,
video-ad-player.net/td/vast.html
- The URL for the Video Ad Player’s HTML shim. For example,
${wrapper_prefix}
- A query parameter that HTML shim will use to read wrapper VAST URIs from its
document.location
. For example&wrapper=
- A query parameter that HTML shim will use to read wrapper VAST URIs from its
${seller_video_query_params}
- A query parameter that HTML shim will use to read the buyers VAST ad URI from its
document.location
. For example&adTag=
- A query parameter that HTML shim will use to read the buyers VAST ad URI from its
After this final round of macro expansion, the URN may now reference a URL that looks like:
https://video-ad-player.net/td/vast.html?
&wrapper=https%3A%2F%2Fcomponent-seller-url-1%2Fad%2Fvast.xml%3FadTag%3D
&wrapper=https%3A%2F%2Ftop-level-seller-url.com%2Fwrapper.xml%3FadTag%3D123
&adTag=https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
- The top-level seller, acting as the PA Integrator, takes the URN from the previous phase and sets it as the source of an iframe.
- The HTML shim should read the encoded URLs from the top-level seller, component seller, and buyer from its query parameters and construct VAST ad tag URL.
For example:
// Within Video Ad HTML Shim
function main() {
const params = new URLSearchParams(document.location.search);
const [wrapper1, wrapper2] = params.getAll('wrapper').map(decodeURIComponent);
const inlineAdTag = decodeURIComponent(params.get('adTag');
// ... continued
}
- The HTML shim should construct a VAST ad tag URI by combining the URLs from top-level seller, component seller, and buyer. For example:
function main() {
// ... continued
function constructWrapper(wrapper, destinationAd) {
return ${wrapper}${encodeURIComponent(destinationAd)};
}
// Note that the inlineAd tag will be double encoded.
return constructWrapper(wrapper2, constructWrapper(wrapper1, inlineAd));
}
Diagram of Ad Tag URI created by HTML shim
Note: the above example shows that the first domain is the top-level seller. However, the first domain can also be the component seller.
- After constructing the VAST Ad Tag URI, the video ad player's HTML shim feeds the constructed VAST ad tag URI into a VAST player for resolution.
- The VAST player should resolve each VAST response in sequence, following wrapper tags. For example, the VAST player makes an initial HTTP request, fetching a VAST wrapper from the first endpoint. This may look like:
http://top-level-seller.com/wrapper.xml/
?adTag=https%3A%2F%2Fcomponent_seller.com%2Fwrapper.xml%26adTag%3D=
https%253A%252F%252Fbuyer.com%253Fvideo_ad%253D123
- The endpoint (the top-level seller in this example) should return a wrapper VAST with its tracking tags and
<VASTAdTagUri>
pointing to the next endpoint, provided on the URL with&adTag=
query parameter. For example, the<VASTAdTagUri>
in the wrapper VAST should be:
https://component-seller.com/wrapper.xml/
?&adTag=https%3A%2F%2Fbuyer.com%3Fvideo_ad%3D123
- The VAST player makes another HTTP request, fetching a VAST wrapper from the next endpoint.
- The next endpoint (component seller in this example) should also return a wrapper VAST with its tracking tags and
<VASTAdTagUri>
pointing to the next endpoint, provided on the URL with&adTag=
query parameter. For example, the<VASTAdTagUri>
in the wrapper VAST should be:
https://buyer.com?video_ad=123
- The VAST player makes a final request to the buyer, who returns an inline VAST ad.
-
Video playback starts as soon as the inline VAST ad is loaded.
-
When the user clicks on the pause button on the publisher page:
- The publisher page should send a
postMessage
event to the HTML Shim. - HTML Shim should pre-register a callback to receive this event. HTML Shim can respond by pausing the ad.
- The publisher page should send a
-
When an event needs to be communicated outside of the video playback:
- The HTML Shim should send a
postMessage
to outside the iframe. - The publisher page should pre-register a callback to receive this event.
- The HTML Shim should send a
Similar to the Protected Audience API for Instream Video proposal, this proposal requires iframes.
It is possible to optimize the rendering flow by parallelizing VAST document requests. The URL sent to the ad video player contains URLs for the top-level seller, component seller, and the buyer as separate query parameters. For example:
https://video-ad-player.net/td/vast.html?
&wrapper=https%3A%2F%2Fcomponent-seller-url-1%2Fad%2Fvast.xml%3FadTag%3D
&wrapper=https%3A%2F%2Ftop-level-seller-url.com%2Fwrapper.xml%3FadTag%3D123
&adTag=https%3A%2F%2Fbuyer.com%2F%3Fvideo_ad%3D123
Instead of chaining these URLs in a series of VAST wrapper redirects, the video ad player can send requests to these URLs in parallel. This can improve rendering latencies.
As an alternative rendering flow, the renderURL
could contain only the HTML Shim requirements and buyers ad tag URL. In this way, the video ad player can skip calling out to the sellers and the component seller for VAST responses. To enable event tracking for sellers, the PA Integrator would trigger a set of predefined Fenced Frame reporting API events. The PA Integrator can publish a list of Fenced Frame reporting API eventNames
for each event that the video ad player will call reportEvent()
on. If an event carries additional metadata (such as the playhead position), it could potentially be communicated through eventData. Further, this set of eventNames can be standardized for all VAST players supporting PA API. The top level seller and component seller can pre-register beacons for these events using the Fenced Frame Reporting API within its reportResult()
.