Skip to content

Latest commit

 

History

History
520 lines (425 loc) · 22.1 KB

bidding_auction_event_level_reporting.md

File metadata and controls

520 lines (425 loc) · 22.1 KB

FLEDGE has been renamed to Protected Audience API. To learn more about the name change, read the blog post.

Protected Audience event level reporting with Bidding and Auction services

Author:
Rashmi Rao, Google Privacy Sandbox

Bidding and Auction services outlines a way to allow Protected Audience auctions to take place in a trusted execution environment (TEE) hosted on a supported cloud platform.

This explainer describes the system design for event level reporting using the Bidding and Auction services. For high level design, ad tech specifications, API, refer to the Bidding and Auction services explainer.

Overview

The seller and the winning buyer each have an opportunity to generate URLs for event-level reporting based on an auction outcome.

Reporting with Bidding and Auction services is planned to be supported in multiple phases.

Reporting support with Bidding and Auction services Timeline
Win reporting for Single Seller Auctions LAUNCHED
Win reporting for Device Orchestrated Multi Seller Auctions. LAUNCHED
Win reporting for Server Orchestrated Multi Seller Auctions. Jan 2025
Private Aggregation API June 2025

This document details the design to generate and ping win reporting URLs with the Bidding and Auction services for single-seller auctions. The reporting URLs are generated from JavaScript using the reportResult() function provided by the seller and reportWin() function provided by the buyer on the Auction service. Final pings to the URLs happen on the client.

This design supports win reporting on Android and Chrome. The design also supports fenced frame reporting, also known as interaction reporting or beacon reporting.

Background

A Bidding and Auction service enables processing Protected Auction requests on the server. Sellers provide the code required for scoring ads and reporting URL generation using the scoreAd() and reportResult() functions. Buyers provide the code for generating the bids and reporting using the generateBid() and reportWin() functions. The flow of Bidding and Auction services is as follows:

  • The seller sends a SelectAd request to the SellerFrontEnd service.
  • The service orchestrates requests in parallel to the buyers' BuyerFrontEnd services for Protected Auction bidding.
  • The buyers generate bids and return the bids to the seller.
  • The SellerFrontEnd service calls the Auction service with the bids and scoring signals obtained from the seller's Key-Value service.
  • The Auction service scores the bids and determines the winner.
  • The Auction service returns the winning ad to the SellerFrontEnd service.
  • The SellerFrontEnd service encrypts the auction result and returns a SelectAdResponse to the seller's ad service.
  • Seller's ad service sends the encrypted auction result back to the client.

After scoring ads and determining a winner, the reportResult() and reportWin() functions generate the reporting URLs. The client must ping these URLs after an ad is rendered.

The reportResult specification

The seller-provided endpoint for scoreAd() contains the reportResult() function.

reportResult(auctionConfig, sellerReportingSignals){
…
  return signalsForWinner
}

The arguments for reportResult() are described in the following table:

Argument JSON Object subfield Description
auctionConfig auctionSignals Contextual signals passed from seller's ad service to the SellerFrontEnd service in SelectAdRequest.AuctionConfig
signalsForWinner Contextual signals passed from seller's ad service to the SellerFrontEnd service in SelectAdRequest.AuctionConfig
sellerReportingSignals interestGroupOwner DSP / buyer domain.
renderURL Ad render URL of winning bid.
bid Value of bid that scored highest.
desirability Score of winning bid.

Note: Winning bid refers to the bid with the highest score.
highestScoringOtherBid This is the value of a bid with the second highest score in the auction. This value represents eCPM (effective cost per thousand impressions), valued in US dollars.

Note:
  • A higher bid value can get a lower score, so it is possible this bid value is higher than "highest scoring bid".
  • Rejected bids are not included.
  • If more than one bid has the second highest score, then the 'highestScoringOtherBid' is randomly selected.
  • This value will be 0 if there was only 1 bid.
topWindowHostName This is the host name of the publisher.

The reportResult() function returns signalsForWinner, which is used as input for the buyer's reportWin() function.

The reportWin specification

The buyer-provided endpoint for generateBid() is expected to contain the reportWin() function.

reportWin(auctionSignals, perBuyerSignals, signalsForWinner, buyerReportingSignals) {
  ...
}

