Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explainer changes for how currency-related things work #571

Merged
merged 20 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions FLEDGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ See [the in progress FLEDGE specification](https://wicg.github.io/turtledove/).
- [3.3 Metadata with the Ad Bid](#33-metadata-with-the-ad-bid)
- [3.4 Ads Composed of Multiple Pieces](#34-ads-composed-of-multiple-pieces)
- [3.5 Filtering and Prioritizing Interest Groups](#35-filtering-and-prioritizing-interest-groups)
- [3.6 Currency Checking](#36-currency-checking)
- [4. Browsers Render the Winning Ad](#4-browsers-render-the-winning-ad)
- [5. Event-Level Reporting (for now)](#5-event-level-reporting-for-now)
- [5.1 Seller Reporting on Render](#51-seller-reporting-on-render)
- [5.2 Buyer Reporting on Render and Ad Events](#52-buyer-reporting-on-render-and-ad-events)
- [5.2.1 Noised and Bucketed Signals](#521-noised-and-bucketed-signals)
- [5.3 Losing Bidder Reporting](#53-losing-bidder-reporting)
- [5.3 Reporting in Multi-Currency Auctions](#53-reporting-in-multi-currency-auctions)
- [5.4 Losing Bidder Reporting](#54-losing-bidder-reporting)


## Summary
Expand Down Expand Up @@ -275,6 +277,10 @@ const myAuctionConfig = {
'https://www.another-buyer.com': 345,
'*': 456,
...},
'perBuyerCurrencies': {'https://example.co.uk': 'GBP',
'https://example.fr': 'EUR',
'*': 'USD'},
'sellerCurrency:' : 'CAD',
'componentAuctions': [
{'seller': 'https://www.some-other-ssp.com',
'decisionLogicURL': ...,
Expand Down Expand Up @@ -315,6 +321,8 @@ Optionally, `sellerExperimentGroupId` can be specified by the seller to support

Optionally, `perBuyerPrioritySignals` is an object mapping string keys to Javascript numbers that can be used to dynamically compute interest group priorities before `perBuyerGroupLimits` are applied. See [Filtering and Prioritizing Interest Groups](#35-filtering-and-prioritizing-interest-groups) for more information.

Optionally, `perBuyerCurrencies` and `sellerCurrency` are used for [currency-checking](#36-currency-checking). `sellerCurrency` is also used to [homogenize reporting in multi-currency auctions](#53-reporting-in-multi-currency-auctions).

Optionally, `resolveToConfig` is a boolean directing the promise returned from `runAdAuction()` to resolve to a `FencedFrameConfig` if true, for use in a `<fencedframe>`, or if false to an opaque `urn:uuid` URL, for use in an `<iframe>`. If `resolveToConfig` is not set, it defaults to false.
If the `window.FencedFrameConfig` interface is not exposed (because e.g., the script is running in an older version of Chrome that does not yet implement `FencedFrameConfig`, then the auction will _always_ yield a URN.
Therefore, when requesting a `FencedFrameConfig` for use in a fenced frame element, you have two options:
Expand Down Expand Up @@ -354,6 +362,8 @@ scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals,
directFromSellerSignals) {
...
return {desirability: desirabilityScoreForThisAd,
incomingBidInSellerCurrency:
convertToEuros(bid, browserSignals.bidCurrency),
allowComponentAuction: componentAuctionsAllowed};
}
```
Expand All @@ -374,6 +384,7 @@ The function gets called once for each candidate ad in the auction. The argumen
'https://cdn.com/next_ad_component_of_bid',
...],
'biddingDurationMsec': 12,
'bidCurrency': 'USD', /* bidCurrency returned by generateBid, or '???' if none */
'dataVersion': 1, /* Data-Version value from the trusted scoring signals server's response */
}
```
Expand All @@ -384,6 +395,7 @@ The function gets called once for each candidate ad in the auction. The argumen
The output of `scoreAd()` is an object with the following fields:
* desirability: Number indicating how desirable this ad is. Any value that is zero or negative indicates that the ad cannot win the auction. (This could be used, for example, to eliminate any interest-group-targeted ad that would not beat a contextually-targeted candidate.) The winner of the auction is the ad object which was given the highest score.
* allowComponentAuction: (optional) If the bid being scored is from a component auction and this value is not true, the bid is ignored. If not present, this value is considered false. This field must be present and true both when the component seller scores a bid, and when that bid is being scored by the top-level auction.
* incomingBidInSellerCurrency: (optional) Provides a conversion of a bid in a multi-currency auction to seller's own currency. Please see [the section on this functionality](#53-reporting-in-multi-currency-auctions) for more details.
JensenPaul marked this conversation as resolved.
Show resolved Hide resolved

If `scoreAd()` returns only a numeric value, it's equivalent to returning {`desirability`: numericValue, `allowComponentAuction`: false}.

Expand All @@ -405,6 +417,7 @@ Seller scripts in component auctions behave a little differently. They still ex
* desirability: Numeric score of the bid. Must be positive or the ad will be rejected.
* allowComponentAuction: If this field is not true, the bid will be rejected.
* bid: (optional) Modified bid value to provide to the top-level seller script. If present, this will be passed to the top-level seller's `scoreAd()` and `reportResult()` methods instead of the original bid, if the ad wins the component auction and top-level auction, respectively.
* bidCurrency: (optional) Annotates the currency of the modified bid provided by `bid`. Please see the [Currency Checking section](#36-currency-checking)

Once all of a component auction's bids have been scored by the component auction's seller script, the bid with the highest score is passed to the top-level seller to score. For that bid, the top-level seller's `scoreAd()` method is passed the `ad` value from the component auction seller's `scoreAd()` method, and there is an additional `componentSeller` field in the `browserSignals`, which is the seller for the component auction. All other values are the same as if the bid had come from an interest group participating directly in the top-level auction. In the case of a tie, one of the highest scoring bids will be chosen randomly and only that bid will be passed to the top-level seller to score. The seller of a component auction may reject all bids by giving them scores <= 0. In that case, no bid from that component auction will be passed to the top-level auction.

Expand Down Expand Up @@ -540,6 +553,7 @@ generateBid(interestGroup, auctionSignals, perBuyerSignals,
return {'ad': adObject,
'adCost': optionalAdCost,
'bid': bidValue,
'bidCurrency': 'USD',
'render': renderURL,
'adComponents': [adComponent1, adComponent2, ...],
'allowComponentAuction': false,
Expand Down Expand Up @@ -580,6 +594,7 @@ The output of `generateBid()` contains the following fields:
* ad: (optional) Arbitrary metadata about the ad which this interest group wants to show. The seller uses this information in its auction and decision logic. If not present, it's treated as if the value were null.
* adCost: (optional) A numerical value used to pass reporting advertiser click or conversion cost from generateBid to reportWin. The precision of this number is limited to an 8-bit mantissa and 8-bit exponent, with any rounding performed stochastically.
* bid: A numerical bid that will enter the auction. The seller must be in a position to compare bids from different buyers, therefore bids must be in some seller-chosen unit (e.g. "USD per thousand"). If the bid is zero or negative, then this interest group will not participate in the seller's auction at all. With this mechanism, the buyer can implement any advertiser rules for where their ads may or may not appear. While this returned value is expected to be a JavaScript Number, internal calculations dealing with currencies should be done with integer math that more accurately represent powers of ten.
* bidCurrency: (optional) The currency for the bid, used for [currency-checking](#36-currency-checking).
* render: A URL which will be rendered to display the creative if this bid wins the auction.
* adComponents: (optional) A list of up to 20 adComponent strings from the InterestGroup's adComponents field. Each value must match an adComponent renderURL exactly. This field must not be present if the InterestGroup has no adComponent field. It is valid for this field not to be present even when adComponents is present. (See ["Ads Composed of Multiple Pieces"](#34-ads-composed-of-multiple-pieces) below.)
* allowComponentAuction: If this buyer is taking part of a component auction, this value must be present and true, or the bid is ignored. This value is ignored (and may be absent) if the buyer is part of a top-level auction.
Expand Down Expand Up @@ -669,6 +684,16 @@ The `BidFor240Minutes` interest group will have a positive priority if it was jo

The `FilterOnDataFromServer` interest group will result in fetching `https://buyer1.com/bidder_signals?publisher=<...>&interest_groups=FilterOnDataFromServer,<...>`, and then if that result has a `perInterestGroupData.FilterOnDataFromServer.priorityVector` object, then that is used just like the `priorityVector` field from the other two examples, except that it's only used for filtering, not to set the priority (unless the group has a true `enableBiddingSignalsPrioritization` field). A [user defined function](https://github.com/privacysandbox/fledge-docs/blob/main/key_value_service_trust_model.md#support-for-user-defined-functions-udfs) could be used on the FLEDGE Key-Value server to calculate that `priorityVector` value, and hence to decide if `FilterOnDataFromServer`'s `generateBid()` method is invoked or if it's filtered out.

### 3.6 Currency Checking

If participants in the auction need to deal with multiple currencies, they can optionally take advantage of automated currency checking. All of it operates on currency tags, which are required to contain 3 upper-case ASCII letters.

If the `generateBid()` method returns a `bidCurrency`, and the `perBuyerCurrencies` for that buyer is specified, their consistency will be checked, and if there is a mismatch, the bid will be dropped. Both the `perBuyerCurrencies` for that buyer and returned `bidCurrency` must be present for checking to take place; if one or both are missing the currency check does not take place and the bid is passed on as-is. The returned `bidCurrency` will be passed to `scoreAd()`'s `browserSignals.bidCurrency`, with unspecified currency rendered as `'???'`.

Currency checking after `scoreAd()` happens only inside component auctions. If the component seller's `scoreAd()` modifies the bid value, the modified bid's currency will be checked; if not, the passed-through bid from the original buyer's currency will be. In either case, the currency will be checked both against the component auction's `sellerCurrency` and top-level auction's `perBuyerCurrencies` as applied to the component auction's seller. As before, both the bid currency and the configured currency in question must be specified for the checking to take place; if one or both are missing that particular currency check does not take place. If there is a mismatch, the bid will not take part in the top-level auction.

`sellerCurrency` also has an extensive effect on how reporting behaves. Please see the section on [Reporting in Multi-Currency Auctions](#53-reporting-in-multi-currency-auctions) for more details.

### 4. Browsers Render the Winning Ad

The winning ad will be rendered in a [Fenced Frame](https://github.com/shivanigithub/fenced-frame): a mechanism under development for rendering a document in an embedded context which is unable to communicate with the surrounding page. This communication blockage is necessary to meet the privacy goal that sites cannot learn about their visitors' ad interests. (Note that the microtargeting prevention threshold alone is not enough to address this threat: the threshold prevents ads which could identify a single person, but it allows ads which identify a group of people that share a single interest.)
Expand Down Expand Up @@ -719,14 +744,17 @@ The arguments to this function are:
'componentSeller': 'https://www.some-other-ssp.com',
'interestGroupOwner': 'https://www.example-dsp.com/',
'renderURL': 'https://cdn.com/url-of-winning-creative.wbn',
'bid:' bidValue,
'bid': bidValue,
'bidCurrency': 'USD',
'desirability': desirabilityScoreForWinningAd,
'topLevelSellerSignals': outputOfTopLevelSellersReportResult,
'dataVersion': versionFromKeyValueResponse,
'modifiedBid': modifiedBidValue,
'highestScoringOtherBid': highestScoringOtherBidValue
'highestScoringOtherBid': highestScoringOtherBidValue,
'highestScoringOtherBidCurrency': 'EUR'
}
```
* `bidCurrency` and `highestScoringOtherBidCurrency` provide (highly redacted) information on what currency the corresponding numbers are in. Please refer to the section on [Reporting in Multi-Currency Auctions](#53-reporting-in-multi-currency-auctions) for more details.
JensenPaul marked this conversation as resolved.
Show resolved Hide resolved
* directFromSellerSignals is an object that may contain the following fields:
* sellerSignals: Like auctionConfig.sellerSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?sellerSignals`.
* auctionSignals: Like auctionConfig.auctionSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?auctionSignals`.
Expand Down Expand Up @@ -784,7 +812,26 @@ When `joinCount` is passed to `generateBid()`, no noising or bucketing is applie

These signals were requested in [issue 435](https://github.com/WICG/turtledove/issues/435). The signals are intented to ship in Chrome M114, they will no longer be available for event level reporting when event level reporting is retired.

#### 5.3 Losing Bidder Reporting
#### 5.3 Reporting in Multi-Currency Auctions

In auctions that involve multiple currencies, there may be values with different units floating around, which makes aggregated information incomprehensible, and event-level information hard to process, potentially requiring participants to interpret currencies of jurisdictions they do no business in.

To help deal with this scenario, an optional mode is available that converts all bid-related information to seller's preferred currency (in component auctions, reporting for it is for that component's seller). This is configured via the `sellerCurrency` setting in each auction configuration.

Regardless of configuration, the bid price passed to `reportWin()` and `reportResult()` is always the bid price that participated in that particular level of the auction (which, for top-level auction `reportResult()`, may be the bid price altered by the component auction seller's `scoreAd()`), subject to the usual rounding rules. Since passing the returned currency tags around could leak an unacceptable amount of information, the values provided for `browserSignals.bidCurrency` to those methods are the currencies required by the auction configuration (i.e. `sellerCurrency` and `perBuyerCurrencies`), or `'???'` if unspecified.

(Warning: `reportResult` did not follow this rule in Chrome earlier than M116)

All other values, including `highestScoringOtherBid` and winning bids provided to private aggregation and debug event-level loss reporting depend on the `sellerCurrency` setting. We refer to those usages as "potentially mixed currency" contexts, as they can involve information from multiple bids, and hence potentially multiple currencies.
JensenPaul marked this conversation as resolved.
Show resolved Hide resolved

If `sellerCurrency` is not set, all bid prices in potentially mixed currency contexts are passed as-is, and all the corresponding currency tags (`bidCurrency`, `highestScoringOtherBidCurrency`) are redacted to `'???'`.

If `sellerCurrency` is set, `scoreAd()` for an auction is responsible for converting bids not already in that currency to `sellerCurrency`, via the `incomingBidInSellerCurrency` field of its return value. A bid already explicitly in the seller's currency cannot be changed by `incomingBidInSellerCurrency`. If neither the original bid is explicitly in `sellerCurrency` nor an `incomingBidInSellerCurrency` is specified, a value of 0 is used for reporting in potentially mixed currency contexts. All currency tags for reporting in those potentially mixed currency contexts will be set to `sellerCurrency`.
JensenPaul marked this conversation as resolved.
Show resolved Hide resolved

Note that `incomingBidInSellerCurrency` is different from the modified bid returned by a component auction: it represents a mechanical currency translation of the original buyer's bid, rather than the bid the component auction is making in a top-level auction (which could, perhaps, be reduced by the intermediate seller's fee or the like). It can also be specified in top-level auctions, unlike the modified bid.


#### 5.4 Losing Bidder Reporting

We also need to provide a mechanism for the _losing_ bidders in the auction to learn aggregate outcomes. Certainly they should be able to count the number of times they bid, and losing ads should also be able to learn (in aggregate) some seller-provided information about e.g. the auction clearing price. Likewise, a reporting mechanism should be available to buyers who attempted to bid with a creative that had not yet reached the k-anonymity threshold.

Expand Down
6 changes: 6 additions & 0 deletions FLEDGE_extended_PA_reporting.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ Where `signalBucket` and `signalValue` is a dictionary which consists of:
* 6: indicates seller rejected bid because “Creative Filtered - Language Exclusions”
* 7: indicates seller rejected bid because “Creative Filtered - Category Exclusions”
* 8: indicates seller rejected bid because "Creative Filtered - Did Not Meet The K-anonymity Threshold"
* 9: indicates bid produced by `generateBid()` was rejected because it failed a currency check (e.g. the bid returned by `generateBid()` doesn't match
what's specified by `perBuyerCurrency`)
* 10: indicates bid passed through or altered by `scoreAd()` was rejected
because it failed a currency check (e.g. the bid returned or passed through
by `scoreAd()` in a component auction doesn't match the `sellerCurrency` of
its auction or the `perBuyerCurrency` required by the top-level auction)
* Perhaps other values indicating:
* generateBid() hitting timeout
* The auction was aborted (i.e. calling endAdAuction())
Expand Down
Loading