Tích hợp với B&A với tư cách là người bán

Dịch vụ Đặt giá thầu và Phiên đấu giá (B&A) là một bộ dịch vụ dành cho người mua và người bán quảng cáo, chạy trong Môi trường thực thi đáng tin cậy (TEE) để hỗ trợ phiên đấu giá Protected Audience (PA). Hướng dẫn dành cho nhà phát triển này giải thích cách người bán có thể tích hợp với phiên đấu giá PA của Chrome cho B&A.

Hướng dẫn từng bước

Quy trình tích hợp của người bán, trong đó mã JavaScript nhận được tải trọng phiên đấu giá B&A được gửi đến SAS và SAS chuyển tiếp yêu cầu đến Giao diện người dùng của người bán (SFE). SFE trả về kết quả mà SAS sẽ chuyển tiếp đến trình duyệt và mã JavaScript của người bán gọi runAdAuction

Các bước có thể được tóm tắt như sau:

  1. Gọi getInterestGroupAdAuctionData() để lấy tải trọng đã mã hoá từ trình duyệt
  2. Gọi fetch('https://your-ad-server.example') và gửi yêu cầu đấu giá hợp nhất cùng với tải trọng đã mã hoá đến SAS
  3. Gọi toán tử SelectAd() của SFE từ SAS để chạy phiên đấu giá B&A
  4. Trả về kết quả phiên đấu giá B&A cho trang cùng với hàm băm của phản hồi
  5. Gọi runAdAuction() trong trình duyệt để chạy phiên đấu giá PA một người bán, chế độ kết hợp hoặc nhiều người bán, đồng thời truyền kết quả phiên đấu giá B&A phía máy chủ vào lệnh gọi

Nhận dữ liệu phiên đấu giá quảng cáo đã mã hoá

Sơ đồ hướng dẫn tương tự với bước đầu tiên được làm nổi bật, tức là khi mã JavaScript của người bán gọi getInterestGroupAdAuctionData

Để lấy dữ liệu cần thiết cho việc chạy phiên đấu giá B&A phía máy chủ, mã JavaScript của người bán trên trang nhà xuất bản sẽ gọi 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;
Trường Mô tả
seller Bắt buộc. Nguồn gốc của người bán đang chạy phiên đấu giá. Giá trị này phải khớp với giá trị seller trong lệnh gọi runAdAuction() sau này.
requestSize Không bắt buộc. Đặt kích thước tải trọng tối đa của tất cả dữ liệu người mua. Hãy xem phần kích thước yêu cầu trong nội dung giải thích để tìm hiểu thêm.
perBuyerConfig Không bắt buộc. Đặt cấu hình cho từng người mua, đồng thời kiểm soát những người mua tham gia phiên đấu giá B&A.

Nếu nguồn gốc của người mua được liệt kê trong perBuyerConfig, thì chỉ dữ liệu nhóm mối quan tâm của người mua đó mới được đưa vào tải trọng. Nếu không có người mua nào được liệt kê trong perBuyerConfig, thì tất cả các nhóm mối quan tâm của người dùng sẽ được đưa vào tải trọng.

targetSize Không bắt buộc nếu bạn đặt requestSize. Bắt buộc nếu bạn đặt nguồn gốc của người mua trong perBuyerConfig nhưng không đặt requestSize.

Đặt kích thước tải trọng tối đa của dữ liệu của người mua đó. Hãy xem phần kích thước yêu cầu trong nội dung giải thích để tìm hiểu thêm.

coordinatorOrigin Không bắt buộc, nhưng cuối cùng sẽ bắt buộc. Mặc định là https://publickeyservice.pa.gcp.privacysandboxservices.com khi không được đặt.

Đặt trình điều phối để sử dụng cho việc tìm nạp khoá nhằm mã hoá tải trọng. Hãy xem phần trình điều phối trong nội dung giải thích để tìm hiểu thêm.

Khi lệnh gọi được thực hiện, trình duyệt sẽ đọc các nhóm mối quan tâm của người mua được liệt kê trong perBuyerConfig và mã hoá dữ liệu của người mua. Dữ liệu người mua này chứa thông tin trên nhiều trang web để dùng cho tính năng đặt giá thầu và không thể giải mã bên ngoài TEE. Để tối ưu hoá tải trọng, tải trọng chỉ bao gồm tên nhóm mối quan tâm, khoá tín hiệu đặt giá thầu đáng tin cậy và tín hiệu trình duyệt.

Trong đối tượng dữ liệu phiên đấu giá quảng cáo do lệnh gọi getInterestGroupAdAuctionData() trả về, bạn có thể sử dụng chuỗi requestId và mảng byte request đã mã hoá.

