PAAPI module

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.

Publisher Integration

To use PAAPI, publishers must:

  • include this module in their Prebid.js bundle

     gulp build --modules=paapi,...
    
  • enable PAAPI, globally or by ad unit, through configuration
  • manage the PAAPI auctions. This can be delegated to GPT with the paapiForGpt module; homegrown solutions are possible with topLevelPaapi.

Module Configuration

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']
    }
  });
});

AdUnit Configuration

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
        }
    }
});

Advanced usage: publisher-managed component auction

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)

Bid Adapter Integration

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:

  1. Detecting when a bid request is PAAPI eligible
  2. Responding with AuctionConfig or InterestGroupBuyer in addition to (or instead of) bids
  3. (Optional, but recommended) implementing a buildPAAPIConfigs method to support parallel auctions

Input parameters

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  

Output values

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.

Parallel auctions

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'
  }
})