Сервисы торгов и аукционов (B&A) — это набор сервисов для покупателей и продавцов рекламы, работающих в доверенной среде выполнения (TEE) для проведения аукциона с защищенной аудиторией (PA). В этом руководстве для разработчиков объясняется, как продавец может интегрировать сервис с аукционом Chrome PA для B&A.
Пошаговое руководство

Эти шаги можно кратко описать следующим образом:
- Вызовите метод
getInterestGroupAdAuctionData(), чтобы получить зашифрованные данные из браузера. - Вызовите функцию
fetch('https://your-ad-server.example')и отправьте запрос на унифицированный аукцион с зашифрованными данными на ваш SAS. - Вызовите операцию
SelectAd()из вашего SAS в модуле SFE, чтобы запустить аукцион B&A. - Верните на страницу результат аукциона B&A вместе с хешем ответа.
- Для запуска аукциона PA с одним, смешанным или многосторонним участием вызывайте
runAdAuction()в браузере и передавайте результат серверного аукциона B&A в этот вызов.
Получите зашифрованные данные аукциона рекламы.

Для получения данных, необходимых для запуска серверного аукциона «Покупка и продажа», JavaScript-код продавца на странице издателя вызывает navigator.getInterestGroupAdAuctionData() .
const adAuctionData = await navigator.getInterestGroupAdAuctionData({
seller: 'https://ssp.example', // Required
requestSize: 51200,
coordinatorOrigin: 'https://publickeyservice.pa.gcp.privacysandboxservices.com/',
perBuyerConfig: {
'https://dsp-x.example': { targetSize: 8192 },
'https://dsp-y.example': { targetSize: 8192 }
}
});
const { requestId, request } = adAuctionData;
| Поле | Описание |
|---|---|
seller | Обязательно . Источник продавца, проводящего аукцион. Это значение должно совпадать со значением seller в последующем вызове функции runAdAuction() . |
requestSize | Необязательный параметр . Задает максимальный размер полезной нагрузки всех данных покупателя. Подробнее см. раздел « Размер запроса» в пояснительной записке. |
perBuyerConfig | Необязательный параметр . Задает параметры для каждого покупателя, а также контролирует, какие покупатели участвуют в аукционе «Покупка и продажа». Если в параметре |
targetSize | Необязательный параметр, если задан параметр requestSize . Обязательный параметр , если в параметре perBuyerConfig указан источник покупателя, но requestSize не задан.Устанавливает максимальный размер полезной нагрузки данных этого покупателя. Подробнее см. раздел « Размер запроса» в пояснительной записке. |
coordinatorOrigin | Необязательный параметр , но в конечном итоге он станет обязательным. По умолчанию, если он не задан, используется https://publickeyservice.pa.gcp.privacysandboxservices.com .Задает координатор, используемый для получения ключа для шифрования данных. Подробнее см. раздел «Координатор» в пояснительной записке. |
При выполнении вызова браузер считывает группы интересов покупателей, указанные в perBuyerConfig , и шифрует данные покупателей. Эти данные покупателей содержат межсайтовую информацию, используемую для торгов, и не могут быть расшифрованы вне TEE. Для оптимизации полезной нагрузки в нее включаются только имя группы интересов, доверенные ключи сигналов торгов и сигналы браузера.
В объекте данных аукциона рекламы, возвращаемом вызовом getInterestGroupAdAuctionData() , доступны строка requestId и зашифрованный массив байтов request .

Строка requestId используется позже при вызове runAdAuction() для завершения аукциона в браузере. Зашифрованный request отправляется в службу размещения рекламы продавца как часть единого запроса на аукцион.
Чтобы увидеть пример такого вызова, посмотрите JavaScript-код продавца в локальном тестовом приложении .
Отправьте единый запрос на аукцион в SAS.

