Implementing Bid Throttling in Prebid.js: A Step-by-Step Guide
Bid throttling is being sold by many prebid resellers as being a crucial aspect of managing header bidding auctions, particularly for optimizing performance and avoiding overwhelming the supply path with excessive bid requests. There are of course also a multitude of non-performance related benefits to bid throttling that include such topics as reducing your carbon footprint, minimizing the number of participants that receive data on a per user basis, and so forth. In this post I will attempt to demystify the process of implementing bid throttling using pre-existing features in prebid.js.
Understanding Bid Throttling
Before diving into the code, it's essential to grasp what bid throttling is. In the context of ad auctions, bid throttling refers to limiting the number of bid requests sent to a bidder based on some set of business rules. Imagine for instance that you would like to minimize requests going to bidders who have a historically high no-bid rate or low-bid rate after being called more than 3 times in a singular user session - bid throttling might hypothetically improve your overall monetization with a particular bidder by artificially introducing scarcity.
Getting Started
Before we begin, it is recommended that you use Prebid 8.0 or later when following this tutorial. You will also need to build prebid.js with the following module:
allowActivities
One quick note: the specifics of decisioning algorithms used to enforce throttling go beyond the scope of this tutorial.
Our simple tutorial will demonstrate a naive approach to throttling bidders to no more than one auction per minute if their fill rate drops below 50%. Again, this is not intended to be a decisioning system for your production prebid setup :)
Setting Up the Tracking Mechanism
With the disclaimers out of the way, lets get started! We begin by tracking bid requests, bid responses, and no-bids for each bidder. This data will help us determine which bidders to throttle. Here's a snippet to set up this tracking in the auctionEnd event of Prebid.js:
Breakdown:
Implementing Throttling Logic
Next, we define the logic to decide which bidders to throttle. We will simply tag all bidders who's cumulative bid rate drops below 50% . This check happens once at the end of each previous auction.
Breakdown:
Implement our throttling decision system
In our simple decisioning system, we will define a function that simply returns true or false if our bidder has been throttled due to the low bid rate check implemented in our previous step.
领英推荐
Breakdown:
Enforcing Throttling thanks to Activity Controls
According to prebid.org :
Starting with version 7.52, Prebid.js introduced a centralized control mechanism for privacy-sensitive activities - such as accessing device storage or sharing data with partners. These controls are intended to serve as building blocks for privacy protection mechanisms, allowing module developers or publishers to directly specify what should be permitted or avoided in any given regulatory environment.
As it turns out, activity controls are a fantastic way to implement simple bid throttling logic in prebid, no proprietary vendor code needed!
If you want to learn more about all of the various things that can be accomplished with Activity Controls, please take a look at https://docs.prebid.org/dev-docs/activity-controls.html#activities
let's continue with our tutorial...
The last thing we need to do is tell prebid to call our decisioning function before it goes to request bids.
Breakdown:
Conclusion
By following these steps, you can effectively implement bid throttling in Prebid.js. This approach helps in managing bidder performance, enhancing auction efficiency, and potentially increasing ad revenue. Remember, the key to effective throttling lies in continuously monitoring and adjusting your decisioning system based on bidder performance or other business rules. Happy coding!
A word of caution regarding "AI" or "ML" based bid throttling:
The latest trend in ad tech is to throw "AI/ML" at everything and while this is an incredibly complicated topic outside of the scope of this tutorial, there is enough vendor noise at the moment that I thought I'd chime in my two cents: It is impossible to predict the stock market. There are a few macro trends that may be discovered (often using statistics more than 'AI') when looking at large bid landscapes such as bidders preferring certain geographies, time of day, or season. However do not assume that any vendor will be able to reliably predict the price of a bidder on a per impression basis and make a throttling decision based on this. If they could do this reliably, they would be the world's best stock traders and not ad tech vendors :)
Came here for the copy-pasta? Full code snippet below:
// The prebid auctionEnd event gives a nice summary of the auction results and
// is a good place to track the number of bid requests, bid responses and no-bids for each bidder.
pbjs.onEvent("auctionEnd", function (auctionDetails) {
// Let's track the number of bid requests, bid responses and no-bids in a global
// object called pbjsTracking. In a real-world scenario, you would want to store
// this data in temporary storage (e.g. local storage) so that it can be accessed
// across different pages and sessions for the user.
window.pbjsTracking = window.pbjsTracking || {
bidRequests: {},
bidResponses: {},
noBids: {},
};
// Track bid requests
auctionDetails.bidderRequests.forEach(function (bidderRequest) {
const bidder = bidderRequest.bidderCode;
window.pbjsTracking.bidRequests[bidder] =
(window.pbjsTracking.bidRequests[bidder] || 0) +
bidderRequest.bids.length;
});
// Track bid responses
auctionDetails.bidsReceived.forEach(function (bid) {
const bidder = bid.bidder;
window.pbjsTracking.bidResponses[bidder] =
(window.pbjsTracking.bidResponses[bidder] || 0) + 1;
});
// Track no-bids
auctionDetails.noBids.forEach(function (noBid) {
const bidder = noBid.bidder;
window.pbjsTracking.noBids[bidder] =
(window.pbjsTracking.noBids[bidder] || 0) + 1;
});
updateThrottledBidders();
});
// Next we want to implement our throttling logic. For this example, we will
// throttle the number of bid requests to 1 per minute if the no-bid rate for
// a bidder is greater than 50%. We will do this by setting a flag in the
// pbjsTracking object for each bidder that is throttled along with a timestamp
// of when the throttling was applied. We will then use the new Activity Controls
// feature in Prebid to enforce the throttling.
function updateThrottledBidders() {
window.pbjsTracking.throttledBidders =
window.pbjsTracking.throttledBidders || {};
const now = Date.now();
Object.keys(window.pbjsTracking.noBids).forEach(function (bidder) {
if (
window.pbjsTracking.noBids[bidder] /
(window.pbjsTracking.bidRequests[bidder] || 1) >
0.5
) {
console.log (`Throttling ${bidder} for 1 minute`)
window.pbjsTracking.throttledBidders[bidder] = now + 60000;
} else {
console.log (`Unthrottling ${bidder}`)
delete window.pbjsTracking.throttledBidders[bidder];
}
});
}
// A function that tells us if a bidder is throttled or not
function isBidderThrottled(bidder) {
const isThrottled = (window.pbjsTracking?.throttledBidders?.[bidder] > Date.now());
console.log (`${bidder} is throttled: ${isThrottled}`);
return isThrottled;
}
// Finally, we need to implement the throttling enforcement. We will do this by
// using the new Activity Controls fetchBids feature in Prebid.
pbjs.setConfig({
allowActivities: {
// We will use the fetchBids activity to enforce throttling
fetchBids: {
// By default, we will allow all bidders to fetchBids
default: true,
// We will add a rule that disallows fetchBids if the bidder is throttled
rules: [
{
condition(params) {
const bidder = params.componentName;
// Do not allow fetchBids if the bidder is throttled
return isBidderThrottled(bidder);
},
// Disallow fetchBids if the condition returns true
allow: false,
// Set the priority to 1 so that this rule takes precedence over other rules
priority: 1,
},
],
},
},
});