Ảnh chụp màn hình Chrome DevTools cho thấy yêu cầu và mã yêu cầu có trong dữ liệu phiên đấu giá quảng cáo

Chuỗi requestId được sử dụng sau này khi runAdAuction() được gọi để kết thúc phiên đấu giá trong trình duyệt. Tải trọng request đã mã hoá được gửi đến Dịch vụ quảng cáo của người bán trong yêu cầu phiên đấu giá hợp nhất.

Để xem ví dụ về lệnh gọi này, hãy xem mã JavaScript của người bán trong ứng dụng kiểm thử cục bộ.

Gửi yêu cầu phiên đấu giá hợp nhất đến SAS

Biểu đồ hướng dẫn tương tự với bước thứ hai được làm nổi bật, đó là khi mã JavaScript của người bán gửi một yêu cầu đấu giá hợp nhất đến SAS

Yêu cầu đấu giá hợp nhất là yêu cầu chứa tải trọng đấu giá theo bối cảnh ở dạng văn bản thuần tuý và tải trọng đấu giá B&A của Protected Audience. Tải trọng phiên đấu giá B&A PA là dữ liệu request đã mã hoá mà trình duyệt tạo ra trong lệnh gọi getInterestGroupAdAuctionData(). Yêu cầu này được gửi đến SAS, nơi phiên đấu giá theo bối cảnh và phiên đấu giá B&A PA được điều phối.

fetch('https://ssp.example/ad-auction', {
  method: 'POST',
  adAuctionHeaders: true,
  body: JSON.stringify({
    contextualAuctionPayload: { somePayload },
    protectedAudienceAuctionPayload: encodeBinaryData(request)
  }),
});

Để gửi yêu cầu đến SAS, một lệnh gọi fetch() sẽ được thực hiện từ trang:

  • Lệnh gọi phải bao gồm tuỳ chọn adAuctionHeaders: true. Tuỳ chọn này sẽ báo hiệu cho trình duyệt xác minh phản hồi của lệnh gọi này vào lúc khác khi runAdAuction() được gọi để kết thúc phiên đấu giá trong trình duyệt.
  • Nguồn gốc của yêu cầu tìm nạp phải khớp với nguồn gốc seller được cung cấp cho các lệnh gọi getInterestGroupAdAuctionData()runAdAuction().

Nội dung của lệnh gọi chứa:

  1. Trọng tải phiên đấu giá theo bối cảnh ở dạng văn bản thuần tuý mà SAS sẽ sử dụng để chạy phiên đấu giá theo bối cảnh.
  2. Tải trọng phiên đấu giá Protected Audience đã mã hoá sẽ được SAS gửi đến SFE để chạy phiên đấu giá B&A phía máy chủ.

Để xem ví dụ về lệnh gọi này, hãy xem mã JavaScript của người bán trong ứng dụng kiểm thử cục bộ.

Mã hoá và giải mã Base64

Tải trọng request đã mã hoá được trả về từ lệnh gọi getInterestGroupAdAuctionData() là một thực thể của Uint8Array, đây là một loại dữ liệu mà JSON không thể xử lý. Để gửi mảng byte ở định dạng JSON, bạn có thể áp dụng phương thức mã hoá base64 cho dữ liệu nhị phân để chuyển đổi dữ liệu đó thành một chuỗi.

API trình duyệt JavaScript cung cấp các hàm atob()btoa() trên window để chuyển đổi giữa dữ liệu nhị phân và chuỗi ASCII được mã hoá base64. (atob có nghĩa là ASCII sang nhị phân và btoa có nghĩa là nhị phân sang ASCII).

Gọi btoa() để mã hoá dữ liệu nhị phân thành một chuỗi được mã hoá base64 như sau:

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

Kết quả phiên đấu giá B&A được mã hoá được trả về từ lệnh gọi fetch này cũng ở dạng mã hoá base64, vì vậy, bạn cần giải mã kết quả đó trở lại thành dữ liệu nhị phân. Gọi atob() để giải mã chuỗi ASCII được mã hoá base64 thành dữ liệu nhị phân:

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

Tuy nhiên, một chuỗi được mã hoá base64 thường lớn hơn dữ liệu ban đầu khoảng 33%. Nếu bạn muốn cải thiện thêm độ trễ, hãy sử dụng một định dạng khác ngoài JSON để gửi dữ liệu nhị phân.

Gọi SelectAd của SFE để chạy phiên đấu giá B&A

Sơ đồ hướng dẫn tương tự với bước thứ ba được làm nổi bật, đó là khi SAS gửi yêu cầu SelectAd đến SFE và SFE chạy phiên đấu giá B&A