Единый запрос на аукцион — это запрос, содержащий контекстную полезную нагрузку аукциона в открытом виде и полезную нагрузку аукциона PA B&A. Полезная нагрузка аукциона PA B&A — это зашифрованные данные request , сгенерированные браузером в вызове getInterestGroupAdAuctionData() . Этот запрос отправляется в SAS, где осуществляется координация контекстного аукциона и аукциона PA B&A.
fetch('https://ssp.example/ad-auction', {
method: 'POST',
adAuctionHeaders: true,
body: JSON.stringify({
contextualAuctionPayload: { somePayload },
protectedAudienceAuctionPayload: encodeBinaryData(request)
}),
});
Для отправки запроса в SAS со страницы выполняется вызов функции fetch() :
- В вызов необходимо включить опцию
adAuctionHeaders: true, которая указывает браузеру на необходимость проверки ответа на этот вызов позднее, когда будет вызванrunAdAuction()для завершения аукциона в браузере. - Источник запроса на получение данных должен совпадать с источником
seller, указанным в вызовахgetInterestGroupAdAuctionData()иrunAdAuction().
Тело вызова содержит:
- Текстовый код контекстного аукциона, используемый SAS для проведения контекстного аукциона.
- Зашифрованные данные аукциона Protected Audience, которые SAS отправляет в SFE для запуска серверного аукциона B&A.
Чтобы увидеть пример такого вызова, посмотрите JavaScript-код продавца в локальном тестовом приложении .
Кодирование и декодирование Base64
Зашифрованный request , возвращаемый вызовом getInterestGroupAdAuctionData() представляет собой экземпляр типа данных Uint8Array , который не поддерживает формат JSON. Для отправки массива байтов в формате JSON можно применить кодирование base64 к двоичным данным, чтобы преобразовать их в строку.
API браузера JavaScript предоставляет функции atob() и btoa() для window , которые преобразуют двоичные данные в закодированную в base64 строку ASCII. ( atob означает преобразование ASCII в двоичные данные, а btoa — преобразование двоичных данных в ASCII).
Вызов функции btoa() для кодирования двоичных данных в строку, закодированную в формате Base64, выглядит следующим образом:
function encodeBinaryData(data) {
return btoa(String.fromCharCode.apply(null, data));
}
Результат зашифрованного аукциона B&A, возвращаемый этим вызовом функции fetch , также закодирован в base64, поэтому вам необходимо декодировать его обратно в двоичные данные. Вызовите функцию atob() для декодирования закодированной в base64 строки ASCII в двоичные данные:
function decodeBase64String(base64string) {
return new Uint8Array(
atob(base64string)
.split('')
.map((char) => char.charCodeAt(0))
);
}
Однако строка, закодированная в base64, обычно примерно на 33% больше исходных данных. Если вы хотите еще больше снизить задержку, используйте формат, отличный от JSON, для отправки двоичных данных.
Обратитесь в службу поддержки SFE SelectAd для проведения аукциона по продаже и покупке недвижимости.

