This module allows Prebid.js to support PAAPI, formerly known as FLEDGE.
This document covers the steps necessary for publishers to enable PAAPI on their inventory. It also describes the changes Bid Adapters need to implement in order to support PAAPI.
A related module, paapiForGpt, adds support specifically for GPT’s component auctions.
To use PAAPI, publishers must:
include this module in their Prebid.js bundle
gulp build --modules=paapi,...
This module exposes the following settings:
Name | Type | Description | Notes |
---|---|---|---|
enabled | Boolean | Enable/disable the module | Defaults to false |
bidders | Array[String] | Optional list of bidders | Defaults to all bidders |
defaultForSlots | Number | Default value for imp.ext.ae in requests for specified bidders |
Should be 1 |
componentSeller | Object | Configuration for publishers acting as component sellers | See note |
parallel | Boolean | If true, start PAAPI auctions in parallel with Prebid auctions when possible | See parallel auctions |
As noted above, PAAPI support is disabled by default. To enable it, set the enabled
value to true
for this module and configure defaultForSlots
to be 1
(meaning Client-side auction).
using the setConfig
method of Prebid.js:
pbjs.que.push(function() {
pbjs.setConfig({
paapi: {
enabled: true,
defaultForSlots: 1
}
});
});
Optionally, PAAPI support can be limited to specific bidders:
pbjs.que.push(function() {
pbjs.setConfig({
paapi: {
enabled: true,
defaultForSlots: 1,
bidders: ['bidderA', 'bidderB']
}
});
});
All adunits can be opted-in to PAAPI in the global config via the defaultForSlots
parameter.
If needed, adunits can be configured individually by setting an attribute of the ortb2Imp
object for that
adunit. This attribute will take precedence over defaultForSlots
setting.
Name | Type | Description | Notes |
---|---|---|---|
ortb2Imp.ext.ae | Integer | Auction Environment: 1 indicates PAAPI eligible, 0 indicates it is not | Absence indicates this is not PAAPI eligible |
The ae
field stands for Auction Environment and was chosen to be consistent with the field that GAM passes to bidders
in their Open Bidding and Exchange Bidding APIs. More details on that can be found
here
In practice, this looks as follows:
pbjs.addAdUnits({
code: "my-adunit-div",
// other config here
ortb2Imp: {
ext: {
ae: 1
}
}
});
Bid adapters typically act as PAAPI sellers, each providing one or more component auctions in a multi-seller PAAPI auction.
Some adapters may act as PAAPI buyers: instead of a full component auction, they can reply directly with buyer information. By configuring componentSeller
, these buyers are collected into one or more publisher-managed component auctions.
Name | Type | Description |
---|---|---|
componentSeller.auctionConfig | Object | AuctionConfig object to use for the component auction(s) |
componentSeller.separateAuctions | Boolean | If true , generate a component auction for each bid adapter. If false (the default), buyers are collected into as few component auctions as possible (typically one, but multiple are possible if multiple bidders reply with the same buyer) |
Chrome has enabled a two-tier auction in PAAPI. This allows multiple sellers (frequently SSPs) to act on behalf of the publisher with a single entity serving as the final decision maker. In their current approach, GPT has opted to run the final auction layer while allowing other SSPs/sellers to participate as Component Auctions which feed their bids to the final layer. To learn more about Component Auctions, go here.
The PAAPI auction, including Component Auctions, are configured via an AuctionConfig
object that defines the parameters of the auction for a given
seller. This module enables PAAPI support by allowing bid adaptors to return AuctionConfig
objects in addition to bids. If a bid adaptor returns an
AuctionConfig
object, Prebid.js will make it available through getPAAPIConfig
, as well as other PAAPI modules such as paapiForGpt.
If your adapter interfaces with an ORTB backend, you may take advantage of Prebid’s ORTB conversion library, which implements the following using protected audience community extensions
Modifying a bid adapter to support PAAPI is a straightforward process and consists of the following steps:
buildPAAPIConfigs
method to support parallel auctions
When PAAPI is configured, the following fields are made available to adapters’ buildRequests
:
Name | Type | Description | Notes |
---|---|---|---|
validBidRequests[].ortb2Imp.ext.ae |
Integer | 1 when the PAAPI is enabled for the request |
|
validBidRequests[].ortb2Imp.ext.igs |
Object | InterestGroupSupport object | |
validBidRequests[].ortb2Imp.ext.igs.ae |
Integer | duplicate of ortb2Imp.ext.ae |
|
validBidRequests[].ortb2Imp.ext.igs.biddable |
Integer | 1 when ae is 1 |
|
validBidRequests[].ortb2Imp.ext.paapi.requestedSize |
Object | Size (as an object {width, height} ) that will be passed as requestedSize to runAdAuction |
|
bidderRequest.paapi.enabled |
Boolean | true if the publisher has enabled PAAPI and the browser supports it |
|
bidderRequest.paapi.componentSeller |
Boolean | true if the publisher can act as a component seller and accept igb objects instead of auction configs |
When a bid request is PAAPI enabled, a bid adapter can return a tuple consisting of bids and PAAPI objects rather than just a list of bids:
function interpretResponse(resp, req) {
// Load the bids from the response - this is adapter specific
const bids = parseBids(resp);
// Load auction configs or igb from the response - also adapter specific
const paapi = parsePaapi(resp);
return {bids, paapi};
}
paapi
must be an array of objects containing:
Name | Type | Description | Notes |
---|---|---|---|
bidId |
String | one of the input requests’ bidId . Used to identify the slot that this object refers to. |
|
igb |
Object | InterestGroupBuyer object | |
config |
Object | AuctionConfig object |
Each object must specify exactly one of igb
or config
.
An example of this can be seen in the OpenX bid adapter here or RTB House bid adapter here.
PAAPI auctions can be started in parallel with Prebid auctions for a significant improvement in end-to-end latency, as long as the adapters involved provide at least part of the auction config(s) in advance, before any request is sent to their backend.
To support parallel execution, adapters can provide a buildPAAPIConfigs
method, taking the same arguments as buildRequests and returning an array of PAAPI configuration objects in the same format as interpretResponse
’s paapi
parameter.
registerBidder({
// ...
buildPAAPIConfigs(validBidRequests, bidderRequest) {
// should return an array of {bidId, config, igb}
}
})
When provided, buildPAAPIConfigs
is invoked just before buildRequests
, and the configuration it returns is eligible to be immediately used to start PAAPI auctions (whether it will depends on the parallel
config flag and the top level seller’s support for it).
When not provided, the adapter cannot participate in parallel auctions, and PAAPI configuration returned by interpretResponse
are liable to be discarded when parallel auctions are enabled. For this reason we recommend implementing buildPAAPIConfigs
.
Some signals can be provided asynchronously; Prebid supports this by merging them from the return value of interpretResponse
, using bidId
as key.
Notably, however, at least seller
, interestGroupBuyers
, and decisionLogicUrl
must be provided synchronously (i.e., they must be hard-coded).
For example:
// suppose that `buildPAAPIConfigs` returns the following:
([
{
bidId: 'bid1',
config: {
seller: 'example.seller',
decisionLogicUrl: 'example.seller/logic.js',
interestGroupBuyers: ['example.buyer'],
auctionSignals: {
foo: 'bar'
},
perBuyerTimeouts: {
'example.buyer': 200
}
}
},
])
// and `interpretResponse` later returns:
({
paapi: [
{
bidId: 'bid1', // matches the bidId from `buildPAAPIConfigs`
config: {
// `perBuyerCurrencies` must be provided synchronously;
// this will be ignored
perBuyerCurrencies: {
'example.buyer': 'USD'
},
// `auctionSignals` and `sellerSignals` can be provided asynchronously
// and will be merged with those returned by `buildPAAPIConfigs`
auctionSignals: {
bar: 'baz'
},
sellerSignals: {
foo: 'bar'
}
}
},
{
bidId: 'bid2', // does not match.
// `config` will be used as-is, but only if no auction was already
// started in parallel for this slot; it will be discarded otherwise.
config: {
/* ... */
}
}
]
})
// the result as seen in the sandboxed auction for `bid1` will then be:
({
seller: 'example.seller',
decisionLogicUrl: 'example.seller/logic.js',
interestGroupBuyers: ['example.buyer'],
auctionSignals: {
foo: 'bar',
bar: 'baz'
},
perBuyerTimeouts: {
'example.buyer': 200
},
sellerSignals: {
foo: 'bar'
}
})