Sau khi Dịch vụ quảng cáo của người bán nhận được yêu cầu phiên đấu giá hợp nhất từ trang, phiên đấu giá theo bối cảnh sẽ chạy trước để xác định người chiến thắng phiên đấu giá theo bối cảnh và thu thập các tín hiệu của người mua để chuyển vào phiên đấu giá B&A PA. Sau đó, phiên đấu giá B&A được bắt đầu bằng cách gọi thao tác SelectAd của SFE từ SAS với tải trọng yêu cầu. Lưu ý rằng một số siêu dữ liệu từ yêu cầu của trang đến SAS ở bước 2 sẽ được chuyển tiếp đến SFE.

Tạo tải trọng SelectAdRequest

Bạn có thể tạo tải trọng yêu cầu của lệnh gọi SelectAd như sau:

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

Xin lưu ý rằng nếu dữ liệu phiên đấu giá quảng cáo đã mã hoá từ trình duyệt được mã hoá base64, thì dữ liệu đó cần được giải mã trở lại thành dữ liệu nhị phân nếu yêu cầu gửi đến SFE được gửi bằng gRPC. Nếu yêu cầu được gửi bằng HTTP, thì dữ liệu phiên đấu giá quảng cáo đã mã hoá có thể vẫn ở dạng được mã hoá base64.

Để xem các trường khác được xác định trong yêu cầu SelectAd, hãy xem định nghĩa proto của SelectAdRequest.

Đặt trường người bán cấp cao nhất cho phiên đấu giá ở chế độ kết hợp và phiên đấu giá thành phần

Nếu người bán đang chạy phiên đấu giá ở chế độ kết hợp hoặc tham gia với tư cách là người bán thành phần trong phiên đấu giá nhiều người bán, thì bạn cần xác định trường top_level_seller trong yêu cầu.

Nếu bạn là người bán ở chế độ kết hợp, thì giá trị top_level_seller là nguồn gốc của bạn:

const selectAdRequest = {
  auction_config: {
    seller: 'https://ssp-mix.example',
    top_level_seller: 'https://ssp-mix.example',
  }
}

Nếu bạn là người bán thành phần, thì giá trị top_level_seller là người bán cấp cao nhất của phiên đấu giá nhiều người bán:

const selectAdRequest = {
  auction_config: {
    seller: 'https://ssp-mix.example',
    top_level_seller: 'https://ssp-top.example',
  }
}

Gọi SelectAd của SFE

Bạn có thể thực hiện lệnh gọi đến SFE từ SAS bằng gRPC hoặc HTTP.

Lệnh gọi gRPC

Yêu cầu gRPC đến SFE có dạng như sau khi sử dụng Express trong Node với ứng dụng gRPC:

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

Bạn có thể tìm thấy định nghĩa proto cho ứng dụng SFE trong kho lưu trữ ứng dụng kiểm thử cục bộ.

Lệnh gọi HTTP đến proxy Envoy

Yêu cầu POST HTTP đến SFE được gửi đến đường dẫn /v1/selectAd và có dạng như sau:

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

Chuyển tiếp siêu dữ liệu

Bạn nên thêm siêu dữ liệu sau đây từ lệnh gọi của trang đến SAS vào lệnh gọi SelectAd của SAS đến SFE:

Khi siêu dữ liệu được gửi đến SFE, siêu dữ liệu phải sử dụng các tiêu đề không chuẩn sau đây vì gRPC có thể thay đổi tiêu đề User-Agent:

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

Sau đây là ví dụ về cách chuyển tiếp siêu dữ liệu bằng Express trong Node bằng ứng dụng 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);
})

Sau đây là ví dụ về cách chuyển tiếp siêu dữ liệu bằng lệnh gọi 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)
  });
})

Phiên đấu giá nhiều người bán do máy chủ điều phối

Nếu bạn là người bán cấp cao nhất đang chạy phiên đấu giá nhiều người bán do máy chủ điều phối, thì lệnh gọi GetComponentAuctionCiphertexts sẽ được thực hiện đến SFE trước khi lệnh gọi SelectAd được thực hiện. Phản hồi chứa tải trọng phiên đấu giá thành phần được mã hoá lại được gửi đến dịch vụ quảng cáo của người bán thành phần. Kết quả phiên đấu giá quảng cáo B&A của thành phần được trả về được cung cấp cho lệnh gọi SelectAd của SFE của người bán cấp cao nhất.

Hãy xem nội dung giải thích về nhiều người bán trên GitHub để tìm hiểu thêm.

Trả về kết quả phiên đấu giá B&A cho trang