После того как служба Seller Ad Service получит единый запрос на аукцион со страницы, сначала запускается контекстный аукцион, чтобы определить победителя контекстного аукциона и собрать сигналы покупателей, которые будут переданы в аукцион PA B&A. Затем аукцион B&A инициируется путем вызова операции SelectAd службы SFE из SAS с полезной нагрузкой запроса. Обратите внимание, что некоторые метаданные из запроса страницы к SAS на шаге №2 передаются в SFE.
Сформируйте полезную нагрузку SelectAdRequest
Полезная нагрузка запроса при вызове SelectAd может быть сформирована следующим образом:
const selectAdRequest = {
auction_config: {
seller: 'https://ssp.example',
auction_signals: '{"testKey":"someValue"}',
seller_signals: '{"testKey":"someValue"}',
buyer_list: [
'https://dsp-x.example',
'https://dsp-y.example',
],
per_buyer_config: {
'https://dsp-x.example': { buyer_signals: '{"testKey": "someValue"}' },
'https://dsp-y.example': { buyer_signals: '{"testKey": "someValue"}' },
},
},
client_type: 'CLIENT_TYPE_BROWSER',
protected_auction_ciphertext: decodeBase64string(request)
};
Обратите внимание, что если зашифрованные данные аукциона рекламы из браузера были закодированы в формате base64, их необходимо декодировать обратно в двоичные данные, если запрос к SFE отправляется с использованием gRPC. Если запрос отправляется с использованием HTTP, то зашифрованные данные аукциона рекламы могут оставаться в закодированном в base64 виде.
Чтобы увидеть другие поля, определенные в запросе SelectAd , см. определение протокола SelectAdRequest .
Установите поле "Продавец" верхнего уровня для аукционов смешанного типа и по отдельным компонентам.
Если продавец проводит аукцион в смешанном режиме или участвует в аукционе с участием нескольких продавцов в качестве продавца компонентов, поле top_level_seller необходимо определить в запросе.
Если вы являетесь продавцом, работающим в смешанном режиме, значение top_level_seller указывает на ваш источник:
const selectAdRequest = {
auction_config: {
seller: 'https://ssp-mix.example',
top_level_seller: 'https://ssp-mix.example',
}
}
Если вы являетесь продавцом компонентов, значение top_level_seller — это продавец верхнего уровня в аукционе с участием нескольких продавцов:
const selectAdRequest = {
auction_config: {
seller: 'https://ssp-mix.example',
top_level_seller: 'https://ssp-top.example',
}
}
Позвоните в SelectAd компании SFE.
Вызов SFE из SAS может осуществляться с использованием gRPC или HTTP.
вызов gRPC
При использовании Express в Node с gRPC-клиентом запрос к SFE выглядит следующим образом:
import grpc from '@grpc/grpc-js';
// Load proto definition
const packageDefinition = protoLoader.loadSync(protoPath, { keepCase: true, enums: String });
const {
privacy_sandbox: {
bidding_auction_servers: { SellerFrontEnd }
}
} = grpc.loadPackageDefinition(packageDefinition);
// Instantiate the gRPC client
const sfeGrpcClient = new SellerFrontEnd('192.168.84.104:50067', grpc.credentials.createInsecure());
// Send SelectAd request
sfeGrpcClient.selectAd(selectAdRequest,(error, response) => {
// Handle SFE response
});
Прототип клиента SFE можно найти в локальном репозитории тестового приложения .
HTTP-запрос к прокси-серверу Envoy.
HTTP POST-запрос к SFE отправляется по пути /v1/selectAd и выглядит следующим образом:
fetch('https://ssp-ba.example/sfe/v1/selectAd', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(selectAdRequest),
});
Пересылаемые метаданные
Следующие метаданные из вызова SAS со страницы следует добавить к вызову SelectAd сервиса SFE:
-
Accept-Language -
User-Agent - IP-адрес
При отправке метаданных в SFE необходимо использовать следующие нестандартные заголовки, поскольку gRPC может изменять заголовок User-Agent :
-
X-Accept-Language -
X-User-Agent -
X-BnA-Client-IP
Ниже приведён пример того, как метаданные можно передавать с помощью Express в Node.js с использованием gRPC-клиента :
sellerAdService.post('/ad-auction', (req, res) => {
// …
const metadata = new grpc.Metadata();
metadata.add('X-Accept-Language', req.header('Accept-Language'));
metadata.add('X-User-Agent', req.header('User-Agent'));
metadata.add('X-BnA-Client-IP', req.ip);
const sfeGrpcClient = createSfeGrpcClient();
sfeGrpcClient.selectAd(selectAdRequest, metadata, callbackFn);
})
Ниже приведён пример того, как метаданные могут быть переданы с помощью HTTP-запроса:
sellerAdService.post('/ad-auction', (req, res) => {
// …
fetch('https://ssp-ba.example/sfe/v1/selectAd', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Accept-Language': req.header('Accept-Language'),
'X-User-Agent': req.header('User-Agent'),
'X-BnA-Client-IP': req.ip
},
body: JSON.stringify(selectAdRequest)
});
})
Аукцион с участием нескольких продавцов, управляемый сервером
Если вы являетесь продавцом верхнего уровня, управляющим многопользовательским аукционом, организуемым сервером , вызов GetComponentAuctionCiphertexts в SFE выполняется до вызова SelectAd . Ответ содержит повторно зашифрованные данные аукциона компонентов, которые отправляются в рекламные сервисы продавцов компонентов. Возвращенные результаты аукциона компонентов B&A передаются в вызов SelectAd в SFE продавца верхнего уровня.
Подробнее можно узнать в разделе " Объяснение работы с несколькими продавцами" на GitHub.
Верните результаты аукциона B&A на эту страницу.

