Bidding and Auction (B&A) Services is a set of services for ad buyers and sellers that runs in a Trusted Execution Environment (TEE) to facilitate a Protected Audience (PA) auction. This Developer's Guide explains how a buyer can integrate with a B&A PA auction for Chrome.
Overview
To participate in a Protected Audience auction with B&A Services, the buyer updates the interest group (IG) to optimize the payload for improved auction latency.
The following payload optimization tasks are required by the buyer:
joinAdInterestGroup()
tasksgenerateBid()
tasks
Interest group for B&A
The following is an example interest group config for a B&A PA auction with payload optimization applied:
navigator.joinAdInterestGroup({
name: 'example-ig',
owner: 'https://dsp.example',
// An ID is mapped to each render URL
ads: [
{
renderURL: 'https://dsp.example/ad.html',
adRenderId: '12345678' // 12 characters max,
buyerReportingId: 'brid123', // Optional
buyerAndSellerReportingId: 'bsrid123', // Optional
selectableBuyerAndSellerReportingId: ['sbsrid123', 'sbsrid456'], // Optional
},
],
adComponents: [
{
renderURL: 'https://dsp.example/ad-component.html',
adRenderId: 'abcdefgh'
},
],
// Flags are set to omit data in the B&A auction payload
auctionServerRequestFlags: ['omit-ads', 'omit-user-bidding-signals'],
// Data not included in the B&A auction payload can be fetched as trusted signals
// The following is an example of how the keys could look, but the actual
// implementation is up to the ad tech
trustedBiddingSignalsKeys: [
'exampleUserBiddingSignalsKey',
'exampleAdRenderIdKey',
'exampleAdMetadataKey',
'exampleAdReportingIdKey',
],
// Optionally, interest groups can be prioritized
priority: 0.0,
});
The differences between the B&A and on-device interest group configs are:
Fields | B&A IG | On-device IG | Included in the B&A auction payload |
auctionServerRequestFlags |
Used | Not used | No |
userBiddingSignals |
Not recommended | Used | No, if omit-user-bidding-signals flag is set |
adRenderId in ads and adComponents |
Used | Not used | If the omit-ads flag is set, adRenderId in ads is available only in browserSignals.prevWins of the payload. adRenderId defined in adComponents is not included in the payload.If the |
renderURL in ads and adComponents |
Used | Used | No |
metadata in ads and adComponents |
Not used | Used | No |
Reporting IDs in ads |
Used | Used | No |
- The
auctionServerRequestFlags
field allows setting flags that tells the browser to omit some data in the B&A auction payload. - The
userBiddingSignals
value can be defined in the interest group, but it is recommended to omit them by using theomit-user-bidding-signals
flag. The omitted signals can be supplied by using the K/V Service. - The
adRenderId
field is set along with the associatedrenderURL
, but only theadRenderId
will become part of the B&A auction payload. The render URL returned fromgenerateBid()
later during auction time must match the render URL defined in the IG. - Reporting IDs are defined in the B&A IG, but are not included in the B&A auction payload. The reporting ID returned from
generateBid()
later during auction time must match the render URL defined in the IG. - The
ad.metadata
and reporting IDs are not included in the B&A auction payload, and instead, those data become available through the Trusted Key/Value Service usage.
Note that renderURL
s and reporting IDs in ads
are still defined in the interest group config, though they don't become included in the auction request payload, because the browser checks that the render URL and reporting IDs returned from generateBid()
function of the Bidding Service match the values defined in the interest group.
joinAdInterestGroup()
tasks
The following tasks need to be performed for the joinAdInterestGroup()
call.
Set server request flags
The joinAdInterestGroup()
config's auctionServerRequestFlags
field accepts the following flags:
Flag | Description |
omit-user-bidding-signals |
The omit-user-bidding-signals flag omits the userBiddingSignals object in the auction payload.
If the flag is not set, the |
omit-ads |
The omit-ads flag tells the browser to omit the ads and adComponents objects in the auction payload.The If the flag is not set, It is highly recommended for buyers to opt for the |
The omitted data is handled by making relevant information available in trustedBiddingSignals
. The flags can be used individually, and don't have to be used together.
Example usage:
navigator.joinAdInterestGroup({
auctionServerRequestFlags: ['omit-user-bidding-signals', 'omit-ads'],
});
Set ad render IDs
To reduce the size of the B&A auction payload, the ads
and adComponents
objects of the interest group are omitted, and in turn, these objects are not available inside the generateBid()
function running in Bidding Service.
To handle the missing ad information, the buyer maintains an identifier (adRenderId
and adComponentRenderId
) associated with each ad in the interest group config. The identifier must be a DOMString that is 12 bytes long or less. If the identifier is Base64 encoded, its length must be 12 bytes long or less.
An example interest group with ad render IDs:
navigator.joinAdInterestGroup({
ads: [
{
renderURL: 'https://dsp.example/ad.html',
adRenderId: '12345678' // 12 characters max
},
],
adComponents: [
{
renderURL: 'https://dsp.example/ad-component.html',
adComponentRenderId: 'abcdefgh'
},
],
});
The adRenderId
associated with the ads become available in prevWins.browserSignals
in generateBid()
.
Though the renderURL
is not included in the request payload, the returned render URL from generateBid()
must match the render URL defined in the interest group config. Ad techs can send back ad metadata and other information in trustedBiddingSignals
, so that ad render URL and ad component render URL can be generated for the bid during the generateBid()
execution.
Set interest group priorities
Chrome allows buyers to prioritize interest groups. If the per-buyer payload size limit set by the seller is reached, then the interest group priority values are used to drop the lower priority interest groups for a single buyer when the B&A auction payload is generated for the seller. For selecting interest groups between different buyers, the browser decides based on the size of the serialized payload. By default, each buyer is given an equal size. Note that the actual prioritization occurs on the B&A servers, and not when the request payload is generated.
The priority is calculated at auction time by using the buyer's priority vectors (priorityVector
) and the seller's priority signals (prioritySignals
). The buyer has the ability to override the seller's priority signals.
Property | Description |
Priority vector | The buyer supplies the vectors as the value of the priorityVector key from the K/V Service |
Priority signals | The seller supplies the signals by setting priority_signals of the auction config |
Priority signals overrides | The buyer supplies the override in the priority_signals_overrides field of the PerBuyerConfig in the auction config. |
During the auction, the browser calculates the sparse dot product of the matching keys in priorityVector
and prioritySignals
for the priority. In the following diagram, the priority is calculated by (4 * 2) + (3 * -1)
which is reduced to 8 + -3
, so the priority of this interest group at auction time is 5
.