The arguments for `reportWin() are described in the following table:

Argument JSON Object Subfield Description
auctionSignals Contextual signals passed from the seller's ad service to the SellerFrontEnd service in SelectAdRequest.AuctionConfig.
signalsForWinner Signals returned by seller's ReportResult() function execution.
perBuyerSignals Contextual signals passed from the seller's ad service to the SellerFrontEnd service in SelectAdRequest.AuctionConfig. This is the buyer signals for the winning buyer.
buyerReportingSignals seller Seller's origin. This will be passed to the Auction service from the SellerFrontEnd service.
adCost An optional field returned by generateBid(), rounded to fit into a floating point number with an 8 bit mantissa and 8 bit exponent for reporting.
interestGroupName The name of the interest group corresponding to the highest scoring bid.
madeHighestScoringOtherBid This is set to true if the winning buyer was the only buyer that made bids with the second highest score.
recency Duration of time (in minutes) from when this device joined this interest group until now. This is passed by the client.
modelingSignals Sent as an output from the generateBid() function. This is expected to be a single integer value.
joinCount The number of times the given device has joined the same interest group in the last 30 days, while the interest group has been continuously stored.

Note:

  • buyerReportingSignals additionally contains all the signals present in the sellerReportingSignals.
  • The recency, modelingSignals and joinCount fields are noised using the noising scheme described here. The parameters bid, desirability and adCost will be rounded to a floating point number with an 8 bit mantissa and 8 bit exponent. Currently the noising can be enabled by setting ENABLE_REPORT_WIN_INPUT_NOISING to true. However, this flag will be removed and noise will be applied by default in B&A from Beta 2.
  • The bid, score, and adCost fields are stochastically rounded.
  • browserSignals in the signature of on-device implementation has been renamed to sellerReportingSignals for reportResult and buyerReportingSignals for reportWin. The reason we changed the name of the argument is because this is actually reporting signals that is not generated by the browser in case of B&A but by the TEE based Auction server based on different parameters. The contents of browserSignals (for on-device) and seller/buyerReportingSignals are the same.
  • The feature support for buyer_and_seller_reporting_id and selectable_buyer_and_seller_reporting_id in ad properties were recently introduced with on-device Protected Audience auctions. These signals are expected to be used instead of interestGroupName if present. For the server side implementation, these fields will need to be fetched from an AdTech's Key/Value server so that the payload (encrypted ProtectedAuctionInput) from the device doesn't increase. This requires a detailed design to ensure there is no significant increase in latency and costs for the Adtechs.

Reporting function

In the short-term, reportResult() and reportWin() reporting are run by calling a sendReportTo() API. The sendReportTo() function can be called at most once during a function's execution. Eventually, reporting will also support the Private Aggregation API.

The executable code in Roma contains a sendReportTo() function which takes a single string argument representing a URL:

sendReportTo = function(url){
  // Stores the url in a global variable
}

Fenced Frame reporting

Ad techs can register URLs that correspond to events or beacons when reportResult() and reportWin() are run. These beacons can be used to trigger pings using the reportEvent API on the client.

The beacons can be registered by calling the registerAdBeacon() function, which will be a part of the executable code in Roma:

registerAdBeacon = function(interactionUrlMap){
  // Stores the map to a global variable.
}

The input to registerAdBeacon is expected to be a JSON object with a mapping of the event string to a corresponding URL.

Design

The high level flow for reporting is as follows:

  • The client and buyer send the required signals for reporting to the The SellerFrontEnd service.
  • The SellerFrontEnd service sends the required signals to run reportResult() and reportWin() to the Auction service
  • Auction service executes the reportResult() and reportWin() functions in Roma and returns the reporting URLs to The SellerFrontEnd service.
  • The SellerFrontEnd service encodes the reporting URLs using CBOR encoding for both buyer and seller and adds it to the SelectAdResponse. The reportResult() and reportWin() functions are executed serially in a single dispatch call after the winner has been determined.
  • Clients use these URLs to ping the buyer and seller reporting endpoints after the ad is rendered.

Rationale for the design choices

Why is the reporting URL generation done on the server?

The inputs to the reporting functions include large signals such as:

  • Auction config
  • Per-buyer signals

The response payload will significantly increase (potentially by 30kb or more) if reporting URL generation is performed on the client, leading to an increase in the cost and latency. Server-generated reporting URLs are lightweight and don't affect the response payload size.

Why is the buyer's reportWin function executed on the seller's auction

server?

The reporting function execution can happen only after the ads are scored and the winner is determined. The reportWin() function call depends on an output of the reportResult() function called signalsForWinner(). If reportWin() needs to be executed on the buyer's Bidding service, an RPC from the SellerFrontEnd service to BuyerFrontEnd service is needed to fetch the URLs. This adds significant latency on the critical response path (>50ms) and additional network costs to both buyer and seller.

BuyerReportingId

buyerReportingId is one of the interest group attributes which is input to reportWin via buyerReportingSignals. If set, the interestGroupName in buyerReportingSignals will not be set. The buyerReportingId is expected to be returned in the response from generateBid for every bid. This value is not obtained from the device due to payload optimization.

GenerateBid() API changes

generateBid(interestGroup, auctionSignals, perBuyerSignals,
    trustedBiddingSignals, browserSignals, directFromSellerSignals) {
  ...
  return {'adCost': …,
          'bid': …,
          'bidCurrency': …,
          'render': …,
          'adComponents': [...],
          'allowComponentAuction': …,
          'modelingSignals': …,
          'buyerReportingId': “...”};
}

API changes

The reporting URLs and beacon URL map for both the seller and the buyer are sent to the client in a SelectAdResponse.

These URLs are CBOR-encoded and encrypted before sending the response from the SellerFrontEnd service.

Message AdScore {
...
// The reporting URLs registered during the execution of reportResult() and
// reportWin().
WinReportingUrls win_reporting_urls = 10;
...
std::string buyer_reporting_id = 19;
}

message WinReportingUrls {

message ReportingUrls {
// The url to be pinged for reporting win to the buyer or seller.
string reporting_url = 1;
// The map of (interactionKey, URI).
map<string, string> interaction_reporting_urls = 2;
}

// The reporting URLs registered during the execution of
// reportWin(). These URLs will be pinged from the client.
ReportingUrls buyer_reporting_urls = 1;

// The reporting URLs registered during the execution of reportResult() of the
// seller in case of single seller auction and component seller in case of
// multi seller auctions. These URLs will be pinged from the client.
ReportingUrls component_seller_reporting_urls = 2;

// The reporting URLs registered during the execution of reportResult() of the
// top level seller in case of multi seller auction. These URLs will be pinged
// from the client. This will not be set for single seller auctions.
ReportingUrls top_level_seller_reporting_urls = 3;
}

SFE

buyer_reporting_id for the winning buyer will be sent back to the client in the SelectAdResponse.

Flags

Reporting function execution is enabled by 2 flags on the server:

  • enableReportResultUrlGeneration: To enable executing the reportResult() function
  • enableReportWinUrlGeneration: To enable executing the reportWin() function.

If enableReportResultUrlGeneration is set to false, neither of the functions are executed.

Code fetch and loading

The code executed in the auction service is loaded only once at startup time, and periodically every few hours (as configured by the developer) in the Auction service from endpoints where the ad tech's reporting code modules are hosted.

The function name to be called is determined at run time before the dispatch request. The code is periodically fetched from public endpoints provided by the seller and buyer. The code loaded into Roma should to contain the following functions:

  • scoreAd()
  • reportResult()
  • reportWin() for all buyers. reportWin() is called only for the winner.

The reportWin() functions are loaded if enableReportWinUrlGeneration has been set to true.

Note: Try to keep reportWin() in a separate code module from generateBid(), so that a seller can only fetch the partner buyers' reportWin() code modules.

ReportWin udf endpoint validation

The Buyer reportWin() UDF URL on the Auction Service will be validated as per the following criteria:

If the udf endpoint fails the validation, the buyer reportWin() function will not be loaded into Roma or executed on the Auction service. An error log will be printed. However the winner will still be returned to the client.

JavaScript wrapper

The reportResult function is called using a wrapper JavaScript function such as:

function reportResultEntryFunction(auctionConfig, sellerReportingSignals, directFromSellerSignals, enable_logging) {
…
const ps_report_result_response = {
        signalsForWinner : "null",
        reportResultUrl : "",
        interactionReportingUrls : {},
      }
…
      return {
        response: ps_report_result_response,
        logs: ps_logs,
        errors: ps_errors,
        warnings: ps_warns
      }

}

The reportWin function is called using a wrapper JavaScript function such as:

function reportWinEntryFunction(auctionSignals, perBuyerSignals, signalsForWinner, buyerReportingSignals, directFromSellerSignals, enable_logging) {
…
  const ps_report_win_response = {
    reportWinUrl: '',
    interactionReportingUrls: {},
    sendReportToInvoked: false,
    registerAdBeaconInvoked: false,
  };
…
reportWin(
        auctionSignals, perBuyerSignals, signalsForWinner,
        buyerReportingSignals, directFromSellerSignals);

…
  return {
    response: ps_report_win_response,
    buyerLogs: ps_logs,
    buyerErrors: ps_errors,
    buyerWarnings: ps_warns
  };
}

During each function call, the ad tech can log information or error messages using console.log ,console.warn and console.error functions. These logs are exported in the response from the wrapper. Log capture is enabled only if user-consented debugging is enabled.

During each function call, the ad tech can log information or error messages using console.log and console.error functions. These logs are exported in the response from the wrapper. Log capture is enabled only if the server side flag enableAdTechCodeLogging is set to true. In the future, the logging will be controlled by an additional user-consented debugging flag.

Client side

Chrome and Android will extract the reporting URLs and beacon URL map from the ProtectedAudience (encrypted AuctionResult) response. Upon rendering of the ad, reporting URLs are pinged based on the client controlled flag. Clients are expected to do an additional check to verify if the domain of the reporting URLs belong to the seller's or buyer's domain. The buyer_reporting_id returned in encrypted AuctionResult will be validated by the client with the buyerReportingId present as a part of the interest group attributes stored on-device. If the ids don’t match, the win reporting urls will be dropped.