После завершения аукциона B&A зашифрованный результат аукциона возвращается в SAS, и SAS отвечает на запрос унифицированного аукциона со страницы на шаге #2 зашифрованным результатом аукциона. В ответе SAS на страницу в заголовке ответа Ad-Auction-Result устанавливается закодированный в base64url хеш SHA-256 зашифрованного результата аукциона. Этот хеш используется браузером для проверки полезной нагрузки при завершении аукциона на стороне клиента.
Создание хеша SHA-256 с кодировкой base64 в Node.js выглядит следующим образом:
import { createHash } from 'crypto';
createHash('sha256')
.update(binaryData, 'base64')
.digest('base64url');
Добавление хеша в заголовок ответа и возврат результата аукциона на страницу выглядит следующим образом:
sellerAdService.post('/ad-auction', (req, res) => {
// …
sfeGrpcClient.selectAd(selectAdRequest, metadata, (error, response) => {
const { auction_result_ciphertext } = response;
const ciphertextShaHash = createHash('sha256')
.update(auction_result_ciphertext, 'base64')
.digest('base64url');
res.set('Ad-Auction-Result', ciphertextShaHash);
res.json({
protectedAudienceAuctionResult: encodeBinaryData(auction_result_ciphertext),
contextualAuctionResult: getContextualAuctionResult()
});
});
})
Поскольку это ответ на единый запрос аукциона, отправленный со страницы на шаге №2 , контекстный результат аукциона также включен в ответ.
В Ad-Auction-Result можно указать несколько хешей, повторив заголовок или разделив хеши. Следующие два заголовка ответа эквивалентны:
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=,9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=
Ad-Auction-Result: 9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Чтобы увидеть пример такого вызова, см. код сервера продавца в локальном тестовом приложении .
Вызовите функцию runAdAuction() для завершения аукциона.