Additional signals are also available to be used for prioritization in B&A:
Signal | Description |
deviceSignals.one |
The value is always 1, and is useful for adding a constant to the dot product. |
deviceSignals.ageInMinutes |
The value describes the interest group's age (the time since the most recent interest group join) in minutes as an integer between 0 and 43,200. |
deviceSignals.ageInMinutesMax60 |
The value describes the same as the ageInMinutes signal, but is maxed at 60. If the group is more than 1 hour old, then 60 is returned. |
deviceSignals.ageInHoursMax24 |
The value describes the interest group's age in hours, maxed at 24 hours. If the group is more than a day old, then 24 is returned. |
deviceSignals.ageInDaysMax30 |
The value describes the interest group's age in days, maxed at 30 days. If the group is more than 30 days old, then 30 is returned. |
To learn more, visit the explainer on GitHub.
Set up trusted bidding signals
Since some data will be omitted from the B&A auction payload, you can use the Key/Value Service to supply the omitted data as trusted bidding signals to the generateBid()
function.
The following omitted data can be supplied by the K/V Service:
userBiddingSignals
if used by the buyermetadata
associated with each adadRenderId
associated with each ad- Reporting ID

One approach that can be taken is to include a unique identifier in the trusted bidding signals keys, and then send the associated data to your server so it can be loaded into the Key/Value Service. However, the actual implementation is up to the ad tech and the API is not prescriptive.
The following example describes one approach that can be implemented:
const ad1RenderURL = 'https://dsp.example/ad-1.html';
const ad2RenderURL = 'https://dsp.example/ad-2.html';
const ad1RenderId = 'render-id-1';
const ad2RenderId = 'render-id-2';
const ad1ReportingId = 'reporting-id-1';
const ad2ReportingId = 'reporting-id-2';
// Generate a unique identifier
const id = crypto.randomUUID();
// Define the keys with the unique ID
const trustedSignalsKeyForIG = `interest-group-${id}`
// Set the keys in the interest group
navigator.joinAdInterestGroup({
// …
ads: [
{
renderURL: ad1RenderURL,
adRenderId: ad1RenderId,
buyerReportingId: ad1ReportingId
},
{
renderURL: ad2RenderURL,
adRenderId: ad2RenderId,
buyerReportingId: ad2ReportingId
},
],
trustedBiddingSignalsKeys: [
trustedSignalsKeyForIG
]
});
// Send the associated data to your server to be loaded into the Key/Value Service
fetch('https://dsp.example/kv/load', {
method: 'POST',
body: JSON.stringify({
id,
[trustedSignalsKeyForIG]: {
userBiddingSignals: {
favoriteColor: 'blue'
},
ads: [
{
renderURL: ad1RenderURL,
adRenderId: ad1RenderId,
buyerReportingId: ad1ReportingId,
metadata: {
color: 'red'
}
},
{
renderURL: ad2RenderURL,
adRenderId: ad2RenderId,
buyerReportingId: ad2ReportingId,
metadata: {
color: 'blue'
}
},
]
}
})
});
In the example, a unique identifier is defined for an IG and becomes part of the trusted signals key. The key for the IG and their associated values are sent to your server to be loaded into the Key/Value Service. At a later time during the auction, the browser fetches the trusted signals and makes them available in the buyer's generateBid()
function.
Return interest group update signal from K/V if needed
The updateIfOlderThanMs
key for the trusted signals is used to update the interest group earlier than the usual daily interval. If the interest group hasn't been joined or updated in a duration of time exceeding the milliseconds value returned for the updateIfOlderThanMs
key, the interest group will be updated with the updateURL
mechanism. Note that Chrome won't update interest groups more frequently than once every 10 minutes.
If the B&A auction returns a winning ad that doesn't match one of the ads defined in the interest group stored in the browser, then the browser will fail the auction. The updateIfOlderThanMs
mechanism can be useful in ensuring that the browser and the B&A auction agree on the set of ads in the interest group.
Visit the explainer to learn more.
generateBid()
tasks
The following tasks need to be performed for the generateBid()
call.
Read browser signals
The browserSignals
object passed into the B&A generateBid()
call looks like the following:
{
topWindowHostname: 'advertiser.example',
seller: 'https://ssp.example',
topLevelSeller: 'https://ssp-top.example',
joinCount: 5,
bidCount: 24,
recency: 1684134092,
// prevWins is [timeInSeconds, adRenderId]
prevWins: [
[9342, 'render-id-1'],
[1314521, 'render-id-2']
],
// Compiled WebAssembly code
wasmHelper: WebAssembly.Module
// Data-Version value from K/V response, if available
dataVersion: 1,
}
The following modified or new properties are available in browserSignals
:
Property | Description |
prevWins |
prevWins is an array of tuples of time and ad. The time represents the seconds passed since the associated ad's previous win in the last 30 days.It has been modified to provide the |
wasmHelper |
Compiled object of the code supplied from biddingWasmHelperURL . |
dataVersion |
A trusted server may optionally include a numeric Data-Version response header that becomes available in generateBid() .Read the explainer on GitHub to learn more. |
Return render URL from generateBid()
Since the ads
object is omitted in the B&A auction payload, the render URL returned from generateBid()
must be recreated. How the render URL is recreated is determined by your implementation, and the returned URL must match the render URL defined in the interest group.
One approach that could be taken is to maintain a base URL, and populate the template with the information from interestGroup
and trustedBiddingSignals
.
In this example, we are defining 4 ads based on the color and product:
await navigator.joinAdInterestGroup({
ads: [
{ renderURL: 'https://dsp.example/red-shirt-ad.html', adRenderId: 'arid1'},
{ renderURL: 'https://dsp.example/blue-shirt-ad.html', adRenderId: 'arid2'},
{ renderURL: 'https://dsp.example/red-pants-ad.html', adRenderId: 'arid3'},
{ renderURL: 'https://dsp.example/blue-pants-ad.html', adRenderId: 'arid4'},
],
trustedBiddingSignalKeys: [
'userBiddingSignals-someUniqueId',
// ...and more
]
})
Then we send the user's favorite color and product information to be loaded into the Key/Value Service:
fetch('https://dsp.example/kv/load', {
body: JSON.stringify({
'userBiddingSignals-someUniqueId': {
favoriteColor: 'blue',
favoriteProduct: 'shirt'
}
})
})
At a later time, when the auction runs, the trusted bidding signals become available in generateBid()
, and that information can be used to reconstruct the URL:
function generateBid(..., trustedBiddingSignals, browserSignals) {
const { userBiddingSignals } = trustedBiddingSignals
const { favoriteColor, favoriteProduct } = userBiddingSignals
return {
bid: 1,
render: `https://dsp.example/${favoriteColor}-${favoriteProduct}-ad.html`
}
}
Return reporting IDs from generateBid()
Since the reporting IDs are not included in the B&A auction payload, the ID becomes available to generateBid()
through trusted bidding signals. Once which reporting ID to use is determined, the chosen reporting ID is returned from generateBid()
. The returned IDs must match the IDs defined in the interest group.
In this example, ad 1 is chosen, and its associated render ID is returned from generateBid()
:
generateBid(..., trustedBiddingSignals, …) {
const { ad1ReportingId, ad2reportingId } = trustedBiddingSignals;
// ...
return {
bid: 1,
render: 'https://dsp.example/ad-1.html'
buyerReportingId: ad1reportingId
}
}
The returned reporting ID becomes available in reportWin()
through buyerReportingSignals
:
reportWin(..., buyerReportingSignals) {
const { buyerReportingId } = buyerReportingSignals;
}
If buyerReportingId
is not returned from generateBid()
, then the interestGroupName
value is available in buyerReportingSignals
instead of buyerReportingId
.
Visit the Reporting ID guide to learn more.
Next steps
The following resources are available for you
Learn more
- Learn more about the B&A auction configurations in Chrome
- Experiment with Protected Audience with B&A by following the End-to-End Local Testing codelab.
Have questions?
- If you have a question about Bidding and Auction Services, open an issue in the B&A Services repository.
- If you have a question about Privacy Sandbox in general, open an issue in the privacy-sandbox-dev-support repository.