판매자로서 B&A와 통합

입찰 서비스Protected Audience(PA) 입찰을 용이하게 하기 위해 신뢰할 수 있는 실행 환경(TEE)에서 실행되는 광고 구매자 및 판매자를 위한 서비스 모음입니다. 이 개발자 가이드에서는 판매자가 B&A를 위해 Chrome PA 입찰과 통합하는 방법을 설명합니다.

둘러보기

JavaScript 코드가 SAS로 전송되는 입찰 페이로드를 가져오고 SAS가 요청을 판매자 프런트엔드 (SFE)로 전달하는 판매자 통합 흐름 SFE는 SAS가 브라우저로 전달해야 하는 결과를 반환하고 판매자 JavaScript 코드는 runAdAuction을 호출합니다.

단계는 다음과 같이 요약할 수 있습니다.

  1. getInterestGroupAdAuctionData()를 호출하여 브라우저에서 암호화된 페이로드를 가져옵니다.
  2. fetch('https://your-ad-server.example')를 호출하고 암호화된 페이로드가 포함된 통합 입찰 요청을 SAS로 전송합니다.
  3. SAS에서 SFE의 SelectAd() 작업을 호출하여 입찰 실행
  4. 응답의 해시와 함께 입찰 결과를 페이지에 반환합니다.
  5. 브라우저에서 runAdAuction()를 호출하여 단일 판매자, 혼합 모드 또는 복수 판매자 PA 입찰을 실행하고 서버 측 입찰 결과를 호출에 전달합니다.

암호화된 광고 입찰 데이터 가져오기

판매자 JavaScript 코드가 getInterestGroupAdAuctionData를 호출하는 첫 번째 단계가 강조 표시된 동일한 둘러보기 다이어그램

서버 측 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 필수사항: 입찰을 실행하는 판매자의 출처입니다. 이 값은 나중에 runAdAuction() 호출의 seller 값과 일치해야 합니다.
requestSize 선택사항. 모든 구매자 데이터의 최대 페이로드 크기를 설정합니다. 자세한 내용은 설명의 요청 크기 섹션을 참고하세요.
perBuyerConfig 선택사항. 각 구매자의 구성을 설정하고 입찰에 참여하는 구매자를 제어합니다.

구매자 출처가 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에 통합 입찰 요청 전송

판매자 JavaScript 코드가 SAS에 통합 입찰 요청을 전송하는 두 번째 단계가 강조 표시된 동일한 둘러보기 다이어그램

통합 입찰 요청은 일반 텍스트 문맥 입찰 페이로드와 PA B&A 입찰 페이로드가 포함된 요청입니다. PA 입찰 페이로드는 브라우저가 getInterestGroupAdAuctionData() 호출에서 생성한 암호화된 request 데이터입니다. 이 요청은 문맥 입찰 및 PA 입찰이 조정되는 SAS로 전송됩니다.

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. SAS에서 서버 측 B&A 입찰을 실행하기 위해 SFE로 전송하는 암호화된 Protected Audience 입찰 페이로드입니다.

이 호출의 예는 로컬 테스트 앱의 판매자 JavaScript 코드를 참고하세요.

Base64 인코딩 및 디코딩

getInterestGroupAdAuctionData() 호출에서 반환된 암호화된 request 페이로드는 JSON에서 처리할 수 없는 데이터 유형인 Uint8Array의 인스턴스입니다. 바이트 배열을 JSON 형식으로 전송하려면 바이너리 데이터에 base64 인코딩을 적용하여 문자열로 변환하면 됩니다.

JavaScript 브라우저 API는 바이너리 데이터와 base64로 인코딩된 ASCII 문자열 간에 변환하는 windowatob()btoa() 함수를 제공합니다. (atob는 ASCII-to-binary를 의미하고 btoa는 binary-to-ASCII를 의미합니다.)

btoa()를 호출하여 바이너리 데이터를 base64로 인코딩된 문자열로 인코딩하는 방법은 다음과 같습니다.

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

fetch 호출에서 반환된 암호화된 입찰 결과도 base64 인코딩이므로 바이너리 데이터로 다시 디코딩해야 합니다. atob()를 호출하여 base64로 인코딩된 ASCII 문자열을 바이너리 데이터로 디코딩합니다.

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

그러나 base64로 인코딩된 문자열은 일반적으로 원본 데이터보다 약 33% 더 큽니다. 지연 시간을 더 개선하려면 JSON이 아닌 다른 형식을 사용하여 바이너리 데이터를 전송하세요.

SFE의 SelectAd를 호출하여 입찰 서버 입찰 실행

SAS가 SFE에 SelectAd 요청을 전송하고 SFE가 입찰을 실행하는 세 번째 단계가 강조표시된 동일한 둘러보기 다이어그램

판매자 광고 서비스가 페이지에서 통합 입찰 요청을 수신하면 먼저 문맥 입찰이 실행되어 문맥 입찰 낙찰자를 결정하고 PA B&A 입찰에 전달할 구매자 신호를 수집합니다. 그런 다음 요청 페이로드를 사용하여 SAS에서 SFE의 SelectAd 작업을 호출하여 입찰이 시작됩니다. 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에 추가해야 합니다.

메타데이터가 SFE로 전송될 때는 gRPC가 User-Agent 헤더를 변경할 수 있으므로 다음과 같은 비표준 헤더를 사용해야 합니다.

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

다음은 gRPC 클라이언트를 사용하여 Node에서 Express를 사용하여 메타데이터를 전달하는 방법의 예입니다.

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 호출 전에 SFE에 GetComponentAuctionCiphertexts 호출이 이루어집니다. 응답에는 구성요소 판매자 광고 서비스로 전송되는 재암호화된 구성요소 입찰 페이로드가 포함됩니다. 반환된 구성요소 입찰 광고 입찰 결과는 최상위 판매자의 SFE의 SelectAd 호출에 제공됩니다.

자세한 내용은 GitHub의 복수 판매자 설명을 참고하세요.

입찰 결과를 페이지로 반환

SAS가 SelectAd의 입찰 결과를 브라우저로 다시 전송하는 4단계가 강조표시된 동일한 둘러보기 다이어그램

입찰이 종료되면 암호화된 입찰 결과가 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에 여러 해시를 포함할 수 있습니다. 다음 두 응답 헤더는 동일합니다.

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

이 호출의 예는 로컬 테스트 앱의 판매자 서버 코드를 참고하세요.

runAdAuction()을 호출하여 입찰을 완료합니다.

클라이언트 측 JavaScript 코드가 입찰을 실행하고 서버 응답을 제공하는 5단계가 강조 표시된 동일한 둘러보기 다이어그램

SAS에서 반환된 통합 입찰 응답에는 암호화된 입찰 결과가 포함됩니다. 이 페이로드는 runAdAuction() 호출에 전달되어 브라우저에서 입찰을 완료합니다. 1단계getInterestGroupAdAuctionData() 호출에서 가져온 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() 호출에 전달되는 입찰 구성의 구조는 판매자가 선택한 입찰 구성에 따라 다릅니다.

단일 판매자 입찰

단일 판매자 입찰을 실행하는 경우 runAdAuction() 호출의 입찰 구성은 다음과 같이 구성됩니다.

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

requestId 필드는 getInterestGroupAdAuctionData() 호출에서 반환된 requestId를 허용합니다. serverResponse 필드는 3단계에서 실행된 입찰의 바이트 배열을 허용합니다.

이 호출의 예는 로컬 테스트 앱의 판매자 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 코드를 참고하세요.

다음 단계

이 가이드를 읽은 후 다음 단계를 따르세요.

자세히 알아보기

궁금한 점이 있으신가요?