Единый ответ аукциона, возвращаемый SAS, включает зашифрованный результат аукциона B&A. Эта полезная нагрузка передается в вызов runAdAuction() для завершения аукциона в браузере. Значение requestId из вызова getInterestGroupAdAuctionData() на шаге #1 также передается в аукцион.
// Get the encrypted ad auction data (Step #1)
const { requestId, request } = navigator.getInterestGroupAdAuctionData(adAuctionDataConfig)
// Send unified auction request (Step #2)
const response = await fetch('https://ssp-ba.example/ad-auction', {
method: 'POST',
body: JSON.stringify({
adAuctionRequest: encodeBinaryData(request),
}),
});
const { protectedAudienceAuctionResult } = await response.json();
// Finish the auction in the browser
await navigator.runAdAuction({
// pass in "requestId" and "protectedAudienceAuctionResult"
// the config structure will differ based on the auction configuration
});
Структура конфигурации аукциона, передаваемой в вызов runAdAuction() различается в зависимости от конфигурации аукциона, выбранной продавцом.
Аукцион с одним продавцом
Для проведения аукциона «покупка-продажа» с одним продавцом конфигурация аукциона в вызове runAdAuction() формируется следующим образом:
await navigator.runAdAuction({
seller: 'https://ssp-ba.example',
requestId,
serverResponse: protectedAudienceAuctionResult,
});
Поле requestId принимает requestId , возвращаемый вызовом getInterestGroupAdAuctionData() . Поле serverResponse принимает массив байтов аукциона B&A, который был выполнен на шаге #3 .
Чтобы увидеть пример такого вызова, посмотрите JavaScript-код продавца в локальном тестовом приложении .
Аукцион в смешанном режиме
Для запуска смешанного аукциона «Купить и купить», в котором могут участвовать как покупатели на устройстве, так и покупатели, приобретающие товары через аукцион, конфигурация аукциона в вызове runAdAuction() формируется следующим образом:
await navigator.runAdAuction({
seller: 'https://ssp-mix.example',
decisionLogicURL: 'https://ssp-mix.example/score-ad.js',
componentAuctions: [
// B&A auction result
{
seller: 'https://ssp-mix.example',
requestId,
serverResponse: protectedAudienceAuctionResult,
},
// On-device auction config
{
seller: 'https://ssp-mix.example',
decisionLogicURL: 'https://ssp-mix.example/on-device-score-ad.js',
interestGroupBuyers: [
'https://dsp-a.example', // On-device buyer
'https://dsp-a.example', // On-device buyer
],
},
]
});
Для обеспечения работы аукциона в смешанном режиме результат аукциона B&A и конфигурация аукциона на устройстве передаются в поле componentAuctions . В аукционе в смешанном режиме значение seller одинаково как для конфигурации верхнего уровня, так и для конфигураций компонентов.
Чтобы увидеть пример такого вызова, посмотрите JavaScript-код продавца в локальном тестовом приложении .
Аукцион с участием нескольких продавцов
Если вы являетесь продавцом высшего уровня и проводите аукцион с участием нескольких продавцов, управляемый устройством, то каждый продавец компонентов предоставляет результаты своего аукциона B&A, а также конфигурации аукциона на устройстве.
await navigator.runAdAuction({
seller: 'https://ssp-top.example',
decisionLogicURL: 'https://ssp-top.example/score-ad.js',
componentAuctions: [
// SSP-BA's B&A-only auction result
{
seller: 'https://ssp-ba.example',
requestId: 'g8312cb2-da2d-4e9b-80e6-e13dec2a581c',
serverResponse: Uint8Array(560) [193, 120, 4, …] // Encrypted B&A auction result
},
// SSP-MIX's B&A auction result
{
seller: 'https://ssp-mix.example',
requestId: 'f5135cb2-da2d-4e9b-80e6-e13dec2a581c',
serverResponse: Uint8Array(560) [133, 20, 4, …] // Encrypted B&A auction result
}.
// SSP-MIX's on-device auction config
{
seller: 'https://ssp-mix.example',
interestGroupBuyers: ['https://dsp-a.example', 'https://dsp-b.example'],
decisionLogicURL: 'https://ssp-mix.example/score-ad.js',
}
// SSP-OD's on-device auction config
{
seller: 'https://ssp-od.example',
interestGroupBuyers: ['https://dsp-a.example', 'https://dsp-b.example'],
decisionLogicURL: 'https://ssp-od.example/score-ad.js',
}
]
})
Чтобы увидеть пример такого вызова, посмотрите JavaScript-код продавца в локальном тестовом приложении .
Следующие шаги
После прочтения этого руководства вы можете предпринять следующие шаги:
Узнать больше
- Для более подробного понимания ознакомьтесь со следующими пояснениями на GitHub:
- Узнайте больше об архитектуре B&A для веб-разработки.
- Поэкспериментируйте с защищенной аудиторией в B&A, следуя инструкциям из практического руководства по сквозному локальному тестированию .
Есть вопросы?
- Если у вас есть вопрос о сервисах торгов и аукционов, создайте заявку в репозитории B&A Services .