販売者として B&A と統合する

入札とオークション(B&A)サービスは、広告の購入者と販売者向けのサービス群です。高信頼実行環境(TEE)で実行され、Protected Audience(PA)オークションを促進します。このデベロッパー ガイドでは、販売者が B&A 向けの Chrome PA オークションを統合する方法について説明します。

チュートリアル

販売者の統合フロー。JavaScript コードが SAS に送信される B&A オークション ペイロードを取得し、SAS がリクエストを販売者フロントエンド(SFE)に転送します。SFE は、SAS がブラウザに転送する結果を返します。販売者の JavaScript コードは runAdAuction を呼び出します。

手順の概要は次のとおりです。

  1. getInterestGroupAdAuctionData() を呼び出して、ブラウザから暗号化されたペイロードを取得する
  2. fetch('https://your-ad-server.example') を呼び出して、暗号化されたペイロードを含む統合オークション リクエストを SAS に送信します。
  3. SAS から SFE の SelectAd() オペレーションを呼び出して、B&A オークションを実行する
  4. レスポンスのハッシュとともに、B&A オークションの結果をページに返す
  5. ブラウザで runAdAuction() を呼び出して、単一販売者、混合モード、または複数販売者の PA オークションを実行し、サーバーサイドの B&A オークションの結果を呼び出しに渡します。

暗号化された広告オークション データを取得する

同じチュートリアルの図で、最初のステップ(販売者の JavaScript コードが getInterestGroupAdAuctionData を呼び出すステップ)がハイライト表示されています

パブリッシャー ページの販売者の JavaScript コードは、サーバーサイドの B&A オークションの実行に必要なデータを取得するために 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 必須。オークションを実施している販売者の所在地。この値は、後で runAdAuction() 呼び出しの seller 値と一致する必要があります。
requestSize (省略可)すべての購入者データの最大ペイロード サイズを設定します。詳しくは、説明のリクエスト サイズのセクションをご覧ください。
perBuyerConfig (省略可)購入者ごとに構成を設定し、B&A オークションに参加する購入者を制御します。

購入者のオリジンが perBuyerConfig にリストされている場合、ペイロードにはその購入者のインタレスト グループのデータのみが含まれます。perBuyerConfig に購入者がリストされていない場合、ユーザーのすべてのインタレスト グループがペイロードに含まれます。

targetSize requestSize が設定されている場合は省略可perBuyerConfig に購入者の送信元が設定されていて、requestSize が設定されていない場合は必須です。

その購入者のデータの最大ペイロード サイズを設定します。詳しくは、説明のリクエスト サイズのセクションをご覧ください。

coordinatorOrigin 省略可ですが、最終的には必須になります。設定しない場合のデフォルトは https://publickeyservice.pa.gcp.privacysandboxservices.com です。

ペイロードの暗号化に使用する鍵の取得に使用するコーディネータを設定します。詳しくは、説明のコーディネーターのセクションをご覧ください。

呼び出しが行われると、ブラウザは perBuyerConfig にリストされている購入者のインタレスト グループを読み取り、購入者データを暗号化します。この購入者データには、入札に使用されるクロスサイト情報が含まれており、TEE の外部で復号することはできません。ペイロードの最適化では、ペイロードに含まれるのは、インタレスト グループ名、信頼できる入札シグナルキー、ブラウザ シグナルのみです。

getInterestGroupAdAuctionData() 呼び出しによって返される広告オークション データ オブジェクトでは、requestId 文字列と暗号化された request バイト配列を使用できます。

広告オークション データで利用可能なリクエストとリクエスト ID を示す Chrome DevTools のスクリーンショット

requestId 文字列は、後で runAdAuction() が呼び出されたときにブラウザでオークションを終了するために使用されます。暗号化された request ペイロードは、統一オークション リクエストの一部として販売者の広告サービスに送信されます。

この呼び出しの例については、ローカル テストアプリの販売者の JavaScript コードをご覧ください。

統合オークション リクエストを SAS に送信する

同じチュートリアルの図で、2 番目のステップ(販売者の JavaScript コードが統合オークション リクエストを SAS に送信するステップ)がハイライト表示されています

統合オークション リクエストは、プレーンテキストのコンテキスト オークション ペイロードと PA B&A オークション ペイロードを含むリクエストです。PA B&A オークション ペイロードは、ブラウザが getInterestGroupAdAuctionData() 呼び出しで生成した暗号化された request データです。このリクエストは 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() が呼び出されたときにブラウザでオークションが終了し、この呼び出しのレスポンスが確認されます。
  • 取得リクエストの送信元は、getInterestGroupAdAuctionData() 呼び出しと runAdAuction() 呼び出しに指定された seller 送信元と一致している必要があります。

呼び出しの本文には次のものが含まれます。

  1. SAS がコンテキスト オークションの実行に使用する、平文のコンテキスト オークション ペイロード。
  2. サーバーサイドの B&A オークションを実行するために SAS から SFE に送信される、暗号化された Protected Audience オークション ペイロード。

この呼び出しの例については、ローカル テストアプリの販売者の JavaScript コードをご覧ください。

Base64 エンコーディングとデコーディング

getInterestGroupAdAuctionData() 呼び出しから返された暗号化された request ペイロードは Uint8Array のインスタンスであり、JSON で処理できないデータ型です。バイト配列を JSON 形式で送信するには、バイナリデータに base64 エンコードを適用して文字列に変換します。

JavaScript ブラウザ API には、バイナリデータと base64 でエンコードされた ASCII 文字列を変換する windowatob() 関数と btoa() 関数があります。(atob は ASCII からバイナリへの変換、btoa はバイナリから ASCII への変換を意味します)。

