It's in everyone's best interest to make sure the Protected Audience API operates efficiently:
- People browsing the web want sites to load quickly. This means developers should build with the Protected Audience API efficiently as to not overutilize limited device resources, like compute or network resources, that are necessary to load sites and their embedded ads.
- Publishers want their sites to load quickly, providing users an efficient and responsive experience. Publishers also want effective advertising to maximize their revenue.
- Advertisers and ad techs want their ads to display quickly to provide the greatest utility.
This document outlines some best practices for a Protected Audience API implementation, to ensure your site operates at maximum efficiency.
Buyer (bidder) best practices
To make sure you're optimizing for Protected Audience API auction efficiency, follow these best practices.
Fewer interest group owners
To protect Protected Audience API bidders in the same way that the browser protects different origins on the web using site isolation, the browser uses expensive resources (like operating system processes) to protect individual interest group owners.
To minimize the expenditure of these very expensive resources, having the
fewest number of interest group owners is crucial. Avoid having different
interest groups owned by various subdomains. For example, if adtech.example
had interest groups owned by cats.adtech.example
and dogs.adtech.example
,
the browser would likely use two separate processes to run their bidding
scripts.
Fewer interest groups bidding
The browser must do significant setup and preparation before invoking a buyer's
generateBid()
script, such as setting up a new clean JavaScript execution
environment, and parsing and loading the generateBid()
code.
- Interest groups that represent users who aren't the current target of an
active advertising campaign should have empty ad creative lists. This prevents
the Protected Audience API from executing
generateBid()
for interest groups without relevant ads. - Combining similar interest groups will decrease the number of times
generateBid()
must be run. An interest group'suserBiddingSignals
property can be used to store additional metadata about the user, so fewer interest groups doesn't have to mean less effective targeting. - The Protected Audience API supports seller-specified limits on the numbers of interest groups, and an API for buyers to specify the relative priority of their interest groups. These limits can be used to significantly reduce the number of bidding scripts to run.
Filter out interest groups from bidding in your Key/Value service
If a buyer can determine in their real-time trusted bidding signal server that certain interest groups shouldn't bid (e.g. the campaign is disabled, paused, or out of budget, or shouldn't bid on this particular publisher), they can indicate this to the browser with the priorityVector
response to the trusted bidding signals fetch. If the resulting sparse dot product of the priorityVector
and prioritySignals
is negative, then the browser will skip invoking generateBid()
for this interest group. You can read more about this mechanism in the "Filtering and Prioritizing Interest Groups" section of the explainer.
Reuse JavaScript execution environment
Before the browser can execute generateBid()
, it must initialize a new JavaScript execution environment. This can take a significant amount of time, on par with the amount of time a minimal generateBid()
itself can take to execute. This time can be saved by using the group-by-origin or frozen-context execution modes.
The group-by-origin
mode can reuse execution environments in cases where interest groups are joined on the same origin, and likely won't require changes to your bidding script; to learn more, see the group-by-origin
description in the explainer. The frozen-context mode can reuse potentially all execution environments but may require changes to your bidding script; to learn more, see the frozen-context
description in the explainer.
Reuse bidding scripts
Use the same bidding script for interest groups if possible. This prevents the browser from having to download, parse, and compile multiple scripts (which incurs extra network requests). Bidders can still differentiate bidding based on interest group information (e.g. name
or userBiddingSignals
) while using the same script.
Without HTTP cache control headers, the bidding script is not cached. Specify appropriate headers to ensure the script is not unnecessarily fetched. If there are multiple auctions on the page running in parallel, the bidding script of the same bidder will be reused if it's already in memory, ignoring caching semantics. If the auctions run sequentially, then the browser will adhere to the HTTP caching mechanism.
Note that the browser loads the bidding script during bid time (for generateBid()
) and also during reporting time (for reportWin()
). If cache control headers are not set, then the browser will fetch the same script twice, once for each time period.
Therefore, we recommend setting cache control headers on all your scripts.
Reuse trustedBiddingSignalsUrls
Network latency and resource usage can be very significant. Fewer real-time trusted bidding signals fetches can help reduce this latency.
The trusted bidding signal fetches can be combined
when the trustedBiddingSignalsUrl
is reused amongst multiple interest groups.
When possible, use the same trustedBiddingSignalsUrl
for all interest groups.
Specify appropriate HTTP cache control headers to ensure trusted bidding signal fetches are cached across ad slots on a particular web page. Avoid setting trustedBiddingSignalsSlotSizeMode
to slot-size
as this will prevent caching across ad slots when the sizes of the slots differ because the requested URL will differ.
Smaller real-time trusted bidding signals fetches
Network latency can be very significant, and this is directly impacted by how much data is transferred during the real-time trusted bidding signal fetches.
Prefer storing ad-specific or interest-group-specific data in the interest group, rather than on the real-time trusted bidding signal service. Reserve real-time trusted bidding signal data for only those truly real-time signals, like campaign budgeting or kill-switches.
Any signal that can be updated on a daily or longer basis should be stored in the interest group and updated using the daily updates.
Don't return trusted bidding signals for interest groups that are filtered out as described in the "Filter out interest groups from bidding in your Key/Value service" section.
Prioritize interest groups
Sellers will use timeouts to limit how browser resources are used on publisher pages. When perBuyerCumulativeTimeouts
are used to limit how long buyers have to fetch their trusted bidding signals and execute their bidding scripts, it's critical for buyers to make sure they prioritize their interest groups so that those most likely to win the auction execute first. For example, if perBuyerCumulativeTimeouts
is set to 100 ms and a bidder's trusted bidding signals fetch takes 50 ms, and each generateBid()
invocation takes 10ms and they have 10 interest groups present on a device, then only half of their interest groups will have a chance to calculate bids. The buyer in this example should prioritize their interest groups in order from most-likely-to-win to least-likely-to-win.
Interest groups can contain static priorities defined with their priority
field. Interest groups can also use dynamic priorities that can be calculated on their trusted bidding signals service and returned to the browser with the priorityVector
response to the trusted bidding signals fetch.
Note that when the browser executes interest groups from highest priority to lowest, this may intersperse interest groups from different joining origins which may defeat the group-by-origin
optimization.
Seller best practices
Make sure you're monitoring and optimizing for Protected Audience API auction efficiency.
Parallelize auctions
Modern network connections and multi-core processors do a great job performing multiple activities concurrently. The browser can execute a Protected Audience auction in parallel with other activities. This can be best facilitated by calling runAdAuction()
as early as possible. Recognizing that some inputs to runAdAuction()
may not be available early on, for example, those that are sent back to the browser in the contextual response, the browser allows calling runAdAution()
before they are available, and providing these inputs at a later time using JavaScript Promises. To achieve the lowest possible auction latency, runAdAuction()
should be called when the interestGroupBuyers
input is known. This allows many parts of the auction to commence immediately, including fetching bidder's real-time bidding signals.
Monitor your auctions
Collect metrics on your auctions. The browser can report per-buyer
latency metrics to sellers that provide a lot of insight into how time is spent in a seller's auctions. Sellers can use these metrics to look for ways to optimize their auctions, including informing how to set timeouts most effectively. Sellers can share a specific buyer's latency metrics with the buyer to help them optimize further.
Bidders may have insights into their own interest groups' bidding performance, but they may not be able to compare this to other bidders. Comparing relative win rates and bid rejection rates for different bidders may help identify cases where bidding compute resources were wasted due to interest groups never producing viable bids or excessive bidding with unapproved creatives.
Protect against slow bid scripts
Bidding scripts that take excessive time can slow the Protected Audience API auction down for everyone involved. Using timeouts can prevent slow auctions while still recovering revenue when the auction is slow.
Sellers should use perBuyerCumulativeTimeouts
to prevent slow auctions and also to still accept bids when the auction is slow and reaches the timeout. Using perBuyerCumulativeTimeouts
is preferable to using perBuyerTimeouts
and perBuyerGroupLimits
because perBuyerCumulativeTimeouts
is not opinionated about the number of interest groups or speed of generateBid()
(e.g. many interest groups that bid quickly and few interest groups that bid slowly can both complete before the timeout).
Using the auction config signal
field to implement an overall auction timeout is also a good idea to prevent overly long auctions in cases where trusted scoring signal fetches and executing scoreAd()
take too much time.
What's next?
We want to engage in conversations with you to ensure we build an API that works for everyone.
Discuss the API
Like other Privacy Sandbox APIs, this API is documented and discussed publicly.
Experiment with the API
You can experiment and participate in conversation about the Protected Audience API.