Sơ đồ hướng dẫn tương tự với bước thứ tư được làm nổi bật, đó là khi SAS gửi kết quả phiên đấu giá của SelectAd trở lại trình duyệt

Sau khi phiên đấu giá B&A kết thúc, kết quả phiên đấu giá đã mã hoá sẽ được trả về SAS và SAS sẽ phản hồi yêu cầu phiên đấu giá hợp nhất từ trang trong bước 2 bằng kết quả phiên đấu giá đã mã hoá. Trong phản hồi SAS cho trang, hàm băm SHA-256 được mã hoá base64url của kết quả phiên đấu giá đã mã hoá được đặt trong tiêu đề phản hồi Ad-Auction-Result. Hàm băm này được trình duyệt sử dụng để xác minh tải trọng khi kết thúc phiên đấu giá trong ứng dụng.

Cách tạo hàm băm SHA-256 bằng cách mã hoá base64 trong Node như sau:

import { createHash } from 'crypto';

createHash('sha256')
  .update(binaryData, 'base64')
  .digest('base64url');

Việc đính kèm hàm băm trong tiêu đề phản hồi và trả về kết quả phiên đấu giá cho trang sẽ có dạng như sau:

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

Vì đây là phản hồi cho yêu cầu phiên đấu giá hợp nhất được thực hiện từ trang ở bước 2, nên kết quả phiên đấu giá theo bối cảnh cũng có trong phản hồi.

Bạn có thể đưa nhiều hàm băm vào Ad-Auction-Result bằng cách lặp lại tiêu đề hoặc tách các hàm băm. Hai tiêu đề phản hồi sau đây tương đương nhau:

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

Để xem ví dụ về lệnh gọi này, hãy xem mã máy chủ của người bán trong ứng dụng kiểm thử cục bộ.

Gọi runAdAuction() để hoàn tất phiên đấu giá

Sơ đồ hướng dẫn tương tự với bước thứ năm được làm nổi bật, đó là khi mã JavaScript phía máy khách chạy phiên đấu giá và cung cấp phản hồi của máy chủ

Phản hồi phiên đấu giá hợp nhất được trả về từ SAS bao gồm kết quả phiên đấu giá B&A đã mã hoá. Trọng tải này được truyền vào lệnh gọi runAdAuction() để hoàn tất phiên đấu giá trong trình duyệt. Giá trị requestId từ lệnh gọi getInterestGroupAdAuctionData()bước 1 cũng được truyền vào phiên đấu giá.

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

Cấu trúc của cấu hình phiên đấu giá được truyền vào lệnh gọi runAdAuction() sẽ khác nhau tuỳ thuộc vào cấu hình phiên đấu giá mà người bán chọn.

Phiên đấu giá của một người bán

Để chạy phiên đấu giá B&A của một người bán, cấu hình phiên đấu giá của lệnh gọi runAdAuction() được tạo như sau:

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

Trường requestId chấp nhận requestId do lệnh gọi getInterestGroupAdAuctionData() trả về. Trường serverResponse chấp nhận một mảng byte của phiên đấu giá B&A đã chạy trong bước 3.

Để xem ví dụ về lệnh gọi này, hãy xem mã JavaScript của người bán trong ứng dụng kiểm thử cục bộ.

Phiên đấu giá ở chế độ kết hợp

Để chạy phiên đấu giá B&A ở chế độ kết hợp, trong đó cả người mua trên thiết bị và người mua B&A đều có thể tham gia, cấu hình phiên đấu giá của lệnh gọi runAdAuction() được tạo như sau:

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

Để tạo điều kiện cho phiên đấu giá ở chế độ kết hợp, kết quả phiên đấu giá B&A và cấu hình phiên đấu giá trên thiết bị sẽ được truyền vào trường componentAuctions. Trong phiên đấu giá ở chế độ kết hợp, giá trị seller giống nhau cho cả cấu hình cấp cao nhất và cấu hình thành phần.

Để xem ví dụ về lệnh gọi này, hãy xem mã JavaScript của người bán trong ứng dụng kiểm thử cục bộ.

Phiên đấu giá nhiều người bán

Nếu bạn là người bán cấp cao nhất đang chạy phiên đấu giá nhiều người bán do thiết bị điều phối, thì mỗi người bán thành phần sẽ gửi kết quả phiên đấu giá B&A và cấu hình phiên đấu giá trên thiết bị.

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

Để xem ví dụ về lệnh gọi này, hãy xem mã JavaScript của người bán trong ứng dụng kiểm thử cục bộ.

Các bước tiếp theo

Sau khi đọc hướng dẫn này, bạn có thể thực hiện các bước tiếp theo:

Tìm hiểu thêm

Bạn có câu hỏi?