btoa() を呼び出してバイナリデータを base64 エンコード文字列にエンコードするコードは次のようになります。

function encodeBinaryData(data) {
  return btoa(String.fromCharCode.apply(null, data));
}

この fetch 呼び出しから返された暗号化された B&A オークション結果も base64 エンコードであるため、バイナリデータに戻す必要があります。atob() を呼び出して、base64 でエンコードされた ASCII 文字列をバイナリ データにデコードします。

function decodeBase64String(base64string) {
  return new Uint8Array(
    atob(base64string)
      .split('')
      .map((char) => char.charCodeAt(0))
  );
}

ただし、base64 でエンコードされた文字列は通常、元のデータよりも約 33% 大きくなります。レイテンシをさらに改善したい場合は、JSON 以外の形式を使用してバイナリデータを送信します。

SFE の SelectAd を呼び出して B&A オークションを実行する

同じチュートリアルの図で、3 つ目のステップがハイライトされています。このステップでは、SAS が SFE に SelectAd リクエストを送信し、SFE が B&A オークションを実施します。

販売者の広告サービスがページから統合オークション リクエストを受信すると、まずコンテキスト オークションが実行され、コンテキスト オークションの落札者が決定されます。また、購入者シグナルが収集され、PA B&A オークションに渡されます。次に、リクエスト ペイロードを使用して SAS から SFE の SelectAd オペレーションを呼び出して、B&A オークションを開始します。ステップ 2 のページのリクエストから SAS へのメタデータの一部は 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',
  }
}

SFE の SelectAd を呼び出す

SAS から SFE への呼び出しは、gRPC または HTTP で行うことができます。

gRPC 呼び出し

SFE への gRPC リクエストは、gRPC クライアントを使用して NodeExpress を使用すると次のようになります。

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 クライアントのプロト定義は、 ローカル テストアプリ リポジトリにあります。

Envoy プロキシへの HTTP 呼び出し

SFE への HTTP POST リクエストは /v1/selectAd パスに送信され、次のような形式になります。

fetch('https://ssp-ba.example/sfe/v1/selectAd', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(selectAdRequest),
});

メタデータを転送する

ページの SAS 呼び出しからの次のメタデータを、SAS の SFE への SelectAd 呼び出しに追加する必要があります。

gRPC が User-Agent ヘッダーを変更する可能性があるため、メタデータを SFE に送信する場合は、次の標準以外のヘッダーを使用する必要があります。

  • X-Accept-Language
  • X-User-Agent
  • X-BnA-Client-IP

gRPC クライアントを使用して NodeExpress でメタデータを転送する方法の例を次に示します。

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

サーバー オーケストレーションによるマルチセラー オークション

サーバー オーケストレート型の複数販売者オークションを実行している最上位販売者の場合、SelectAd 呼び出しの前に GetComponentAuctionCiphertexts 呼び出しが SFE に対して行われます。レスポンスには、コンポーネント販売者の広告サービスに送信される、再暗号化されたコンポーネント オークション ペイロードが含まれます。返されたコンポーネント B&A 広告オークションの結果は、最上位の販売者の SFE の SelectAd 呼び出しに提供されます。

詳しくは、GitHub の複数販売者の説明をご覧ください。

B&A オークションの結果をページに戻す

同じチュートリアル ダイアグラムで、4 番目のステップがハイライト表示されています。このステップでは、SAS が SelectAd のオークション結果をブラウザに送り返します。

B&A オークションが終了すると、暗号化されたオークション結果が SAS に返され、SAS はステップ 2 のページから統合オークション リクエストに暗号化されたオークション結果で応答します。ページに対する SAS レスポンスでは、暗号化されたオークション結果の base64url エンコードされた SHA-256 ハッシュAd-Auction-Result レスポンス ヘッダーに設定されます。このハッシュは、クライアントでオークションを終了する際に、ブラウザがペイロードを確認するために使用します。

Node で base64 エンコードを使用して SHA-256 ハッシュを作成するコードは次のようになります。

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 に複数のハッシュを含めることができます。次の 2 つのレスポンス ヘッダーは同等です。

Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=,9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=
Ad-Auction-Result: 9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=

この呼び出しの例については、ローカル テストアプリの販売者サーバー コードをご覧ください。

runAdAuction() を呼び出してオークションを完了します。

同じチュートリアルの図で、5 番目のステップがハイライト表示されています。このステップでは、クライアントサイドの JavaScript コードがオークションを実行し、サーバー レスポンスを提供します。

SAS から返される統合オークション レスポンスには、暗号化された B&A オークション結果が含まれます。このペイロードは runAdAuction() 呼び出しに渡され、ブラウザでオークションが終了します。ステップ 1getInterestGroupAdAuctionData() 呼び出しの requestId 値もオークションに渡されます。

// 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() 呼び出しに渡されるオークション構成の構造は、販売者が選択したオークション構成によって異なります。

単一販売者のオークション

単一販売者の B&A オークションを実行する場合、runAdAuction() 呼び出しのオークションは次のように構成されます。

await navigator.runAdAuction({
  seller: 'https://ssp-ba.example',
  requestId,
  serverResponse: protectedAudienceAuctionResult,
});

requestId フィールドには、getInterestGroupAdAuctionData() 呼び出しによって返された requestId を指定します。serverResponse フィールドには、ステップ 3 で実行された B&A オークションのバイト配列を指定します。

この呼び出しの例については、ローカル テストアプリの販売者の JavaScript コードをご覧ください。

混合モード オークション

オンデバイス購入者と B&A 購入者の両方が参加できる混合モードの B&A オークションを実行する場合、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 コードをご覧ください。

次のステップ

このガイドを読んだら、次のステップに進みます。

その他の情報

ご不明な点がある場合