1. Introduction
This section is non-normative
The Protected Audience API facilitates selecting an advertisement to display to a user based on a previous interaction with the advertiser or advertising network.
When a user’s interactions with an advertiser indicate an interest in something, the advertiser can
ask the browser to record this interest on-device by calling navigator
.joinAdInterestGroup()
. Later, when a website wants to select an
advertisement to show to the user, the website can call navigator
.runAdAuction()
to ask the browser to conduct an auction where
each of these on-device recorded interests are given the chance to calculate a bid to display their
advertisement.
2. Joining Interest Groups
When a user’s interactions with a website indicate that the user may have a particular interest, an
advertiser or someone working on behalf of the advertiser (e.g. a demand side platform, DSP) can ask
the user’s browser to record this interest on-device by calling navigator
.joinAdInterestGroup()
. This indicates an intent to display an
advertisement relevant to this interest to this user in the future. The user agent has an interest group set, a list of interest groups in which owner / name pairs are unique.
[SecureContext ]partial interface Navigator {Promise <undefined >joinAdInterestGroup (AuctionAdInterestGroup ); };
group dictionary {
AuctionAd required USVString ;
renderURL any ;
metadata USVString ;
buyerReportingId USVString ;
buyerAndSellerReportingId sequence <USVString >; };
allowedReportingOrigins dictionary {
GenerateBidInterestGroup required USVString ;
owner required USVString ;
name required double ;
lifetimeMs boolean =
enableBiddingSignalsPrioritization false ;record <DOMString ,double >;
priorityVector DOMString = "compatibility";
executionMode USVString ;
biddingLogicURL USVString ;
biddingWasmHelperURL USVString ;
updateURL USVString ;
trustedBiddingSignalsURL sequence <USVString >;
trustedBiddingSignalsKeys any ;
userBiddingSignals sequence <AuctionAd >;
ads sequence <AuctionAd >; };
adComponents dictionary :
AuctionAdInterestGroup GenerateBidInterestGroup {double = 0.0;
priority record <DOMString ,double >; };
prioritySignalsOverrides
AuctionAdInterestGroup
is used by navigator
.joinAdInterestGroup()
, and
when an interest group is stored to interest group set. priority
and prioritySignalsOverrides
are not passed to generateBid()
because they can be
modified by generatedBid()
calls, so could theoretically be used to create a cross-site profile of
a user accessible to generateBid()
methods, otherwise.
The joinAdInterestGroup(group)
method steps are:
Temporarily, Chromium does not include the required keyword
for lifetimeMs
, and instead starts this algorithm with the step
-
If group["
lifetimeMs
"] does not exist, throw aTypeError
.
This is detectable because it can change the set of fields that are read from the argument when a TypeError
is eventually thrown, but it will never change whether the call succeeds or fails.
-
If this's relevant global object's associated Document is not allowed to use the "join-ad-interest-group" policy-controlled feature, then throw a "
NotAllowedError
"DOMException
. -
Let frameOrigin be this's relevant settings object's origin.
-
Assert that frameOrigin is not an opaque origin and its scheme is "
https
". -
Let interestGroup be a new interest group.
-
Validate the given group and set interestGroup’s fields accordingly.
-
Set interestGroup’s expiry to the current wall time plus group["
lifetimeMs
"] milliseconds. -
Set interestGroup’s next update after to the current wall time plus 24 hours.
-
Set interestGroup’s owner to the result of parsing an origin on group["
owner
"]. -
If interestGroup’s owner is failure, or its scheme is not "
https
", throw aTypeError
. -
Optionally, throw a "
NotAllowedError
"DOMException
.Note: This implementation-defined condition is intended to allow user agents to decline for a number of reasons, for example the owner's site not being enrolled.
-
Set interestGroup’s enable bidding signals prioritization to group["
enableBiddingSignalsPrioritization
"]. -
If group["
priorityVector
"] exists, then set interestGroup’s priority vector to group["priorityVector
"]. -
If group["
prioritySignalsOverrides
"] exists, then set interestGroup’s priority signals overrides to group["prioritySignalsOverrides
"]. -
Set interestGroup’s execution mode to group["
executionMode
"]. -
For each groupMember and interestGroupField in the following table
Group member Interest group field " biddingLogicURL
"bidding url " biddingWasmHelperURL
"bidding wasm helper url " updateURL
"update url " trustedBiddingSignalsURL
"trusted bidding signals url -
If group contains groupMember:
-
Let parsedUrl be the result of running the URL parser on group[groupMember].
-
Throw a
TypeError
if any of the following conditions hold:-
parsedUrl is failure;
-
parsedUrl is not same origin with interestGroup’s owner;
-
parsedUrl includes credentials;
-
parsedUrl fragment is not null.
-
-
Set interestGroup’s interestGroupField to parsedUrl.
-
-
-
If interestGroup’s trusted bidding signals url's query is not null, then throw a
TypeError
. -
If group["
trustedBiddingSignalsKeys
"] exists, then set interestGroup’s trusted bidding signals keys to group["trustedBiddingSignalsKeys
"]. -
If group["
userBiddingSignals
"] exists:-
Set interestGroup’s user bidding signals to the result of serializing a JavaScript value to a JSON string, given group["
userBiddingSignals
"]. This can throw aTypeError
.
-
-
For each groupMember and interestGroupField in the following table
Group member Interest group field " ads
"ads " adComponents
"ad components -
If group contains groupMember, for each ad of group[groupMember]:
-
Let igAd be a new interest group ad.
-
Let renderURL be the result of running the URL parser on ad["
renderURL
"]. -
Throw a
TypeError
if any of the following conditions hold:-
renderURL is failure;
-
renderURL scheme is not "
https
"; -
renderURL includes credentials.
-
-
Set igAd’s render url to renderURL.
-
If ad["
metadata
"] exists, then let igAd’s metadata be the result of serializing a JavaScript value to a JSON string, given ad["metadata
"]. This can throw aTypeError
. -
If groupMember is "
ads
":-
If ad["
buyerReportingId
"] exists, then set igAd’s buyer reporting ID to it. -
If ad["
buyerAndSellerReportingId
"] exists, then set igAd’s buyer and seller reporting ID to it. -
If ad["
allowedReportingOrigins
"] exists:-
For each originStr in ad["
allowedReportingOrigins
"]: -
Set igAd’s allowed reporting origins to allowedReportingOrigins.
-
-
Append igAd to interestGroup’s interestGroupField.
-
-
-
-
If interestGroup’s estimated size is greater than 50 KB, then throw a
TypeError
. -
Let p be a new promise.
-
Let queue be the result of starting a new parallel queue.
-
Enqueue the following steps to queue:
-
Let permission be the result of checking interest group permissions with interestGroup’s owner, frameOrigin, and "
join
". -
If permission is false, then queue a task to reject p with a "
NotAllowedError
"DOMException
and do not run the remaining steps. -
Queue a task to resolve p with
undefined
. -
If the browser is currently storing an interest group with
owner
andname
that matches interestGroup, then set the bid counts, join counts, and previous wins of interestGroup to the values of the currently stored one and remove the currently stored one from the browser. -
Set interestGroup’s joining origin to this's relevant settings object's top-level origin.
-
Set interestGroup’s join time to the current wall time.
-
If the most recent entry in interestGroup’s join counts corresponds to the current day in UTC, increment its count. If not, insert a new tuple the time set to the current UTC day and a count of 1.
-
Store interestGroup in the browser’s interest group set.
-
-
Return p.
The estimated size of an interest group ig is the sum of:
-
The length of the serialization of ig’s owner.
-
8 bytes, which is the size of ig’s priority.
-
The length of ig’s execution mode.
-
2 bytes, which is the size of ig’s enable bidding signals prioritization.
-
If ig’s priority vector is not null, for each key → value of priority vector:
-
The length of key.
-
8 bytes, which is the size of value.
-
-
If ig’s priority signals overrides is not null, for each key → value of priority signals overrides:
-
The length of key.
-
8 bytes, which is the size of value.
-
-
The length of the serialization of ig’s bidding url, if the field is not null.
-
The length of the serialization of ig’s bidding wasm helper url, if the field is not null.
-
The length of the serialization of ig’s update url, if the field is not null.
-
The length of the serialization of ig’s trusted bidding signals url, if the field is not null.
-
For each key of ig’s trusted bidding signals keys:
-
The length of key.
-
-
The length of ig’s user bidding signals.
-
If ig’s ads is not null, for each ad of it:
-
The length of the serialization of ad’s render url.
-
The length of ad’s buyer reporting ID if the field is not null.
-
The length of ad’s buyer and seller reporting ID if the field is not null.
-
If ad’s allowed reporting origins is not null, for each origin of it:
-
The length of the serialization of origin.
-
-
-
If ig’s ad components is not null, for each ad of it:
-
The length of the serialization of ad’s render url.
-
To check interest group permissions given an origin ownerOrigin, an origin frameOrigin, and an enum joinOrLeave which is "join
" or "leave
":
-
If ownerOrigin is same origin with frameOrigin, then return true.
-
Let permissionsUrl be the result of building an interest group permissions url with ownerOrigin and frameOrigin.
-
Let request be a new request with the following properties:
- URL
-
permissionsUrl
- header list
-
«
Accept
:application/json
» - client
-
null
- origin
-
frameOrigin
- mode
-
"
cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
One of the side-effects of a
null
client for this subresource request is it neuters all service worker interceptions, despite not having to set the service workers mode. -
Let resource be null.
-
Fetch request with useParallelQueue set to true, and processResponseConsumeBody set to the following steps given a response response and null, failure, or a byte sequence responseBody:
-
If responseBody is null or failure, set resource to failure and return.
-
Let headers be response’s header list.
-
Let mimeType be the result of extracting a MIME type from headers.
-
If mimeType is failure or is not a JSON MIME Type, set resource to failure and return.
-
Set resource to responseBody.
-
-
Wait for resource to be set.
-
If resource is failure, then return false.
-
Let permissions be the result of parsing JSON bytes to an Infra value with resource, returning false on failure.
-
If permissions is not an ordered map, then return false.
-
If joinOrLeave is "
join
" and permissions["joinAdInterestGroup
"] exists, then return permissions["joinAdInterestGroup
"]. -
If joinOrLeave is "
leave
" and permissions["leaveAdInterestGroup
"] exists, then return permissions["leaveAdInterestGroup
"]. -
Return false.
The browser may cache requests for permissionsUrl within a network partition.
In order to prevent leaking data, the browser must request permissionsUrl regardless of whether the user is a member of the ad interest group. This prevents a leak of the user’s ad interest group membership to the server.
To build an interest group permissions url given a origin ownerOrigin and a origin frameOrigin:
-
Let serializedFrameOrigin be the result of serializing frameOrigin.
-
Return the string formed by concatenating
-
The serialization of ownerOrigin,
-
The string "
/.well-known/interest-group/permissions/?origin=
", and -
The result of UTF-8 percent-encoding serializedFrameOrigin using component percent-encode set.
-
3. Leaving Interest Groups
navigator
.leaveAdInterestGroup()
removes a user from a particular interest
group.
[SecureContext ]partial interface Navigator {Promise <undefined >leaveAdInterestGroup (optional AuctionAdInterestGroupKey = {}); };
group dictionary {
AuctionAdInterestGroupKey required USVString ;
owner required USVString ; };
name
The leaveAdInterestGroup(group)
method steps
are:
-
Let frameOrigin be this's relevant settings object's origin.
-
Assert that frameOrigin is not an opaque origin and its scheme is "
https
". -
Let p be a new promise.
-
If group is empty:
-
Let instance be this's relevant global object's browsing context's fenced frame config instance.
-
Let interestGroup be instance’s interest group descriptor.
-
Run these steps in parallel:
-
Queue a task to resolve p with
undefined
. -
If interestGroup is not null:
-
Let owner be interestGroup’s owner.
-
Let name be interestGroup’s name.
-
If owner is same origin with frameOrigin:
-
Remove interest groups from the user agent’s interest group set whose owner is owner and name is name.
-
-
-
-
-
Otherwise:
-
If this's relevant global object's associated Document is not allowed to use the "join-ad-interest-group" policy-controlled feature, then throw a "
NotAllowedError
"DOMException
.Note: both joining and leaving interest groups use the "join-ad-interest-group" feature.
-
Let owner be the result of parsing an origin with group["
owner
"]. -
Let name be group["
name
"]. -
Run these steps in parallel:
-
Let permission be the result of checking interest group permissions with owner, frameOrigin, and "
leave
". -
If permission is false, then queue a task to reject p with a "
NotAllowedError
"DOMException
and do not run the remaining steps. -
Queue a task to resolve p with
undefined
. -
Remove interest groups from the user agent’s interest group set whose owner is owner and name is name.
-
-
-
Return p.
4. Running Ad Auctions
When a website or someone working on behalf of the website (e.g. a supply side platform, SSP) wants
to conduct an auction to select an advertisement to display to the user, they can call the navigator
.runAdAuction()
function, providing an auction configuration that
tells the browser how to conduct the auction and which on-device recorded interests are allowed to
bid in the auction for the chance to display their advertisement.
4.1. runAdAuction()
[SecureContext ]partial interface Navigator {Promise <(USVString or FencedFrameConfig )?>runAdAuction (AuctionAdConfig ); };
config dictionary {
AuctionAdConfig required USVString ;
seller required USVString ;
decisionLogicURL USVString ;
trustedScoringSignalsURL sequence <USVString >;
interestGroupBuyers Promise <any >;
auctionSignals Promise <any >;
sellerSignals Promise <USVString >;
directFromSellerSignals unsigned long long ;
sellerTimeout unsigned short ;
sellerExperimentGroupId USVString ;
sellerCurrency Promise <record <USVString ,any >>;
perBuyerSignals Promise <record <USVString ,unsigned long long >>;
perBuyerTimeouts record <USVString ,unsigned short >;
perBuyerGroupLimits record <USVString ,unsigned short >;
perBuyerExperimentGroupIds record <USVString ,record <USVString ,double >>;
perBuyerPrioritySignals Promise <record <USVString ,USVString >>;
perBuyerCurrencies sequence <AuctionAdConfig >= [];
componentAuctions AbortSignal ?;
signal Promise <boolean >; };
resolveToConfig
The runAdAuction(config)
method steps are:
-
Let global be this's relevant global object.
-
Let settings be this's relevant settings object.
-
If global’s associated Document is not allowed to use the "run-ad-auction" policy-controlled feature, then throw a "
NotAllowedError
"DOMException
. -
Let auctionConfig be the result of running validate and convert auction ad config with config and true.
-
Let p be a new promise.
-
Let configMapping be global’s associated Document's node navigable's traversable navigable's fenced frame config mapping.
-
Let pendingConfig be the result of constructing a pending fenced frame config with auctionConfig.
-
Let urn be the result of running store a pending config on configMapping with pendingConfig.
-
If urn is failure, then resolve p with null and return p.
-
Let bidIgs be a new list of interest groups.
-
If config["
signal
"] exists, then:-
Let signal be config["
signal
"]. -
If signal is aborted, then reject p with signal’s abort reason and return p.
-
Add the following abort steps to signal:
-
Reject p with signal’s abort reason.
-
Run update bid counts with bidIgs.
-
Run interest group update with auctionConfig’s interest group buyers.
-
-
-
Let queue be the result of starting a new parallel queue.
-
Enqueue the following steps to queue:
-
Let winnerInfo be the result of running generate and score bids with auctionConfig, null, global, settings, and bidIgs.
-
If winnerInfo is failure:
-
Queue a global task on DOM manipulation task source, given global, to reject p with a "
TypeError
".
-
-
If winnerInfo is null or winnerInfo’s leading bid is null:
-
Queue a global task on DOM manipulation task source, given global, to resolve p with null.
-
-
Otherwise:
-
Let winner be winnerInfo’s leading bid.
-
Let fencedFrameConfig be the result of filling in a pending fenced frame config with pendingConfig, auctionConfig, and winnerInfo.
-
Finalize a pending config on configMapping with urn and fencedFrameConfig.
-
Wait until auctionConfig’s resolve to config is a boolean.
-
Let result be fencedFrameConfig.
-
If auctionConfig’s resolve to config is false:
-
Set result to urn.
-
-
Queue a global task on the DOM manipulation task source, given global, to resolve p with result.
-
Increment ad k-anonymity count given winner’s interest group and winner’s ad descriptor's url.
-
If winner’s ad component descriptors is not null:
-
For each adComponentDescriptor in winner’s ad component descriptors:
-
Increment component ad k-anonymity count given adComponentDescriptor’s url.
-
-
-
Increment reporting ID k-anonymity count given winner’s interest group and winner’s ad descriptor's url.
-
-
Run interest group update with auctionConfig’s interest group buyers.
-
Run update bid counts with bidIgs.
-
Run update previous wins with winner.
-
-
Return p.
To construct a pending fenced frame config given an auction config config:
-
Return a fenced frame config with the following items:
- mapped url
-
a struct with the following items:
- value
-
"about:blank"
- visibility
-
"
opaque
"
- container size
-
TODO: fill this in once container size is spec’d to be in config
- content size
-
null
- interest group descriptor
- on navigate callback
-
null
- effective sandbox flags
-
a struct with the following items:
- value
-
TODO: fill this in once fenced frame sandbox flags are more fully specified
- visibility
-
"
opaque
"
- effective enabled permissions
- fenced frame reporting metadata
-
null
- exfiltration budget metadata
-
null
- nested configs
-
a struct with the following items:
- value
-
an empty list «»
- visibility
-
"
opaque
"
- embedder shared storage context
-
null
To fill in a pending fenced frame config given a fenced frame config pendingConfig, auction config auctionConfig, and leading bid info winningBidInfo:
-
Let winningBid be winningBidInfo’s leading bid.
-
Set pendingConfig’s mapped url's value to winningBid’s ad descriptor's url.
-
Let adSize be winningBid’s ad descriptor's size.
-
If adSize is not null:
-
Set pendingConfig’s content size to a struct with the following items:
- value
-
adSize TODO: Resolve screen-relative sizes and macros and cast this properly.
- visibility
-
"
opaque
"
-
-
Set pendingConfig’s interest group descriptor's value to a struct with the following items:
- owner
-
winningBid’s interest group's owner
- name
-
winningBid’s interest group's name
-
Set pendingConfig’s fenced frame reporting metadata to a struct with the following items:
- value
-
If auctionConfig’s component auctions is empty (i.e., if there was no component auction), then a struct with the following items:
- fenced frame reporting map
-
a map «[ "
buyer
" → «», "seller
" → «»]» - direct seller is seller
-
true
Otherwise (i.e., if there was a component auction), a struct with the following items:
- fenced frame reporting map
-
a map «[ "
buyer
" → «», "seller
" → «», "component-seller
" → «»]» - direct seller is seller
-
false
- visibility
-
"
opaque
"
-
Set pendingConfig’s on navigate callback to an algorithm with these steps:
-
Asynchronously finish reporting with pendingConfig’s fenced frame reporting metadata's value's fenced frame reporting map and winningBidInfo.
-
-
Set pendingConfig’s nested configs's value to the result of running create nested configs with winningBid’s ad component descriptors.
-
Return pendingConfig.
To asynchronously finish reporting given a fenced frame reporting map reportingMap and leading bid info leadingBidInfo:
-
Let buyerDone, sellerDone, and componentSellerDone be booleans, initially false.
-
If leadingBidInfo’s component seller is null, set componentSellerDone to true.
-
-
If buyerDone, sellerDone, and componentSellerDone are all true, then break.
-
Wait until one of the following fields of leadingBidInfo being not null:
-
If buyerDone is false and leadingBidInfo’s buyer reporting result is not null:
-
Let buyerMap be leadingBidInfo’s buyer reporting result's reporting beacon map.
-
If buyerMap is null, set buyerMap to an empty map «[]».
-
Let allowedReportingOrigins be leadingBidInfo’s leading bid's bid ad's allowed reporting origins.
-
Let macroMap be leadingBidInfo’s buyer reporting result's reporting macro map.
-
TODO: Pass macroMap and allowedReportingOrigins to Finalize a reporting destination when it is updated to take the parameters. May need to convert macroMap to a list, based on what that function expects.
-
Finalize a reporting destination with reportingMap,
buyer
, and buyerMap. -
Send report to leadingBidInfo’s buyer reporting result's report url.
-
Set buyerDone to true.
-
-
If sellerDone is false and leadingBidInfo’s seller reporting result is not null:
-
Let sellerMap be leadingBidInfo’s seller reporting result's reporting beacon map.
-
If sellerMap is null, set sellerMap to an empty map «[]».
-
Finalize a reporting destination with reportingMap,
seller
, and sellerMap. -
Send report to leadingBidInfo’s seller reporting result's report url.
-
Set sellerDone to true.
-
-
If componentSellerDone is false and leadingBidInfo’s component seller reporting result is not null:
-
Let componentSellerMap be leadingBidInfo’s component seller reporting result's reporting beacon map.
-
If componentSellerMap is null, set componentSellerMap to an empty map «[]».
-
Finalize a reporting destination with reportingMap,
component-seller
, and componentSellerMap. -
Send report to leadingBidInfo’s component seller reporting result's report url.
-
Set componentSellerDone to true.
-
-
To create nested configs given ad component descriptors adComponentDescriptors:
-
Let nestedConfigs be an empty list «».
-
If adComponentDescriptors is null:
-
Return nestedConfigs.
-
-
For each adComponentDescriptor of adComponentDescriptors:
-
Let fencedFrameConfig be a fenced frame config with the following items:
- mapped url
-
a struct with the following items:
- value
-
adComponentDescriptor’s url
- visibility
-
"
opaque
"
- container size
-
null
- content size
-
If adComponentDescriptor’s size is null, then null. Otherwise, a struct with the following items:
- value
-
adComponentDescriptor’s size TODO: Resolve screen-relative sizes and macros and cast this properly.
- visibility
-
"
opaque
"
- interest group descriptor
-
null
- on navigate callback
-
null
- effective sandbox flags
-
a struct with the following items:
- value
-
TODO: fill this in once fenced frame sandbox flags are more fully specified
- visibility
-
"
opaque
"
- effective enabled permissions
- fenced frame reporting metadata
-
null
- exfiltration budget metadata
-
null
- nested configs
-
a struct with the following items:
- value
-
an empty list «»
- visibility
-
"
opaque
"
- embedder shared storage context
-
null
-
Append fencedFrameConfig to nestedConfigs.
-
-
Return nestedConfigs.
To validate and convert auction ad config given an AuctionAdConfig
config and a boolean isTopLevel:
-
Let auctionConfig be a new auction config.
-
Let seller be the result of parsing an origin with config["
seller
"]. -
If seller is failure, or its scheme is not "
https
", then throw aTypeError
. -
Optionally, throw a "
NotAllowedError
"DOMException
.Note: This implementation-defined condition is intended to allow user agents to decline for a number of reasons, for example the [=auctionConfig]'s seller’s site not being enrolled.
-
Set auctionConfig’s seller to seller.
-
Let decisionLogicURL be the result of running the URL parser on config["
decisionLogicURL
"]. -
If decisionLogicURL is failure, or it is not same origin with auctionConfig’s seller, then throw a
TypeError
. -
Set auctionConfig’s decision logic url to decisionLogicURL.
-
If config["
trustedScoringSignalsURL
"] exists:-
Let trustedScoringSignalsURL be the result of running the URL parser on config["
trustedScoringSignalsURL
"]. -
If trustedScoringSignalsURL is failure, or it is not same origin with auctionConfig’s seller, then throw a
TypeError
. -
Set auctionConfig’s trusted scoring signals url to trustedScoringSignalsURL.
-
-
If config["
interestGroupBuyers
"] exists:-
Let buyers be a new empty list.
-
For each buyerString in config["
interestGroupBuyers
"]:-
Let buyer be the result of parsing an origin with buyerString.
-
If buyer is failure, or buyer’s scheme is not "
https
", then throw aTypeError
. -
Append buyer to buyers.
-
-
Set auctionConfig’s interest group buyers to buyers.
-
-
If config["
auctionSignals
"] exists:-
Set auctionConfig’s auction signals to config["
auctionSignals
"]. -
Handle an input promise in configuration given auctionConfig and auctionConfig’s auction signals:
-
To parse the value result:
-
Let auctionSignalsJSON be the result of serializing a JavaScript value to a JSON string, given result.
-
Set auctionConfig’s auction signals to auctionSignalsJSON.
-
Set auctionConfig’s config idl["
auctionSignals
"] to result.
-
-
To handle an error:
-
Set auctionConfig’s auction signals to failure.
-
Set auctionConfig’s config idl["
auctionSignals
"] toundefined
.
-
-
-
-
If config["
sellerSignals
"] exists:-
Set auctionConfig’s seller signals to config["
sellerSignals
"]. -
Handle an input promise in configuration given auctionConfig and auctionConfig’s seller signals:
-
To parse the value result:
-
Set auctionConfig’s seller signals to the result of serializing a JavaScript value to a JSON string, given result.
-
-
To handle an error, set auctionConfig’s seller signals to failure.
-
-
-
If config["
directFromSellerSignals
"] exists:-
TODO: The receiving end of this isn’t specified yet, so there is no place to put the computed value.
-
Handle an input promise in configuration given auctionConfig and config["
directFromSellerSignals
"]:-
To parse the value result:
-
Let directFromSellerSignalsPrefix be the result of running the URL parser on result.
-
Throw a
TypeError
if any of the following conditions hold:-
directFromSellerSignalsPrefix is failure;
-
directFromSellerSignalsPrefix is not same origin with auctionConfig’s seller;
-
directFromSellerSignalsPrefix’s query is not null.
-
-
-
To handle an error:
-
TODO: set the rep in auctionConfig to failure.
-
-
-
-
If config["
sellerTimeout
"] exists, set auctionConfig’s seller timeout to config["sellerTimeout
"] in milliseconds or 500 milliseconds, whichever is smaller. -
If config["
sellerExperimentGroupId
"] exists:-
Set auctionConfig’s seller experiment group id to config["
sellerExperimentGroupId
"].
-
-
If config["
sellerCurrency
"] exists:-
If the result of checking whether a string is a valid currency tag on config["
sellerCurrency
"] is false, throw aTypeError
. -
Set auctionConfig’s seller currency to config["
sellerCurrency
"]
-
-
If config["
perBuyerSignals
"] exists:-
Set auctionConfig’s per buyer signals to config["
perBuyerSignals
"]. -
Handle an input promise in configuration given auctionConfig and auctionConfig’s per buyer signals:
-
To parse the value result:
-
Set auctionConfig’s per buyer signals to a new ordered map whose keys are origins and whose values are strings.
-
For each key → value of result:
-
Let buyer be the result of parsing an origin with key. If buyer is failure, throw a
TypeError
. -
Let signalsString be the result of serializing a JavaScript value to a JSON string, given value.
-
Set auctionConfig’s per buyer signals[buyer] to signalsString.
-
-
-
To handle an error, set auctionConfig’s per buyer signals to failure.
-
-
-
If config["
perBuyerTimeouts
"] exists:-
Set auctionConfig’s per buyer timeouts to config["
perBuyerTimeouts
"]. -
Handle an input promise in configuration given auctionConfig and auctionConfig’s per buyer timeouts:
-
To parse the value result:
-
Set auctionConfig’s per buyer timeouts to a new ordered map whose keys are origins and whose values are durations in milliseconds.
-
For each key → value of result:
-
If key is "*", then set auctionConfig’s all buyers timeout to value in milliseconds or 500 milliseconds, whichever is smaller, and continue.
-
Let buyer be the result of parsing an origin with key. If buyer is failure, throw a
TypeError
. -
Set auctionConfig’s per buyer timeouts[buyer] to value in milliseconds or 500 milliseconds, whichever is smaller.
-
-
-
To handle an error, set auctionConfig’s per buyer timeouts to failure.
-
-
-
If config["
perBuyerGroupLimits
"] exists, for each key → value of config["perBuyerGroupLimits
"]:-
If key is "*", then set auctionConfig’s all buyers group limit to value, and continue.
-
Let buyer be the result of parsing an origin with key. If buyer is failure, throw a
TypeError
. -
Set auctionConfig’s per buyer group limits[buyer] to value.
-
If config["
perBuyerExperimentGroupIds
"] exists, for each key → value of config["perBuyerExperimentGroupIds
"]:-
If key is "*", then set auctionConfig’s all buyer experiment group id to value, and continue.
-
Let buyer the result of parsing an origin with key. If buyer is failure, throw a
TypeError
. -
Set auctionConfig’s per buyer experiment group ids[buyer] to value.
-
-
If config["
perBuyerPrioritySignals
"] exists, for each key → value of config["perBuyerPrioritySignals
"]:-
Let signals be an ordered map whose keys are strings and whose values are
double
. -
for each k → v of value:
-
If k starts with "browserSignals.", throw a
TypeError
. -
Set signals[k] to v.
-
-
If key is "*", then set auctionConfig’s all buyers priority signals to value, and continue.
-
Let buyer be the result of parsing an origin with key. If it fails, throw a
TypeError
. -
Set auctionConfig’s per buyer priority signals[buyer] to signals.
-
-
If config["
perBuyerCurrencies
"] exists:-
Set auctionConfig’s per buyer currencies to config["
perBuyerCurrencies
"] -
Handle an input promise in configuration given auctionConfig and auctionConfig’s per buyer currencies:
-
To parse the value result:
-
Set auctionConfig’s per buyer currencies to a new ordered map whose keys are origins and whose values are currency tags.
-
for each key → value of result:
-
If the result of checking whether a string is a valid currency tag given value is false, throw a
TypeError
. -
If key is "*", then set auctionConfig’s all buyers currency to value, and continue.
-
Let buyer be the result of parsing an origin with key. If buyer is failure, throw a
TypeError
. -
Set auctionConfig’s per buyer currencies[buyer] to value.
-
-
-
To handle an error, set auctionConfig’s per buyer currencies to failure.
-
-
-
For each component in config["
componentAuctions
"]:-
Let componentAuction be the result of running validate and convert auction ad config with component and false.
-
Append componentAuction to auctionConfig’s component auctions.
-
Set auctionConfig’s config idl to config.
-
If config["
resolveToConfig
"] exists:-
Let auctionConfig’s resolve to config be config["
resolveToConfig
"]. -
TODO: What should happen if this rejects?
-
Upon fulfillment of auctionConfig’s resolve to config with resolveToConfig, set auctionConfig’s resolve to config to resolveToConfig.
-
-
Return auctionConfig.
To parse an origin given a string input:
-
Let url be the result of running the URL parser on input.
-
If url is failure, then return failure.
-
Return url’s origin.
To update bid count given a list of interest groups igs:
-
For each ig in igs:
-
Let loadedIg be the interest group from the user agent’s interest group set whose owner is ig’s owner and whose name is ig’s name, continue if none found.
-
If the most recent entry in loadedIg’s bid counts corresponds to the current day in UTC, increment its count. If not, insert a new tuple of the time set to the current UTC day and a count of 1.
-
Replace the interest group that has loadedIg’s owner and name in the browser’s interest group set with loadedIg.
-
To update previous wins given a generated bid bid:
-
Let ig be bid’s interest group.
-
Let loadedIg be the interest group from the user agent’s interest group set whose owner is ig’s owner and whose name is ig’s name, return if none found.
-
Let win be a new previous win.
-
Set win’s time to the current wall time.
-
Let ad be the ad descriptor from ig’s ads whose url is bid’s ad descriptor url, return if none found.
-
Set win’s ad json to the result of serializing an Infra value to a JSON string given ad.
-
Append win to loadedIg’s previous wins.
-
Replace the interest group that has loadedIg’s owner and name in the browser’s interest group set with loadedIg.
To build bid generators map given an auction config auctionConfig:
-
Let bidGenerators be a new ordered map whose keys are origins and whose values are per buyer bid generators.
-
For each buyer in auctionConfig’s interest group buyers:
-
For each ig of the user agent’s interest group set whose owner is buyer:
-
Let signalsUrl be ig’s trusted bidding signals url.
-
Let joiningOrigin be ig’s joining origin.
-
If bidGenerators does not contain buyer:
-
Let perBuyerGenerator be a new per buyer bid generator.
-
Let perSignalsUrlGenerator be a new per signals url bid generator.
-
Set perSignalsUrlGenerator[joiningOrigin] to « ig ».
-
Set perBuyerGenerator[signalsUrl] to perSignalsUrlGenerator.
-
Set bidGenerators[buyer] to perBuyerGenerator.
-
TODO: add a perBiddingScriptUrlGenerator layer that replaces the list of IGs with a map from biddingScriptUrl to a list of IGs.
-
-
Otherwise:
-
Let perBuyerGenerator be bidGenerators[buyer].
-
If perBuyerGenerator does not contain signalsUrl:
-
Let perSignalsUrlGenerator be a new per signals url bid generator.
-
Set perSignalsUrlGenerator[joiningOrigin] to « ig ».
-
Set perBuyerGenerator[signalsUrl] to perSignalsUrlGenerator.
-
-
Otherwise:
-
-
-
-
Return bidGenerators.
To generate a bid given an ordered map allTrustedBiddingSignals, a string auctionSignals, a BiddingBrowserSignals
browserSignals, a string perBuyerSignals, a duration perBuyerTimeout in milliseconds, a currency tag expectedCurrency,
an interest group ig, and a moment auctionStartTime:
-
Let igGenerateBid be the result of building an interest group passed to generateBid with ig.
-
Set browserSignals["
joinCount
"] to the sum of ig’s join counts for all days within the last 30 days. -
Set browserSignals["
recency
"] to the current wall time minus ig’s join time, in milliseconds. -
Set browserSignals["
bidCount
"] to the sum of ig’s bid counts for all days within the last 30 days. -
Let prevWins be a new
sequence<
.PreviousWin
> -
For each prevWin of ig’s previous wins for all days within the the last 30 days:
-
Let timeDelta be auctionStartTime minus prevWin’s time.
-
Set timeDelta to 0 if timeDelta is negative, timeDelta’s nearest second (rounding down) otherwise.
-
Let prevWinIDL be a new
PreviousWin
. -
Append prevWinIDL to prevWins.
-
-
Set browserSignals["
prevWinsMs
"] to prevWins. -
Let biddingScript be the result of fetching script with ig’s bidding url.
-
If biddingScript is failure, return failure.
-
If ig’s bidding wasm helper url is not null:
-
Let wasmModuleObject be the result of fetching WebAssembly with ig’s bidding wasm helper url.
-
If wasmModuleObject is not failure:
-
Set browserSignals["
wasmHelper
"] to wasmModuleObject.
-
-
-
Let trustedBiddingSignals be an ordered map whose keys are strings and whose values are
any
. -
For each key of ig’s trusted bidding signals keys:
-
If allTrustedBiddingSignals is an ordered map and allTrustedBiddingSignals[key] exists, then set trustedBiddingSignals[key] to allTrustedBiddingSignals[key].
-
-
Return the result of evaluating a bidding script with biddingScript, ig, expectedCurrency, igGenerateBid, auctionSignals, perBuyerSignals, trustedBiddingSignals, browserSignals, and perBuyerTimeout.
To generate and score bids given an auction config auctionConfig, an auction config-or-null topLevelAuctionConfig, a global object global, an environment settings object settings, and a list of interest groups bidIgs:
-
Assert that these steps are running in parallel.
-
Let auctionStartTime be the current wall time.
-
Let decisionLogicScript be the result of fetching script with auctionConfig’s decision logic url.
-
If decisionLogicScript is failure, return null.
-
Let bidGenerators be the result of running build bid generators map with auctionConfig.
-
Let leadingBidInfo be a new leading bid info.
-
Let queue be the result of starting a new parallel queue.
-
If auctionConfig’s component auctions are not empty:
-
Assert topLevelAuctionConfig is null.
-
Let pendingComponentAuctions be the size of auctionConfig’s component auctions.
-
For each component in auctionConfig’s component auctions, enqueue the following steps to queue:
-
Let compWinner be the result of running generate and score bids with component, auctionConfig, global, and settings.
-
If compWinner is failure, return failure.
-
If recursively wait until configuration input promises resolve given auctionConfig returns failure, return failure.
-
If compWinner is not null:
-
Run score and rank a bid with auctionConfig, compWinner, leadingBidInfo, decisionLogicScript, null, "top-level-auction", null, and settings’s top-level origin.
-
-
Decrement pendingComponentAuctions by 1.
-
-
Wait until pendingComponentAuctions is 0.
-
If leadingBidInfo’s leading bid is null, return null.
-
Let winningComponentConfig be leadingBidInfo’s auction config.
-
Set leadingBidInfo’s auction config to auctionConfig.
-
Set leadingBidInfo’s component seller to winningComponentConfig’s seller.
-
Let « topLevelSellerSignals, unusedTopLevelReportResultBrowserSignals » be the result of running report result with leadingBidInfo and winningComponentConfig.
-
Set leadingBidInfo’s auction config to winningComponentConfig.
-
Set leadingBidInfo’s component seller to null.
-
Set leadingBidInfo’s top level seller to auctionConfig’s seller.
-
Set leadingBidInfo’s top level seller signals to topLevelSellerSignals.
-
Let « sellerSignals, reportResultBrowserSignals » be the result of running report result with leadingBidInfo and null.
-
Run report win with leadingBidInfo, sellerSignals, and reportResultBrowserSignals.
-
Return leadingBidInfo’s leading bid.
-
-
If waiting until configuration input promises resolve given auctionConfig returns failure, return failure.
-
Let allBuyersExperimentGroupId be auctionConfig’s all buyer experiment group id.
-
Let allBuyersGroupLimit be auctionConfig’s all buyers group limit.
-
Let auctionSignals be auctionConfig’s auction signals.
-
Let browserSignals be a
BiddingBrowserSignals
. -
Let topLevelHost be the result of running the host serializer on this's relevant settings object's top-level origin's host.
-
Set browserSignals["
topWindowHostname
"] to topLevelHost. -
Set browserSignals["
seller
"] to the serialization of auctionConfig’s seller. -
Let auctionLevel be "single-level-auction".
-
Let componentAuctionExpectedCurrency be null.
-
If topLevelAuctionConfig is not null:
-
Set browserSignals["
topLevelSeller
"]] to the serialization of topLevelAuctionConfig’s seller. -
Set auctionLevel to "component-auction".
-
Set componentAuctionExpectedCurrency to the result of looking up per-buyer currency with topLevelAuctionConfig and auctionConfig’s seller.
-
-
Let pendingBuyers be the size of bidGenerators.
-
For each buyer → perBuyerGenerator of bidGenerators, enqueue the following steps to queue:
-
Let buyerExperimentGroupId be allBuyersExperimentGroupId.
-
Let perBuyerExperimentGroupIds be auctionConfig’s per buyer experiment group ids.
-
If perBuyerExperimentGroupIds is not null and perBuyerExperimentGroupIds[buyer] exists:
-
Set buyerExperimentGroupId to perBuyerExperimentGroupIds[buyer].
-
-
Apply interest groups limits to prioritized list:
-
Let buyerGroupLimit be allBuyersGroupLimit.
-
Let perBuyerGroupLimits be auctionConfig’s per buyer group limits.
-
If perBuyerGroupLimits is not null and perBuyerGroupLimits[buyer] exists:
-
Set buyerGroupLimit to perBuyerGroupLimits[buyer].
-
-
Let igs be a new list of interest groups.
-
For each signalsUrl → perSignalsUrlGenerator of perBuyerGenerator:
-
Sort in descending order igs, with a being less than b if a’s priority is less than b’s priority.
-
Remove the first buyerGroupLimit items from igs.
-
For each signalsUrl → perSignalsUrlGenerator of perBuyerGenerator:
-
For each joiningOrigin → groups of perSignalsUrlGenerator:
-
Remove from groups any interest group contained in igs.
-
-
-
-
Let perBuyerSignals be null.
-
If auctionConfig’s per buyer signals is not null and per buyer signals[buyer] exists:
-
Set perBuyerSignals to auctionConfig’s per buyer signals[buyer].
-
-
Let perBuyerTimeout be auctionConfig’s all buyers timeout.
-
If auctionConfig’s per buyer timeouts is not null and per buyer timeouts[buyer] exists:
-
Set perBuyerTimeout to auctionConfig’s per buyer timeouts[buyer].
-
-
Let expectedCurrency be the result of looking up per-buyer currency with auctionConfig and buyer.
-
For each signalsUrl → perSignalsUrlGenerator of perBuyerGenerator:
-
Let keys be a new ordered set.
-
Let igNames be a new ordered set.
-
For each joiningOrigin → groups of perSignalsUrlGenerator:
-
For each ig of groups:
-
Append ig’s trusted bidding signals keys to keys.
-
-
-
Let biddingSignalsUrl be the result of building trusted bidding signals url with signalsUrl, keys, igNames, buyerExperimentGroupId.
-
Let « allTrustedBiddingSignals, dataVersion » be the result of fetching trusted signals with biddingSignalsUrl and true.
-
If dataVersion is not null:
-
Set browserSignals["
dataVersion
"] to dataVersion.
-
-
For each joiningOrigin → groups of perSignalsUrlGenerator:
-
For each ig of groups:
-
If ig’s bidding url is null, continue.
-
Let generatedBid be the result of generate a bid given allTrustedBiddingSignals, auctionSignals, a clone of browserSignals, perBuyerSignals, perBuyerTimeout, expectedCurrency, ig, and auctionStartTime.
-
If generatedBid is failure, continue.
-
If query generated bid k-anonymity count given generatedBid returns false:
Note: Generate a bid is now rerun with only k-anonymous ads to give the buyer a chance to generate a bid for k-anonymous ads. Allowing the buyer to first generate a bid for non-k-anonymous ads provides a mechanism to bootstrap the k-anonymity count, otherwise no ads would ever trigger increment k-anonymity count and all ads would fail query k-anonymity count.
-
TODO: Run score and rank a bid on generatedBid to find the highest scoring bid that isn’t k-anonymous. After the auction, if the highest scoring bid that isn’t k-anonymous has a higher score than the highest scoring k-anonymous bid, then call increment ad k-anonymity count on it.
-
Let originalAds be ig’s ads.
-
If originalAds is not null:
-
Set ig’s ads to a new list of interest group ad.
-
For each ad in originalAds:
-
If query ad k-anonymity count given ig and ad’s render url returns true, append ad to ig’s ads.
-
-
-
Let originalAdComponents be ig’s ad components.
-
If originalAdComponents is not null:
-
Set ig’s ad components to a new list of interest group ad.
-
For each adComponent in originalAdComponents:
-
If query component ad k-anonymity count given adComponent’s render url returns true, append adComponent to ig’s ad components.
-
-
-
Set generatedBid to the result of generate a bid given allTrustedBiddingSignals, auctionSignals, a clone of browserSignals, perBuyerSignals, perBuyerTimeout, expectedCurrency, and ig.
-
Set ig’s ads to originalAds.
-
Set ig’s ad components to originalAdComponents.
-
If generatedBid is failure, continue.
-
-
Insert generatedBid’s interest group in bidIgs.
-
Score and rank a bid with auctionConfig, generatedBid, leadingBidInfo, decisionLogicScript, dataVersion, auctionLevel, componentAuctionExpectedCurrency, and settings’s top-level origin.
-
-
-
-
Decrement pendingBuyers by 1.
-
-
Wait until pendingBuyers is 0.
-
If leadingBidInfo’s leading bid is null, return null.
-
If topLevelAuctionConfig is null:
-
Let « sellerSignals, reportResultBrowserSignals » be the result of running report result with leadingBidInfo and null.
-
Run report win with leadingBidInfo, sellerSignals, and reportResultBrowserSignals.
-
-
Return leadingBidInfo’s leading bid.
-
Let igGenerateBid be a new
GenerateBidInterestGroup
with the following fields:owner
- The serialization of ig’s owner
name
- ig’s name
enableBiddingSignalsPrioritization
- ig’s enable bidding signals prioritization
priorityVector
- ig’s priority vector if not null, otherwise
undefined
executionMode
- ig’s execution mode
biddingLogicURL
- The serialization-or-undefined of ig’s bidding url
biddingWasmHelperURL
- The serialization of ig’s bidding wasm helper url
updateURL
- The serialization of ig’s update url
trustedBiddingSignalsURL
- The serialization of ig’s trusted bidding signals url
trustedBiddingSignalsKeys
- ig’s trusted bidding signals keys
userBiddingSignals
- Parse a JSON string to a JavaScript value given ig’s user bidding signals
ads
- ig’s ads converted to an AuctionAd sequence
adComponents
- ig’s ad components converted to an AuctionAd sequence
-
Return igGenerateBid.
-
If url is null, then return
undefined
. -
Return the serialization of url.
-
If ads is null, then return
undefined
. -
For each ad of ads:
-
Let adIDL be a new
AuctionAd
. -
Set adIDL["
renderURL
"] to the serialization of ad’s render url. -
If ad’s metadata is not null, then:
-
Set adIDL["
metadata
"] to the result of parsing a JSON string to a JavaScript value given ad’s metadata.
-
-
Append adIDL to adsIDL.
-
-
Return adsIDL.
To score and rank a bid given an auction config auctionConfig, a generated bid generatedBid, a leading bid info leadingBidInfo, a string decisionLogicScript, a unsigned long
-or-null biddingDataVersion, an enum auctionLevel, which is
"single-level-auction", "top-level-auction", or "component-auction", a currency tag componentAuctionExpectedCurrency, and an origin topWindowOrigin:
-
Let renderURL be serialized generatedBid’s ad descriptor's url.
-
Let adComponentRenderURLs be a new empty list.
-
If generatedBid’s ad component descriptors is not null:
-
For each adComponentDescriptor in generatedBid’s ad component descriptors:
-
Append serialized adComponentDescriptor’s url to adComponentRenderURLs.
-
-
-
Let fullSignalsUrl be the result of building trusted scoring signals url with auctionConfig’s trusted scoring signals url, «renderURL», adComponentRenderURLs, auctionConfig’s seller experiment group id, and topWindowOrigin.
Implementations may batch requests by collecting render URLs and ad component render URLs from multiple invocations of score and rank a bid and passing them all to a single invocation of building trusted scoring signals url -- the network response has to be parsed to pull out the pieces relevant to each evaluation of a scoring script.
-
Let trustedScoringSignals be null.
-
Let «allTrustedScoringSignals, scoringDataVersion» be the result of fetching trusted signals with fullSignalsUrl and false.
-
If allTrustedScoringSignals is an ordered map:
-
Set trustedScoringSignals to a new empty map.
-
If allTrustedScoringSignals["
renderURLs
"] exists and allTrustedScoringSignals["renderURLs
"][renderURL] exists:-
Set trustedScoringSignals["
renderURL
"][renderURL] to allTrustedScoringSignals["renderURLs
"][renderURL].
-
-
If adComponentRenderURLs is not empty:
-
-
Let adMetadata be generatedBid’s ad.
-
Let bidValue be generatedBid’s bid.
-
If generatedBid’s modified bid is not null:
-
Set bidValue to generatedBid’s modified bid.
-
-
Let owner be generatedBid’s interest group's owner.
-
Let browserSignals be a
ScoringBrowserSignals
with the following fields:topWindowHostname
- The result of running the host serializer on topWindowOrigin’s host
interestGroupOwner
- Serialized owner
renderURL
- The result of running the URL serializer on generatedBid’s ad descriptor's url
biddingDurationMsec
- generatedBid’s bid duration
bidCurrency
- The result of serializing a currency tag with generatedBid’s bid's currency
dataVersion
- scoringDataVersion if it is not null,
undefined
otherwise adComponents
- generatedBid’s ad component descriptors converted to a string sequence
-
Let scoreAdResult be the result of evaluating a scoring script with decisionLogicScript, adMetadata, bidValue’s value, auctionConfig’s config idl, trustedScoringSignals, browserSignals, and auctionConfig’s seller timeout.
-
Let scoreAdOutput be result of processing scoreAd output with scoreAdResult.
-
If scoreAdOutput is failure, return.
-
If auctionLevel is not "single-level-auction", and scoreAdOutput ["
allowComponentAuction
"] is false, return. -
Let score be scoreAdOutput["
desirability
"]. -
If score is negative or 0, return.
-
If auctionLevel is "component-auction":
-
Let bidToCheck be generatedBid’s bid.
-
If scoreAdOutput["
bid
"] exists:-
Let modifiedBidValue be scoreAdOutput["
bid
"]. -
If modifiedBidValue is negative or 0, return.
-
Let modifiedBidCurrency be null.
-
If scoreAdOutput["
bidCurrency
] exists:-
Set modifiedBidCurrency to scoreAdOutput["
bidCurrency
].
-
-
Set generatedBid’s modified bid to a bid with currency with value modifiedBidValue and currency modifiedBidCurrency.
-
Set bidToCheck to generatedBid’s modified bid.
-
-
If the result of checking a currency tag with componentAuctionExpectedCurrency and bidToCheck’s currency is false, return.
-
If the result of checking a currency tag with auctionConfig’s seller currency and bidToCheck’s currency is false, return.
-
-
If auctionConfig’s seller currency is not null:
-
If generatedBid’s bid's currency is equal to auctionConfig’s seller currency:
-
Set generatedBid’s bid in seller currency to generatedBid’s bid's value.
-
If scoreAdOutput["
incomingBidInSellerCurrency
"] exists and does not equal generatedBid’s bid in seller currency, return.
-
-
Otherwise if scoreAdOutput["
incomingBidInSellerCurrency
"] exists:-
Set generatedBid’s bid in seller currency to scoreAdOutput["
incomingBidInSellerCurrency
"]
-
-
-
Let updateLeadingBid be false.
-
If leadingBidInfo’s leading bid is null, or score is greater than leadingBidInfo’s top score:
-
Set updateLeadingBid to true.
-
Set leadingBidInfo’s top bids count to 1.
-
Set leadingBidInfo’s at most one top bid owner to true.
-
-
Otherwise if score equals leadingBidInfo’s top score:
-
Increment leadingBidInfo’s top bids count by 1.
-
Set updateLeadingBid to true with 1 in leadingBidInfo’s top bids count chance.
-
If updateLeadingBid is false:
-
Update highest scoring other bid with score, leadingBidInfo’s leading bid, and leadingBidInfo.
-
-
If owner is not same origin with leadingBidInfo’s leading bid's interest group's owner:
-
Set leadingBidInfo’s at most one top bid owner to false.
-
-
-
Otherwise if score is greater than or equal to leadingBidInfo’s second highest score:
-
Update highest scoring other bid with score, bidValue, and leadingBidInfo.
-
-
If updateLeadingBid is true:
-
If leadingBidInfo’s leading bid is not null:
-
Update highest scoring other bid with leadingBidInfo’s top score, leadingBidInfo’s leading bid, and leadingBidInfo.
-
-
Set leadingBidInfo’s top score to score.
-
Set leadingBidInfo’s leading bid to generatedBid.
-
Set leadingBidInfo’s auction config to auctionConfig.
-
Set leadingBidInfo’s bidding data version to biddingDataVersion.
-
Set leadingBidInfo’s scoring data version to scoringDataVersion.
-
double
score, a generated bid-or-null bid, and a leading bid info leadingBidInfo:
-
If bid is null, return.
-
Let owner be bid’s interest group's owner.
-
If score is greater than leadingBidInfo’s second highest score:
-
Set leadingBidInfo’s highest scoring other bid to bid.
-
Set leadingBidInfo’s highest scoring other bids count to 1.
-
Set leadingBidInfo’s second highest score to score.
-
If leadingBidInfo’s at most one top bid owner is true:
-
Set leadingBidInfo’s highest scoring other bid owner to owner.
-
-
Otherwise,
-
Set leadingBidInfo’s highest scoring other bid owner to null.
-
-
-
Otherwise if score is equal to leadingBidInfo’s second highest score:
-
Increment leadingBidInfo’s highest scoring other bids count by 1.
-
Set leadingBidInfo’s highest scoring other bid to bid with 1 in leadingBidInfo’s highest scoring other bids count chance.
-
If leadingBidInfo’s highest scoring other bid owner is not null:
-
If owner is not same origin with leadingBidInfo’s highest scoring other bid owner:
-
Set leadingBidInfo’s highest scoring other bid owner to null.
-
-
-
The Ad-Auction-Allowed
HTTP response header is a structured header whose value must be a boolean.
-
If responseBody is null or failure, return false.
-
If getting `
Ad-Auction-Allowed
` and "item
" from response’s header list does not return a true value, return false. -
Let headerMimeType be the result of extracting a MIME type from response’s header list.
-
Return false if any of the following conditions hold:
-
headerMimeType is failure;
-
mimeType is "
text/javascript
" and headerMimeType is not a JavaScript MIME type; -
mimeType is "
application/json
" and headerMimeType is not a JSON MIME type.
-
-
Let mimeTypeCharset be headerMimeType’s parameters["
charset
"]. -
Return false if any of the following conditions hold:
-
mimeTypeCharset does not exist, or mimeTypeCharset is "utf-8", and responseBody is not UTF-8 encoded;
-
mimeTypeCharset is "us-ascii", and not all bytes in responseBody are ASCII bytes.
-
-
Return true.
-
Let request be a new request with the following properties:
- URL
-
url
- header list
-
«
Accept
:text/javascript
» - client
-
null
- mode
-
"
no-cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
One of the side-effects of a
null
client for this subresource request is it neuters all service worker interceptions, despite not having to set the service workers mode.Stop using "
no-cors
" mode where possible (WICG/turtledove#667). -
Let script be null.
-
Fetch request with useParallelQueue set to true, and processResponseConsumeBody set to the following steps given a response response and null, failure, or a byte sequence responseBody:
-
If validate fetching response with response, responseBody and "
text/javascript
" returns false, set script to failure and return. -
Set script to responseBody.
-
-
Wait for script to be set.
-
Return script.
-
Let request be a new request with the following properties:
- URL
-
url
- header list
-
«
Accept
:application/wasm
» - client
-
null
- mode
-
"
no-cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
One of the side-effects of a
null
client for this subresource request is it neuters all service worker interceptions, despite not having to set the service workers mode.Stop using "
no-cors
" mode where possible (WICG/turtledove#667). -
Let moduleObject be null.
-
Fetch request with processResponseConsumeBody set to the following steps given a response response and null, failure, or a byte sequence responseBody:
-
Set moduleObject to failure and return, if any of the following conditions hold:
-
responseBody is null or failure;
-
Getting `
Ad-Auction-Allowed
` and "item
" from response’s header list does not return a true value.
-
-
Let module be the result of compiling a WebAssembly module response.
-
If module is error, set moduleObject to failure.
-
Otherwise, set moduleObject to module.
-
-
Wait for moduleObject to be set.
-
Return moduleObject.
The Data-Version
HTTP response header is a structured header whose value must be an integer.
The X-fledge-bidding-signals-format-version
HTTP response header
is a structured header whose value must be an integer.
-
Let request be a new request with the following properties:
- URL
-
url
- header list
-
«
Accept
:application/json
» - client
-
null
- mode
-
"
no-cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
One of the side-effects of a
null
client for this subresource request is it neuters all service worker interceptions, despite not having to set the service workers mode.Stop using "
no-cors
" mode where possible (WICG/turtledove#667). -
Let signals be null.
-
Let dataVersion be null.
-
Let formatVersion be null.
-
Fetch request with useParallelQueue set to true, and processResponseConsumeBody set to the following steps given a response response and null, failure, or a byte sequence responseBody:
-
If validate fetching response with response, responseBody and "
application/json
" returns false, set signals to failure and return. -
Let headers be response’s header list.
-
Set dataVersion to the result of getting a structured field value given `
Data-Version
` and "item
" from headers. -
If dataVersion is not null:
-
If dataVersion is not an integer, or is less than 0 or more than 232−1, set signals to failure and return.
-
-
If isBiddingSignal is true:
-
Set formatVersion to the result of getting a structured field value given `
X-fledge-bidding-signals-format-version
` and "item
" from headers.
-
-
Set signals to the result of parsing JSON bytes to an Infra value responseBody.
-
-
Wait for signals to be set.
-
If signals is a parsing exception, or if signals is not an ordered map, return « null, null ».
-
For each key → value of signals:
-
Set signals[key] to the result of serializing an Infra value to a JSON string given value.
-
-
If formatVersion is 2:
-
If signals["
keys
"] does not exist, return « null, null ». -
Set signals to signals["
keys
"]. -
If signals is not an ordered map, return « null, null ».
-
TODO: handle priority vector.
-
-
Return « signals, dataVersion ».
To encode trusted signals keys given an ordered set of strings keys:
-
Let list be a new empty list.
-
Let keysStr be the result of concatenating keys with separator set to ",".
-
Append the result of UTF-8 percent-encoding keysStr using component percent-encode set to list.
-
Return list.
To build trusted bidding signals url given a URL signalsUrl, an ordered set of strings keys, an ordered set of strings igNames, and an unsigned short
-or-null experimentGroupId:
-
Let queryParamsList be a new empty list.
-
Append "hostname=" to queryParamsList.
-
Append the result of UTF-8 percent-encoding this's relevant settings object's top-level origin using component percent-encode set to queryParamsList.
-
If keys is not empty:
-
Append "&keys=" to queryParamsList.
-
Extend queryParamsList with the result of encode trusted signals keys with keys.
-
-
If igNames is not empty:
-
Append "&interestGroupNames=" to queryParamsList.
-
Extend queryParamsList with the result of encode trusted signals keys with igNames.
-
-
If experimentGroupId is not null:
-
Append "&experimentGroupId=" to queryParamsList.
-
Append serialized experimentGroupId to queryParamsList.
-
-
Let fullSignalsUrl be signalsUrl.
-
Set fullSignalsUrl’s query to the result of concatenating queryParamsList.
-
return fullSignalsUrl.
To build trusted scoring signals url given a URL signalsUrl, a list of strings renderURLs, an ordered set of strings adComponentRenderURLs, an unsigned short
experimentGroupId, and an origin topWindowOrigin:
Note: When trusted scoring signals fetches are not batched, renderURLs’s size is 1.
-
Let queryParamsList be a new empty list.
-
Append "hostname=" to queryParamsList.
-
Append the result of UTF-8 percent-encoding topWindowOrigin using component percent-encode set to queryParamsList.
-
If renderURLs is not empty:
-
Append "&renderURLs=" to queryParamsList.
-
Extend queryParamsList with the result of encode trusted signals keys with renderURLs.
-
-
If adComponentRenderURLs is not empty:
-
Append "&adComponentRenderURLs=" to queryParamsList.
-
Extend queryParamsList with the result of encode trusted signals keys with adComponentRenderURLs.
-
-
If experimentGroupId is not null:
-
Append "&experimentGroupId=" to queryParamsList.
-
Append serialized experimentGroupId to queryParamsList.
-
-
Set signalsUrl’s query to the result of concatenating queryParamsList.
-
return signalsUrl.
-
Let request be a new request with the following properties:
- URL
-
url
- client
-
null
- mode
-
"
no-cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
Stop using "
no-cors
" mode where possible (WICG/turtledove#667). -
Fetch request with useParallelQueue set to true.
To serialize an integer, represent it as a string of the shortest possible decimal number.
This would ideally be replaced by a more descriptive algorithm in Infra. See infra/201
double
value:
-
If value is not a valid floating-point number, return value.
-
Let valueExp be value’s IEEE 754 biased exponent field minus 1023.
-
Let normValue be value multiplied by 2(−1 × valueExp).
-
If valueExp is less than −128:
-
If value is less than 0, return −0.
-
Otherwise, return 0.
-
-
If valueExp is greater than 127:
-
If value is less than 0, return −∞.
-
Otherwise, return ∞.
-
-
Let precisionScaledValue be normValue multiplied by 256.
-
Let noisyScaledValue be precisionScaledValue plus a random
double
value greater than or equal to 0 but less than 1. -
Let truncatedScaledValue be the largest integer not greater than noisyScaledValue.
-
Return truncatedScaledValue multiplied by 2(valueExp − 8).
-
Let config be leadingBidInfo’s auction config.
-
Let bidCurrency be null.
-
If winningComponentConfig is not null:
-
Assert that leadingBidInfo’s component seller is not null.
-
Set bidCurrency to winningComponentConfig’s seller currency.
-
If bidCurrency is null:
-
Set bidCurrency to the result of looking up per-buyer currency with config and leadingBidInfo’s component seller.
-
-
-
Otherwise:
-
Set bidCurrency to the result of looking up per-buyer currency with config and leadingBidInfo’s leading bid's interest group's owner.
-
-
Let winner be leadingBidInfo’s leading bid.
-
Let sellerCurrency be leadingBidInfo’s auction config's seller currency.
-
Let highestScoringOtherBid be leadingBidInfo’s highest scoring other bid's bid in seller currency (or 0 if encountered a null).
-
If sellerCurrency is null:
-
Set highestScoringOtherBid to leadingBidInfo’s highest scoring other bid's bid's value (or 0 if encountered a null).
-
-
Let modifiedBid be null.
-
If winner’s modified bid is not null:
-
If leadingBidInfo’s component seller is not null:
-
Set bid to winner’s modified bid.
-
-
Otherwise:
-
Set modifiedBid to winner’s modified bid.
-
-
-
Let browserSignals be a
ReportResultBrowserSignals
with the following fields:topWindowHostname
- The result of running the host serializer on this's relevant settings object's top-level origin's host.
interestGroupOwner
- Serialized winner’s interest group's owner.
renderURL
- Serialized winner’s ad descriptor's url
bid
- Stochastically rounded bid
bidCurrency
- The result of serializing a currency tag with bidCurrency
highestScoringOtherBid
- highestScoringOtherBid
highestScoringOtherBidCurrency
- sellerCurrency if it is not null, "
???
" otherwise topLevelSeller
- leadingBidInfo’s top level seller if it is not null,
undefined
otherwise componentSeller
- leadingBidInfo’s component seller if it is not null,
undefined
otherwise desirability
- Stochastically rounded leadingBidInfo’s top score
topLevelSellerSignals
- leadingBidInfo’s top level seller signals if it is not null,
undefined
otherwise modifiedBid
- Stochastically rounded modifiedBid if it is not null,
undefined
otherwise dataVersion
- leadingBidInfo’s scoring data version if it is not null,
undefined
otherwise
-
Let igAd be the interest group ad from winner’s interest group's ads whose render url is winner’s ad descriptor's url.
-
If igAd’s buyer and seller reporting ID exists and the result of query reporting ID k-anonymity count given winner’s interest group and igAd is true:
-
Set browserSignals["
buyerAndSellerReportingId
"] to igAd’s buyer and seller reporting ID.
-
-
Let sellerReportingScript be the result of fetching script with config’s decision logic url.
-
Let « sellerSignals, reportUrl, reportingBeaconMap, ignored » be the result of evaluating a reporting script with sellerReportingScript, "
reportResult
", and « config’s config idl, browserSignals ». -
Let reportingResult be a reporting result with the following items:
- report url
-
reportUrl
- reporting beacon map
-
reportingBeaconMap
-
If leadingBidInfo’s top level seller is null (i.e., if we are reporting for a component seller), set leadingBidInfo’s component seller reporting result to reportingResult.
-
Otherwise, set leadingBidInfo’s seller reporting result to reportingResult.
-
Remove browserSignals["
desirability
"]. -
Remove browserSignals["
modifiedBid
"]. -
Remove browserSignals["
topLevelSellerSignals
"]. -
Remove browserSignals["
dataVersion
"].
Note: Remove fields specific to ReportResultBrowserSignals
which only sellers can learn about,
so that they are not passed to "reportWin()
".
-
Return « sellerSignals, browserSignals ».
ReportingBrowserSignals
browserSignals:
-
Let config be leadingBidInfo’s auction config.
-
Let winner be leadingBidInfo’s leading bid.
-
Let perBuyerSignals be config’s per buyer signals.
-
Let buyer be winner’s interest group's owner.
-
Let perBuyerSignalsForBuyer be perBuyerSignals[buyer] if that member exists, and null otherwise.
-
Let reportWinBrowserSignals be a
ReportWinBrowserSignals
with the members that are declared onReportingBrowserSignals
initialized to their values in browserSignals. -
Add the following fields to reportWinBrowserSignals:
dataVersion
- leadingBidInfo’s bidding data version if it is not null,
undefined
otherwise. adCost
- Rounded winner’s ad cost
seller
- Serialized config’s seller
madeHighestScoringOtherBid
- Set to true if leadingBidInfo’s highest scoring other bid owner is not null, and buyer is same origin with leadingBidInfo’s highest scoring other bid owner, false otherwise
modelingSignals
- winner’s modeling signals if it is not null,
undefined
otherwise (TODO: noise and bucket this signal)
-
Let igAd be the interest group ad from winner’s interest group's ads whose render url is winner’s ad descriptor's url.
-
If igAd’s buyer and seller reporting ID does not exist and the result of query reporting ID k-anonymity count given winner’s interest group and igAd is true:
-
If igAd’s buyer reporting ID exists, set reportWinBrowserSignals["
buyerReportingId
"] to igAd’s buyer reporting ID. -
Otherwise, Set reportWinBrowserSignals["
interestGroupName
"] to winner’s interest group name.
-
-
Let buyerReportingScript be the result of fetching script with winner’s interest group's bidding url.
-
Let « ignored, resultUrl, reportingBeaconMap, reportingMacroMap » be the result of evaluating a reporting script with buyerReportingScript, "
reportWin
", and « leadingBidInfo’s auction config's config idl'sauctionSignals
, perBuyerSignalsForBuyer, sellerSignals, reportWinBrowserSignals ». -
Set leadingBidInfo’s buyer reporting result to a reporting result with the following items:
- report url
-
resultUrl
- reporting beacon map
-
reportingBeaconMap
- reporting macro map
-
reportingMacroMap
5. K-anonymity
Two goals of this specification rely on applying k-anonymity thresholds:
-
To prevent cross-site leaks: Inputs to event-level reporting functions,
reportWin()
andreportResult()
, only contain limited cross-site information. As described in § 10 Privacy Considerations, part of this limiting is done by applying k-anonymity requirements to the ad URLs. -
To prevent microtargeting: The browser applies k-anonymity requirements on the ad URLs to ensure that the same ad or ad component is being shown to at least some minimum number of people.
The browser enforces these k-anonymity requirements by maintaining counts of how many times each ad and ad component has been shown to users. These counts are maintained across users, so the counting must be done on a central k-anonymity server. This specification relies on two operations to query and increment the counts: query k-anonymity count and increment k-anonymity count.
The details of how the k-anonymity server is operated and accessed are implementation-defined but it should be done in a way that prevents the server operator from joining the identity of two query or increment requests. One way to help prevent this is by making accesses to the server go through an HTTP proxy that prevents the server from seeing the browsers' IP addresses.
The browser should choose a k-anonymity threshold, otherwise known as the value for "k", and a k-anonymity duration depending on the projected sizes of interest groups and the browser’s privacy goals. For example an implementation might choose to require a k-anonymity threshold of fifty users over a seven day period. The server will maintain the count over the chosen duration and compare the count to the chosen k-anonymity threshold when responding to query k-anonymity count.
-
If the k-anonymity server has recorded at least k-anonymity threshold users seeing hashCode over the last k-anonymity duration, return true. Otherwise return false.
-
Return true if it is above the threshold, otherwise return false.
-
Let keyString be the concatenation of the following strings separated with U+000A LF:
-
"AdBid"
-
the serialization of ig’s owner
-
the serialization of ig’s bidding url
-
the serialization of ad.
-
-
Let keyHash be the SHA-256 hash of the ASCII encoding of keyString.
-
Return the result of querying the k-anonymity count given keyHash.
-
Let keyString be the concatenation of the following strings separated with U+000A (LF):
-
"NameReport"
-
the serialization of ig’s owner
-
the serialization of ig’s bidding url
-
the serialization of igAd’s render url
-
If igAd’s buyer and seller reporting ID exists:
-
"BuyerAndSellerReportingId"
-
-
Otherwise, if igAd’s buyer reporting ID exists:
-
"BuyerReportingId"
-
igAd’s buyer reporting ID
-
-
Otherwise:
-
"IgName"
-
ig’s name.
-
-
-
Return the SHA-256 hash of the ASCII encoding of keyString.
-
Let keyString be the concatenation of the following strings separated with U+000A LF:
-
"ComponentBid"
-
the serialization of ad.
-
-
Let keyHash be the SHA-256 hash of the ASCII encoding of keyString.
-
Return the result of querying the k-anonymity count given keyHash.
-
If query ad k-anonymity count given bid’s ad descriptor's url returns false, return false.
-
If bid’s ad component descriptors is not null:
-
For each adComponentDescriptor in bid’s ad component descriptors:
-
If query component ad k-anonymity count given adComponentDescriptor’s url returns false, return false.
-
-
-
Return true.
-
Let keyHash be the result of computing the key hash of reporting ID given ig and igAd.
-
Return the result of querying the k-anonymity count given keyHash.
-
Ask the k-anonymity server to record that this user agent has seen hashCode.
-
Let keyString be the concatenation of the following strings separated with U+000A LF:
-
"AdBid"
-
the serialization of ig’s owner
-
the serialization of ig’s bidding url
-
the serialization of ad.
-
-
Let keyHash be the SHA-256 hash of the ASCII encoding of keyString.
-
Increment k-anonymity count given keyHash.
-
Let keyString be the concatenation of the following strings separated with U+000A LF:
-
"ComponentBid"
-
the serialization of ad.
-
-
Let keyHash be the SHA-256 hash of the ASCII encoding of keyString.
-
Increment k-anonymity count given keyHash.
-
Let igAd be the interest group ad from ig’s ads whose render url is ad.
-
Let keyHash be the result of computing the key hash of reporting ID given ig and igAd.
-
Increment k-anonymity count given keyHash.
6. Script Runners
This introduction sub-section is non-normative.
This specification defines a new type of script execution environment called a script runner. On the surface, these are similar to Worklets in that they too are used for running scripts independent of the main execution environment with a flexible implementation model.
However, some key differences from traditional Worklets motivate us to create a new kind of script execution environment. In particular, they:
-
Are not scoped to a particular
Document
, but are rather scoped to a user agent, as they are spun up by interest groups in the user agent’s interest group set. -
Consequently have a different, more flexible agent cluster allocation model —
specifically, they need not execute in the same agent cluster as any Document
, and for privacy reasons implementations may be motivated to enjoy this flexibility. -
Do not have any other WebIDL interfaces exposed to their global besides the ones defined in this specification, unlike other Worklet types.
-
Have a restricted set of ECMAScript APIs exposed to them; for example
Date
is not exposed in these environments. -
Are not module scripts, and are instead evaluated as if they were classic scripts.
-
Are not scripts in the [HTML] sense, and as such:
-
Their agent does not have an event loop
-
Their realm does not have a settings object, and therefore functions inside them are not run with the familiar [WebIDL] invocation mechanism.
-
They do not perform a microtask checkpoints.
-
6.1. Realm and agent
-
Let signifier be a new unique internal value.
-
Let candidateExecution be a new candidate execution.
-
Return a new agent whose [[CanBlock]] is false, [[Signifier]] is signifier, [[CandidateExecution]] is candidateExecution, and [[IsLockFree1]], [[IsLockFree2]], and [[LittleEndian]] are set at the implementation’s discretion.
Note: This algorithm is almost identical to [HTML]'s create an agent algorithm, with the exception that we do not give the returned agent a new event loop, since it does not process tasks within task sources in the usual way.
-
Let agentCluster be a new agent cluster.
-
Let agent be the result of creating a new script runner agent.
-
Add agent to agentCluster.
-
Return agent.
-
Assert that these steps are running in parallel.
-
Let agent be the result of obtaining a script runner agent given null, true, and false. Run the rest of these steps in agent.
This exclusively creates a new agent cluster for a given script to run in, but we should make this work with execution mode somehow.
-
Let realmExecutionContext be the result of creating a new realm given agent and the following customizations:
-
For the global object, create a new object of type globalType.
-
-
Let realm be realmExecutionContext’s Realm component.
-
Let global be realm’s global object, and run these steps:
-
Perform !global.[[Delete]]("
Date
"). -
If !global.[[HasProperty]]("
Temporal
") is true, then perform !global.[[Delete]]("Temporal
").
This is not the best way to perform such API neutering (see tc39/ecma262#1357), but at the moment it’s the way that host environments do this.
Note: Removing time-referencing APIs from the global object is imperative for privacy, as a script might otherwise be able to more easily exfiltrate data by using more accurate time measurements.
-
-
Return realm.
6.2. Script evaluation
Concretely, a script runner is a JavaScript execution environment instantiated with one of the following global objects:
GenerateBidInterestGroup
igGenerateBid, a string-or-null auctionSignals, a string-or-null perBuyerSignals, an ordered map trustedBiddingSignals, a BiddingBrowserSignals
browserSignals, and an integer millisecond duration timeout:
-
Let realm be the result of creating a new script runner realm given
InterestGroupBiddingScriptRunnerGlobalScope
. -
Let global be realm’s global object.
-
Set global’s group has ad components to true if ig’s ad components is not null, or false otherwise.
-
Set global’s expected currency to expectedCurrency.
-
Let isComponentAuction be true if browserSignals["
topLevelSeller
"] is not null, or false otherwise. -
Set global’s is component auction to isComponentAuction.
-
Set global’s interest group to ig.
-
Let igJS be the result of converting to ECMAScript values given igGenerateBid.
-
Let auctionSignalsJS be the result of parsing a JSON string to a JavaScript value given auctionSignals if auctionSignals is not null, otherwise
undefined
. -
Let perBuyerSignalsJS be the result of parsing a JSON string to a JavaScript value given perBuyerSignals if perBuyerSignals is not null, otherwise
undefined
. -
Let trustedBiddingSignalsJS be trustedBiddingSignals converted to ECMAScript values.
-
Let browserSignalsJS be browserSignals converted to ECMAScript values.
-
Let startTime be the current wall time.
-
Let result be the result of evaluating a script with realm, script, "
generateBid
", « igJS, auctionSignalsJS, perBuyerSignalsJS, trustedBiddingSignalsJS, browserSignalsJS », and timeout. -
Let duration be the current wall time minus startTime in milliseconds.
-
If global’s priority is not null and not failure:
-
Replace the interest group that has ig’s owner and name in the browser’s interest group set with ig.
-
If global’s priority signals is not empty:
-
For each k → v of global’s priority signals:
-
If v is null, remove ig’s priority signals overrides[k].
-
Otherwise, set ig’s priority signals overrides[k] to v.
-
-
Replace the interest group that has ig’s owner and name in the browser’s interest group set with ig.
-
-
Let generatedBid be global’s bid.
-
If result is a normal completion:
-
Let generatedBidIDL be the result of converting result’s [[Value]] to a
GenerateBidOutput
. -
If no exception was thrown in the previous step:
-
Set generatedBid to the result of converting GenerateBidOutput to generated bid with generatedBidIDL, ig, expectedCurrency, isComponentAuction, and global’s group has ad components.
-
-
Otherwise, set generatedBid to failure.
-
-
If generatedBid is a generated bid and generatedBid’s bid's value ≤ 0, set generatedBid to failure.
-
If generatedBid is null, set it to failure.
-
If generatedBid is not failure:
-
Set generatedBid’s bid duration to duration.
-
Set generatedBid’s interest group to ig.
-
-
Return generatedBid.
double
bidValue, an AuctionAdConfig
auctionConfigIDL, an ordered map trustedScoringSignals, a ScoringBrowserSignals
browserSignals, and an integer millisecond duration timeout:
-
Let realm be the result of creating a new script runner realm given
InterestGroupScoringScriptRunnerGlobalScope
. -
Let browserSignalsJS be browserSignals converted to ECMAScript values.
-
Let auctionConfigJS be auctionConfigIDL converted to ECMAScript values.
-
Let trustedScoringSignalsJS be trustedScoringSignals converted to ECMAScript values.
-
Return the result of evaluating a script with realm, script, "
scoreAd
", «adMetadata, bidValue, auctionConfigJS, trustedScoringSignalsJS, browserSignalsJS», and timeout.
-
Let realm be the result of creating a new script runner realm given
InterestGroupReportingScriptRunnerGlobalScope
. -
Let global be realm’s global object.
-
Let argumentsJS be the result of converting arguments to an ECMAScript arguments list. If this throws an exception, return « "null", null, null ».
-
Let result be the result of evaluating a script with realm, script, functionName, argumentsJS, and 50 milliseconds.
-
If result is an abrupt completion, return « "null", null, null ».
-
Let resultJSON be "null".
-
If functionName is "
reportResult
", then set resultJSON to the result of serializing a JavaScript value to a JSON string given result.Note: Consider a return value that can’t be converted to JSON a valid result, so if an exception was thrown in the previous step, keep resultJSON as "null".
-
Let reportURL be global’s report url
-
If reportURL is failure, set reportURL to null.
-
Let macroMap be global’s reporting macro map if functionName is "
reportWin
", null otherwise. -
Return « resultJSON, reportURL, global’s reporting beacon map, macroMap ».
-
Assert that these steps are running in parallel.
-
Let global be realm’s global object, and run these steps in realm’s agent:
-
Let result be ParseScript(script, realm,
empty
).Note: The resulting Script Record will have no [[HostDefined]] component, unlike traditional scripts on the web platform.
-
If result is a list of errors, return Completion { [[Type]]:
throw
, [[Value]]: result, [[Target]]:empty
}. -
Assert: result is a Script Record.
-
Prepare to run script: Push realmExecutionContext onto the JavaScript execution context stack; it is now the running JavaScript execution context.
-
Let evaluationStatus be the result of ScriptEvaluation(result).
-
If evaluationStatus is an abrupt completion, jump to the step labeled return.
-
Let F be Get(global, functionName). If that returns a throw completion, set finalCompletion to F and jump to the step labeled return.
-
Set finalCompletion be Completion(Call(F,
undefined
, arguments)).In timeout milliseconds, if the invocation of Call has not completed, immediately interrupt the execution and set finalCompletion to a new throw completion given null.
-
Return: at this point finalCompletion will be set to a Completion Record.
-
Clean up after script: Assert realmExecutionContext is the running JavaScript execution context, and remove it from the JavaScript execution context stack.
-
Return finalCompletion.
-
6.3. Global scopes
An additional requirement to the interest group script runner globals defined in this specification is that they must not expose any interfaces from other specifications whose own exposure set is the special value "*". The only interfaces that can be exposed inside of the globals defined in this specification are those that explicitly list the global names provided here.
[Exposed =InterestGroupScriptRunnerGlobalScope ]interface { };
InterestGroupScriptRunnerGlobalScope
6.3.1. InterestGroupBiddingScriptRunnerGlobalScope
[Exposed =InterestGroupBiddingScriptRunnerGlobalScope ,Global =(InterestGroupScriptRunnerGlobalScope ,InterestGroupBiddingScriptRunnerGlobalScope )]interface :
InterestGroupBiddingScriptRunnerGlobalScope InterestGroupScriptRunnerGlobalScope {boolean setBid (optional GenerateBidOutput = {});
generateBidOutput undefined setPriority (double );
priority undefined setPrioritySignalsOverride (DOMString ,
key optional double ?); };
priority dictionary {
AdRender required DOMString ;
url DOMString ;
width DOMString ; };
height dictionary {
GenerateBidOutput double = -1;
bid DOMString ; (
bidCurrency DOMString or AdRender );
render any ;
ad sequence <(DOMString or AdRender )>;
adComponents double ;
adCost unrestricted double ;
modelingSignals boolean =
allowComponentAuction false ; };
Each InterestGroupBiddingScriptRunnerGlobalScope
has a
- bid
- priority
-
Null, failure, or a
double
. Defaulting to null. - priority signals
-
An ordered map whose keys are strings and whose values are
double
or null. - interest group
- expected currency
- is component auction
-
A boolean
- group has ad components
-
A boolean
To convert GenerateBidOutput to generated bid given a GenerateBidOutput
generateBidOutput, an interest group ig, a currency tag expectedCurrency, a boolean isComponentAuction and a boolean groupHasAdComponents:
-
Let bid be a new generated bid.
-
If generateBidOutput["
bid
"] ≤ 0:-
Set bid’s bid to a bid with currency with value generateBidOutput["
bid
"] and currency null. -
Return bid.
-
-
If generateBidOutput["
render
"] does not exist, return failure. -
If isComponentAuction is true, and generateBidOutput["
allowComponentAuction
"] is false:-
Return failure.
-
-
Let bidCurrency be null.
-
If generateBidOutput["
bidCurrency
"] is specified:-
If the result of checking whether a string is a valid currency tag on generateBidOutput["
bidCurrency
"] is true:-
Set bidCurrency to generateBidOutput["
bidCurrency
"]
-
-
Otherwise return failure.
-
-
If the result of checking a currency tag with expectedCurrency and bidCurrency is false, return failure.
-
Set bid’s bid to a bid with currency with value generateBidOutput["
bid
"] and currency bidCurrency. -
If generateBidOutput["
ad
"] exists:-
Let adJSON be the result of serializing a JavaScript value to a JSON string, given generateBidOutput["
ad
"]. -
If adJSON is failure, return failure.
-
Set bid’s ad to adJSON.
-
-
Let adDescriptor be a new ad descriptor.
-
If generateBidOutput["
render
"] is aDOMString
:-
Let adUrl be the result of running the URL parser on generateBidOutput["
render
"]. -
If adUrl is failure, return failure.
-
Set adDescriptor’s url to adUrl.
-
-
Otherwise:
-
Set adDescriptor to the result of converting an ad render given generateBidOutput["
render
"]. -
If adDescriptor is failure, return failure.
-
-
Let bidAd be the result of finding matching ad given adDescriptor, ig, and false.
-
If bidAd is null, return failure.
-
Set bid’s ad descriptor to adDescriptor.
-
Set bid’s bid ad to bidAd.
-
If generateBidOutput["
adComponents
"] exists:-
Let adComponents be generateBidOutput["
adComponents
"]. -
Return failure if any of the following conditions hold:
-
groupHasAdComponents is false;
-
adComponents’s size is greater than 20.
-
-
Let adComponentDescriptors be a new list of ad descriptors.
-
For component in adComponents:
-
Let componentDescriptor be a new ad descriptor.
-
If component is
DOMString
:-
Let componentUrl be the result of running the URL parser on component.
-
If componentUrl is failure, return failure.
-
Set componentDescriptor’s url to componentUrl.
-
-
Otherwise:
-
Set componentDescriptor to the result of converting an ad render given component.
-
If componentDescriptor is failure, return failure.
-
-
If finding matching ad given componentUrl, ig, and true returns null, return failure.
-
Append componentDescriptor to adComponentDescriptors.
-
-
Set bid’s ad component descriptors to adComponentDescriptors.
-
-
If generateBidOutput["
modelingSignals
"] exists:-
Let modelingSignals be generateBidOutput["
modelingSignals
"]. -
If modelingSignals ≥ 0 and modelingSignals < 4096:
-
Set bid’s modeling signals to the result of converting the ECMAScript value represented by modelingSignals to an
unsigned short
.
-
-
-
Return bid.
-
Let position be a position variable, initially pointing at the start of input.
-
Strip leading and trailing ASCII whitespace from input.
-
If input starts with "
0
" but is not "0
" and does not start with "0.
", then return null as the dimension and the empty string as the dimension unit. -
Collect a sequence of code points that are ASCII digits or U+002E (.), given position. Let that be dimensionString.
-
If dimensionString is the empty string, then return null as the dimension and the empty string as the dimension unit.
-
Let dimension be the result of parsing dimensionString using the rules for parsing floating-point number values.
-
If dimension is an error, then return null as the dimension and the empty string as the dimension unit.
-
Collect a sequence of code points that are ASCII lower alpha, given position. Let that be dimensionUnit.
-
If position is not past the end of input, then return null as the dimension and the empty string as the dimension unit.
-
If dimensionUnit is the empty string, then set dimensionUnit to "px".
-
If dimensionUnit is not "px", "sh", or "sw", then return null as the dimension and the empty string as the dimension unit.
-
Return dimension as the dimension and dimensionUnit as the dimension unit.
AdRender
adRender:
-
Let adUrl be the result of running the URL parser on adRender["
url
"]. -
If adUrl is failure, return failure.
-
Let adDescriptor be a new ad descriptor.
-
Set adDescriptor’s url to adUrl.
-
-
Let width and widthUnit be the dimension and dimension unit that results from running parse an AdRender dimension value with adRender["
width
"], respectively. -
If width is null, return failure.
-
Let height and heightUnit be the dimension and dimension unit that results from running parse an AdRender dimension value with adRender["
height
"], respectively. -
If height is null, return failure.
-
Let adSize be a new ad size.
-
Set adSize’s width to width, width units to widthUnit, height to height, height units to heightUnit.
-
Set adDescriptor’s size to adSize.
-
Return adDescriptor.
-
Let adUrl be adDescriptor’s url.
-
If adUrl’s scheme is not "
https
", return null. -
TODO: Need to check size as well.
-
If isComponent:
-
For each ad in ig’s ad components:
-
If ad’s render url equals adUrl, return ad.
-
-
-
Otherwise:
-
-
If ad’s render url equals adUrl, return ad.
-
-
-
Return null.
setBid(generateBidOutput)
method steps are:
-
Set this's relevant global object's bid to null.
-
Let ig be this's relevant global object's interest group.
-
Let expectedCurrency be this's relevant global object's expected currency.
-
Let bidToSet be the result of converting GenerateBidOutput to generated bid with generateBidOutput, ig, expectedCurrency, this's relevant global object's is component auction, and this's relevant global object's group has ad components.
-
Set this's relevant global object's bid to bidToSet.
setPriority(priority)
method steps are:
-
If this's relevant global object's priority is not null:
-
Set this's relevant global object's priority to failure.
-
-
Set this's relevant global object's priority to priority.
setPrioritySignalsOverride(key, priority)
method steps are:
-
Set this's relevant global object's priority signals[key] to priority.
6.3.2. InterestGroupScoringScriptRunnerGlobalScope
[Exposed =InterestGroupScoringScriptRunnerGlobalScope ,Global =(InterestGroupScriptRunnerGlobalScope ,InterestGroupScoringScriptRunnerGlobalScope )]interface :
InterestGroupScoringScriptRunnerGlobalScope InterestGroupScriptRunnerGlobalScope { };
6.3.3. InterestGroupReportingScriptRunnerGlobalScope
[Exposed =InterestGroupReportingScriptRunnerGlobalScope ,Global =(InterestGroupScriptRunnerGlobalScope ,InterestGroupReportingScriptRunnerGlobalScope )]interface :
InterestGroupReportingScriptRunnerGlobalScope InterestGroupScriptRunnerGlobalScope {undefined sendReportTo (DOMString );
url undefined registerAdBeacon (record <DOMString ,USVString >);
map undefined registerAdMacro (DOMString ,
name USVString ); };
value
Note: registerAdMacro(name, value)
is only
available in report win, but not report result.
Each InterestGroupReportingScriptRunnerGlobalScope
has a
- report url
-
Null, failure, or a URL. Defaulting to null.
- reporting beacon map
-
Null or an ordered map whose keys are strings and whose values are URLs. Defaulting to null.
- reporting macro map
-
Null or an ordered map whose keys are strings and whose values are strings. Defaulting to null.
sendReportTo(url)
method steps are:
-
If this's relevant global object's report url is not null:
-
Set this's relevant global object's report url to failure.
-
-
Let parsedUrl be the result of running the URL parser on url.
-
If parsedUrl is failure, or parsedUrl’s scheme is not "
https
", set this's relevant global object's report url to failure and Throw aTypeError
. -
Optionally, return.
Note: This implementation-defined condition is intended to allow user agents to decline for a number of reasons, for example the parsedUrl’s site not being enrolled.
-
Set this's relevant global object's report url to parsedUrl.
registerAdBeacon(map)
method steps are:
-
If this's relevant global object's reporting beacon map is not null, then Throw a
TypeError
. -
-
Let parsedURL be the result of running URL parser on url.
-
Throw a
TypeError
if any of the following conditions hold:-
parsedURL is failure;
-
parsedURL’s scheme is not "
https
".
-
-
-
Set this's relevant global object's reporting beacon map to map.
registerAdMacro(name, value)
method steps are:
-
Set this's relevant global object's reporting macro map[name] to value.
7. Interest Group Updates
Interest groups have a update url field that allows updating the
interest group definition stored on disk with information periodically retrieved from the update url. The interest group update steps are triggered during runAdAuction()
and by calls to updateAdInterestGroups()
API:
[SecureContext ]partial interface Navigator {undefined updateAdInterestGroups (); };
The updateAdInterestGroups()
method steps are:
-
In parallel, run interest group update with « relevant settings object's top-level origin »
-
For each owner of owners:
-
For each originalInterestGroup of the user agent’s interest group set whose owner is owner and next update after is before the current wall time:
Note: Implementations can consider loading only a portion of these interest groups at a time to avoid issuing too many requests at once.
-
Let ig be a deep copy of originalInterestGroup.
-
Let request be a new request with the following properties:
- URL
-
ig’s update url
- header list
-
«
Accept
:application/json
» - client
-
null
- mode
-
"
no-cors
" - referrer
-
"
no-referrer
" - credentials mode
-
"
omit
" - redirect mode
-
"
error
"
One of the side-effects of a
null
client for this subresource request is it neuters all service worker interceptions, despite not having to set the service workers mode.Stop using "
no-cors
" mode where possible (WICG/turtledove#667). -
Let update be null.
-
Fetch request with useParallelQueue set to true, and processResponseConsumeBody set to the following steps given a response response and null, failure, or a byte sequence responseBody:
-
If validate fetching response with response, responseBody and "
application/json
" returns false, set update to failure and return. -
Set update to responseBody.
-
-
Wait for update to be set.
-
If update is failure, continue.
-
Let parsedUpdate be the result of parsing JSON bytes to an Infra value, given update.
-
If parsedUpdate is failure, continue.
-
If parsedUpdate is not an ordered map, continue.
-
If parsedUpdate["
name
"] exists and doesn’t match ig’s name, continue. -
If parsedUpdate["
owner
"] exists and doesn’t match ig’s owner, continue. -
For each key → value of parsedUpdate:
-
Switch on key:
- "
priority
" -
-
Otherwise, jump to the step labeled Abort update.
- "
enableBiddingSignalsPrioritization
" -
-
If value is a
boolean
, set ig’s enable bidding signals prioritization to value. -
Otherwise, jump to the step labeled Abort update.
-
- "
priorityVector
" -
-
If value is null or an ordered map whose keys are strings and whose values are
double
, set ig’s priority vector to value. -
Otherwise, jump to the step labeled Abort update.
-
- "
prioritySignalsOverrides
" -
-
If value is an ordered map whose keys are strings and whose values are
double
or null:-
For each pvKey → pvValue of value:
-
If pvValue is null, remove ig’s priority signals overrides[pvKey].
-
Otherwise, set ig’s priority signals overrides[pvKey] to pvValue.
-
-
-
Otherwise, jump to the step labeled Abort update.
-
- "
executionMode
" -
-
If value is "
compatibility
" or "group-by-origin
", set ig’s execution mode to value. -
Otherwise, jump to the step labeled Abort update.
-
- "
biddingLogicURL
"- "
biddingWasmHelperURL
"- "
updateURL
"- "
trustedBiddingSignalsURL
" - "
-
-
For each groupMember and interestGroupField in the following table
Group member Interest group field " biddingLogicURL
"bidding url " biddingWasmHelperURL
"bidding wasm helper url " updateURL
"update url " trustedBiddingSignalsURL
"trusted bidding signals url -
Let parsedURL be the result of running the URL parser on value.
-
If key is not groupMember, continue.
-
Jump to the step labeled Abort update if any of the following conditions hold:
-
parsedURL is failure;
-
parsedURL’s origin is not same origin with ig’s owner;
-
parsedURL includes credentials;
-
parsedURL fragment is not null.
-
-
Set ig’s interestGroupField to parsedURL.
-
-
- "
trustedBiddingSignalsKeys
" -
-
If value is a list of strings, set ig’s trusted bidding signals keys to value.
-
Otherwise, jump to the step labeled Abort update.
-
- "
ads
"- "
adComponents
" - "
-
-
For each groupMember and interestGroupField in the following table
Group member Interest group field " ads
"ads " adComponents
"ad components -
If key is not groupMember, continue.
-
If value is not a list of
AuctionAd
, jump to the step labeled Abort update. -
For each ad of value:
-
Let igAd be a new interest group ad.
-
Let renderURL be the result of running the URL parser on ad["
renderURL
"]. -
Jump to the step labeled Abort update if any of the following conditions hold:
-
renderURL is failure;
-
renderURL scheme is not "
https
"; -
renderURL includes credentials.
-
-
Set igAd’s render url to renderURL.
-
If ad["
metadata
"] exists, then let igAd’s metadata be the result of serializing a JavaScript value to a JSON string, given ad["metadata
"]. If this throws, jump to the step labeled Abort update. -
If groupMember is "
ads
":-
If ad["
buyerReportingId
"] exists then set igAd’s buyer reporting ID to it. -
If ad["
buyerAndSellerReportingId
"] exists then set igAd’s buyer and seller reporting ID to it.
-
-
Append igAd to ig’s interestGroupField.
-
-
-
- "
-
-
Set ig’s next update after to the current wall time plus 24 hours.
-
Replace the interest group that has ig’s owner and name in the browser’s interest group set with ig.
-
Abort update: We jump here if some part of the interest group update failed. Continue to the next interest group update.
-
-
8. Permissions Policy integration
This specification defines two policy-controlled features identified by the strings
"join-ad-interest-group
", and
"run-ad-auction
". Their default allowlists are "*
".
Currently they're *
.
9. Structures
dictionary {
PreviousWin required long long ;
timeDelta required DOMString ; };
adJSON dictionary {
BiddingBrowserSignals required DOMString ;
topWindowHostname required USVString ;
seller required long ;
joinCount required long ;
bidCount required long ;
recency USVString ;
topLevelSeller sequence <PreviousWin >;
prevWinsMs object ;
wasmHelper unsigned long ; };
dataVersion dictionary {
ScoringBrowserSignals required DOMString ;
topWindowHostname required USVString ;
interestGroupOwner required USVString ;
renderURL required unsigned long ;
biddingDurationMsec required DOMString ;
bidCurrency unsigned long ;
dataVersion sequence <USVString >; };
adComponents
Note: ScoringBrowserSignals
's adComponents
is undefined
when ad component descriptors is null or an empty list. It cannot be
an empty list.
dictionary {
ReportingBrowserSignals required DOMString ;
topWindowHostname required USVString ;
interestGroupOwner required USVString ;
renderURL required double ;
bid required double ;
highestScoringOtherBid DOMString ;
bidCurrency DOMString ;
highestScoringOtherBidCurrency USVString ;
topLevelSeller USVString ;
componentSeller USVString ; };
buyerAndSellerReportingId
ReportingBrowserSignals
includes browser signals both reportResult()
and reportWin()
get.
topWindowHostname
- Top-level origin's host
interestGroupOwner
- The winning interest group's owner.
renderURL
- The render URL returned by "
generateBid()
". It is k-anonymous bid
- Stochastically rounded winning bid. This is always in the bidder’s own currency
highestScoringOtherBid
-
The stochastically rounded value of the bid that got the second highest score, or 0 if it’s
not available. 0 for top-level auctions with components
bidCurrency
- The currency the
bid
is in highestScoringOtherBidCurrency
- The currency the
highestScoringOtherBid
is in topLevelSeller
- Copied from top level seller
componentSeller
- Copied from component seller
buyerAndSellerReportingId
- Set if the winning ad had a buyer and seller reporting ID set in its listing in the interest group, and that value was jointly k-anonymous combined with interest group owner, bidding script URL, and ad creative URL.
dictionary :
ReportResultBrowserSignals ReportingBrowserSignals {required double ;
desirability DOMString ;
topLevelSellerSignals double ;
modifiedBid unsigned long ; };
dataVersion
desirability
- The stochastically rounded value of the score returned by "
scoreAd()
" for the winning bid topLevelSellerSignals
- Metadata returned by the top-level seller’s "
reportResult()
", as JSON modifiedBid
- The stochastically rounded value of the bid value returned by the component
seller’s "
scoreAd()
" method dataVersion
- Set to the value of the `
Data-Version
` header from the trusted scoring signals server, if any.
dictionary :
ReportWinBrowserSignals ReportingBrowserSignals {double ;
adCost USVString ;
seller boolean ;
madeHighestScoringOtherBid DOMString ;
interestGroupName DOMString ;
buyerReportingId unsigned short ;
modelingSignals unsigned long ; };
dataVersion
adCost
- Stochastically rounded winner’s ad cost.
seller
- The origin of the seller running the ad auction
madeHighestScoringOtherBid
- True if the interest group owner was the only bidder that made bids with the second highest score
buyerReportingId
- Set if the winning ad had a buyer reporting ID but not a buyer and seller reporting ID set in its listing in the interest group, and that value was jointly k-anonymous combined with interest group owner, bidding script URL, and ad creative URL.
interestGroupName
-
Only set if the tuple of interest group owner, name, bidding script URL and ad creative URL
were jointly k-anonymous, and the winning ad had neither buyer and seller reporting ID nor buyer reporting ID set in its listing in the interest group.
modelingSignals
- A 0-4095 integer (12-bits) passed to
reportWin()
, with noising dataVersion
- Only set if the Data-Version header was provided in the response headers from the trusted bidding signals server
9.1. Interest group
An interest group is a struct with the following items:
- expiry
-
A moment at which the browser will forget about this interest group.
- owner
-
An origin. Frames that join interest groups owned by owner must either be served from owner, or another origin delegated by owner (See checking interest group permissions for details). The scheme must be "
https
". - name
-
A string. The (owner, name) tuple is a key that uniquely defines each interest group.
- priority
-
A
double
, initially 0.0. Used to select which interest groups participate in an auction when the number of interest groups are limited byperBuyerGroupLimits
. See applying interest groups limits to prioritized list. - enable bidding signals prioritization
-
A boolean, initially false. Being true if the interest group’s priority should be calculated using vectors from bidding signals fetch.
- priority vector
-
Null or an ordered map whose keys are strings and whose values are
double
. Its dot product with theperBuyerPrioritySignals
will be used in place of priority, if set. - priority signals overrides
-
Null or an ordered map whose keys are strings and whose values are
double
. Overrides theAuctionAdConfig
's corresponding priority signals. - execution mode
-
"
compatibility
" or "group-by-origin
". TODO: Define spec for these execution modes, link to it from here and explain these modes. - bidding url
-
Null or a URL. The URL to fetch the buyer’s JavaScript from.
When non-null, the bidding url's origin will always be same origin with owner.
- bidding wasm helper url
-
Null or a URL. Lets the bidder provide computationally-expensive subroutines in WebAssembly, in addition to JavaScript, to be driven from the JavaScript function provided by bidding url.
When non-null, the bidding wasm helper url's origin will always be same origin with owner.
- update url
-
Null or a URL. Provides a mechanism for the group’s owner to periodically update the attributes of the interest group. See interest group updates.
When non-null, the update url's origin will always be same origin with owner.
- trusted bidding signals url
-
Null or a URL. Provide a mechanism for making real-time data available for use at bidding time. See building trusted bidding signals url.
When non-null, the trusted bidding signals url's origin will always be same origin with owner.
- trusted bidding signals keys
-
Null or a list of string. See building trusted bidding signals url.
- user bidding signals
-
Null or a string. Additional metadata that the owner can use during on-device bidding.
- ads
-
Null or a list of interest group ad. Contains various ads that the interest group might show.
- ad components
-
Null or a list of interest group ad. Contains various ad components (or "products") that can be used to construct ads composed of multiple pieces — a top-level ad template "container" which includes some slots that can be filled in with specific "products".
- joining origin
-
An origin. The top level page origin from where the interest group was joined.
- join counts
-
A list containing tuples of the day and per day join count. The day is calculated based on UTC time. The join count is a count of the number of times
joinAdInterestGroup()
was called for this interest group on the corresponding day. - join time
-
A moment at which the browser joined this interest group, updated upon each join and re-join.
- bid counts
-
A list containing tuples of the day and per day bid count. The day is calculated based on UTC time. The bid count is a count of the number of times the bid calculated during
runAdAuction()
was greater than 0. - previous wins
-
A list of previous wins.
- next update after
-
A moment at which the browser will permit updating this interest group. See interest group updates.
9.2. Interest group ad
An interest group ad is a struct with the following items:
- render url
-
A URL. If this ad wins the auction, this URL (or a urn uuid that maps to this URL) will be returned by
runAdAuction()
. This URL is intended to be loaded into an adiframe
(or afencedframe
). - metadata
-
Null or a string. Extra arbitary information about this ad, passed to
generateBid()
. - buyer reporting ID
-
Null or a string. Will be passed in place of interest group name to report win, subject to k-anonymity checks. Only meaningful in ads, but ignored in ad components.
- buyer and seller reporting ID
-
Null or a string. Will be passed in place of interest group name or buyer reporting ID to report win and report result, subject to k-anonymity checks. Only meaningful in ads, but ignored in ad components.
- allowed reporting origins
-
Null or a list of origins. A list of up to 10 reporting origins that can receive reports with registered macros. All origins must be HTTPS origins and enrolled. Only meaningful in ads, but ignored in ad components.
9.3. Currency tag
A currency tag is a string containing exactly 3 upper-case ASCII letters, or null. The null value is used to denote that the currency is unspecified.-
If currency is null, return "???".
-
Return currency.
-
If length of currencyString is not 3, return false.
-
If currencyString[0] is not a ASCII upper alpha code point, return false.
-
If currencyString[1] is not a ASCII upper alpha code point, return false.
-
If currencyString[2] is not a ASCII upper alpha code point, return false.
-
Return true.
-
If expected is null, return true.
-
If actual is null, return true.
-
If actual is equal to expected, return true.
-
Return false.
9.4. Auction config
An auction config is a struct with the following items:
- seller
-
An origin. The origin of the seller running the ad auction. The scheme must be "
https
". - decision logic url
-
A URL. The URL to fetch the seller’s JavaScript from.
The decision logic url's origin will always be same origin with seller.
- trusted scoring signals url
-
Null or a URL. Provide a mechanism for making real-time data (information about a specific creative) available for use at scoring time, e.g. the results of some ad scanning system.
When non-null, the trusted scoring signals url's origin will always be same origin with seller.
- interest group buyers
-
Null or a list of origins. Owners of interest groups allowed to participate in the auction. Each origin’s scheme must be "
https
". - auction signals
-
Null, a string, a
Promise
, or failure. Opaque JSON data passed to both sellers' and buyers' script runners. - seller signals
-
Null, a string, a
Promise
, or failure. Opaque JSON data passed to the seller’s script runner. - seller timeout
-
A duration in milliseconds, initially 50 milliseconds. Restricts the runtime of the seller’s
scoreAd()
script. If scoring does not complete before the timeout, the bid being scored is not considered further. - per buyer signals
-
Null, a
Promise
, failure, or an ordered map whose keys are origins and whose values are strings. Keys are buyers and must be valid HTTPS origins. Values are opaque JSON data passed to corresponding buyer’s script runner. - per buyer timeouts
-
Null, a
Promise
, failure, or an ordered map whose keys are origins and whose values are durations in milliseconds. Keys are buyers and must be valid HTTPS origins. Values restrict the runtime of corresponding buyer’sgenerateBid()
script. If the timeout expires, only the bid submitted viasetBid()
is considered. - all buyers timeout
-
A duration in milliseconds, initially 50 milliseconds. Restricts the
generateBid()
script’s runtime for all buyers without a timeout specified in per buyer timeouts. If the timeout expires, only the bid submitted viasetBid()
is considered. - per buyer group limits
-
Null or an ordered map whose keys are origins and whose values are
unsigned short
s. Keys are buyers and must be valid HTTPS origins. Values restrict the number of bidding interest groups for a particular buyer that can participate in an auction. - all buyers group limit
-
An
unsigned short
, initially 65535. Limit on the number of bidding interest groups for all buyers without a limit specified in per buyer group limits. - per buyer priority signals
-
Null or an ordered map whose keys are origins and whose values are ordered maps, whose keys are strings and whose values are
double
. Per-buyer sparse vector whose dot product with priority vector is used to calculate interest group priorities. No signal’s key starts with "browserSignals.", which is reserved for values coming from the browser. - all buyers priority signals
-
Null or an ordered map whose keys are strings and whose values are
double
. Merged with per buyer priority signals before calculating per-interest group priorities. In the case both have entries with the same key, the entry inper_buyer_priority_signals
takes precedence. No signals key start with "browserSignals.", which is reserved for values coming from the browser. - component auctions
-
A list of auction configs. Nested auctions whose results will also participate in a top level auction. Only the top level auction config can have component auctions.
- seller experiment group id
-
Null or an
unsigned short
, initially null. Optional identifier for an experiment group to support coordinated experiments with the seller’s trusted server. - per buyer experiment group ids
-
An ordered map whose keys are origins and whose values are
unsigned short
s. Keys are buyers and must be valid HTTPS origins. Values are identifiers for experiment groups, to support coordinated experiments with buyers' trusted servers. - all buyer experiment group id
-
Null or an
unsigned short
, initially null. Optional identifier for an experiment group to support coordinated experiments with buyers' trusted servers for buyers without a specified experiment group. - pending promise count
-
An integer, initially 0. The number of auction signals, per buyer signals, per buyer currencies, per buyer timeouts, directFromSellerSignals, or seller signals whose
Promise
s are not yet resolved. - config idl
- resolve to config
-
A boolean or a
Promise
, initially false. Whether the ad should be returned as aFencedFrameConfig
, or otherwise as a urn uuid. - seller currency
-
A currency tag. Specifies the currency bids returned by
scoreAd()
are expected to use, and which reporting for this auction will agree on. - per buyer currencies
-
A
Promise
or failure or an ordered map whose keys are origins and whose values are currency tags. Specifies the currency bids returned bygenerateBid()
orscoreAd()
in component auctions are expected to use. The initial value is an empty map. - all buyers currency
-
A currency tag. Specifies the currency bids returned by
generateBid()
orscoreAd()
in component auctions are expected to use if per buyer currencies does not specify a particular value.
-
Wait until auctionConfig’s pending promise count is 0.
-
Assert auctionConfig’s auction signals, seller signals, per buyer signals, per buyer currencies, and per buyer timeouts are not
Promise
s. -
If auctionConfig’s auction signals, seller signals, per buyer signals, per buyer currencies or per buyer timeouts is failure, return failure.
-
TODO: the above two steps should also check directFromSellerSignals once something handles it.
-
For each componentAuctionConfig in auctionConfig’s component auctions:
-
If the result of waiting until configuration input promises resolve given componentAuctionConfig is failure, return failure.
-
-
Return the result of waiting until configuration input promises resolve given auctionConfig.
Promise
p, and two sequences of steps, covering the parsing of the value and error-handling:
-
Increment auctionConfig’s pending promise count.
-
Let resolvedAndTypeChecked be the promise representing performing the following steps upon fulfillment of p with result:
-
Execute the steps to be run for parsing of the value given result.
-
If no exception was thrown in the previous step:
-
Decrement auctionConfig’s pending promise count.
-
-
-
Upon rejection of resolvedAndTypeChecked:
-
Execute the steps for error-handling.
-
Decrement auctionConfig’s pending promise count.
-
-
Let perBuyerCurrency be auctionConfig’s all buyers currency
-
Assert: auctionConfig’s per buyer currencies is an ordered map.
-
If auctionConfig’s per buyer currencies[buyer] exists:
-
Set perBuyerCurrency to auctionConfig’s per buyer currencies[buyer].
-
-
Return perBuyerCurrency
9.5. Per buyer bid generator
A per buyer bid generator is an ordered map whose keys are URLs representing trusted bidding signals urls, and whose values are per signals url bid generators.
9.6. Per signals url bid generator
A per signals url bid generator is an ordered map whose keys are origins representing joining origins, and whose values are lists of interest groups.
9.7. Previous win
The interest group's auction win history, to allow on-device frequency capping.
- time
-
A moment. Approximate time the interest group won an auction.
- ad json
-
A string. A JSON serialized object corresponding to the ad that won the auction.
9.8. Bid with currency
Numeric value of a bid and the currency it is in.- value
-
A
double
. The value of the bid. - currency
-
A currency tag. The currency the bid is in.
9.9. Generated bid
The output of running a Protected Audience generateBid()
script, which needs to be scored by
the seller.
- bid
-
A bid with currency. If the value is zero or negative, then this interest group will not participate in the auction.
- bid in seller currency
-
A
double
or null. An equivalent of the original bid in seller’s currency. This is either the original bid if the currency already matched, or a conversion provided byscoreAd()
. - ad
-
A string. JSON string to be passed to the scoring function.
- ad descriptor
-
An ad descriptor. Render URL and size of the bid’s ad.
- ad component descriptors
-
Null or a list of ad descriptors. Ad components associated with bid, if any. May have at most 20 URLs. Must be null if the interest group making this bid has a null ad components field.
- ad cost
-
Null or a
double
. Advertiser click or conversion cost passed fromgenerateBid()
toreportWin()
. Negative values will be ignored and not passed. Will be stochastically rounded when passed. - modeling signals
-
Null or an
unsigned short
. A 0-4095 integer (12-bits) passed toreportWin()
, with noising. - interest group
-
An interest group, whose
generateBid()
invocation generated this bid. - bid ad
-
The interest group ad within interest group to display.
- modified bid
-
Null or a bid with currency. Being null for top level auction. The bid value a component auction’s
scoreAd()
script returns. - bid duration
-
A duration in milliseconds. How long it took to run
generateBid()
.
9.10. Ad descriptor
The render URL and size of an ad.
- url
-
A URL, which will be rendered to display the creative if this bid wins the auction.
- size
-
Null or an ad size, initially null.
9.11. Ad size
Width and height of an ad.
- width
-
A
double
. - width units
-
A string. Can only be one of "px" (pixel), "sh" (screen height), and "sw" (screen width).
- height
-
A
double
. - height units
-
A string. Can only be one of "px" (pixel), "sh" (screen height), and "sw" (screen width).
9.12. Score ad output
The output of running a Protected Audience scoreAd()
script, is represented using the following type:
dictionary {
ScoreAdOutput required double ;
desirability double ;
bid DOMString ;
bidCurrency double ;
incomingBidInSellerCurrency boolean =
allowComponentAuction false ; };
Either a dictionary of this type, or a double
, are handled as the return values.
The meanings of the fields are as follows:
desirability
- Numeric score of the bid. Must be positive or the ad will be rejected. The winner of the auction is the bid which was given the highest score.
bid
- Only relevant if this is a component auction. If present, this will be passed to the top-level
seller’s
scoreAd()
andreportResult()
methods instead of the original bid, if the ad wins the component auction and top-level auction, respectively. bidCurrency
- Only relevant if this is a component auction and
bid
is set. Specifies which currency thebid
field is in. incomingBidInSellerCurrency
- Provides a conversion of the incoming bid to auction’s seller currency. This is different from
bid
which is the bid the component auction itself produces. allowComponentAuction
- If the bid being scored is from a component auction and this value is not true, the bid is ignored. 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.
TODO: This also has an ad field, which should behave similar to the way bid
affects modified bid, and then affecting the adMetadata parameter to scoreAd.
To process scoreAd output given an Completion Record result:
-
If result is an an abrupt completion, return failure.
-
If result.[[Value]] is a Number:
-
Let checkedScore be the result of converting result.[[Value]] to a
double
. -
If an exception was thrown in the previous step, return failure.
-
Let resultIDL be a new
ScoreAdOutput
. -
Set resultIDL’s
desirability
to checkedScore. -
Return resultIDL.
-
-
Let resultIDL be the result of converting result.[[Value]] to a
ScoreAdOutput
. -
If an exception was thrown in the previous step, return failure.
-
If resultIDL["
bidCurrency
"] exists and result of checking whether a string is a valid currency tag applied to resultIDL["bidCurrency
"] is false:-
Return failure.
-
-
Return resultIDL.
9.13. Leading bid info
Information of the auction’s leading bid so far when ranking scored bids.
- top score
-
A
double
, initially 0.0. The highest score so far. - top bids count
-
An integer, initially 0. The number of bids with the same
top score
. - at most one top bid owner
-
A boolean, initially true. Whether all bids of
top score
are from the same interest group owner. - leading bid
-
Null or a generated bid. The leading bid of the auction so far.
- auction config
-
An auction config. The auction config of the auction which generated this leading bid.
- second highest score
-
A
double
, initially 0.0. The second highest score so far. If more than one bids tie withtop score
, this will be set totop score
. - highest scoring other bids count
-
An integer, initially 0. The number of bids with the same
second highest score
. - highest scoring other bid
-
Null or a generated bid. The second highest scoring other bid.
- highest scoring other bid owner
-
Null or an origin, initially null. The interest group owner that made bids with the
second highest score
. Set to null if there are more than one owners made bids with thesecond highest score
. - top level seller
-
Null or a string. The seller in the top level auction. Only set for component auctions, null otherwise.
- top level seller signals
-
Null or a string. Signals from the seller in the top level auction, produced as the output of the top-level seller’s
reportResult()
method. Only set for component auctions, null otherwise. - component seller
-
Null or a string. Seller in component auction which generated this leading bid. Only set the top level auction when component auctions are present, null otherwise.
- bidding data version
-
Null or an
unsigned long
. Data-Version value from the trusted bidding signals server’s response(s). Will only be not null if the Data-Version header was provided and had a consistent value for all of the trusted bidding signals server responses used to construct the trustedBiddingSignals. - scoring data version
-
Null or an
unsigned long
. Data-Version value from the trusted scoring signals server’s response. Will only be not null if the Data-Version header was provided in the response headers from the trusted scoring signals server. - buyer reporting result
-
Null or a reporting result, initially null.
- seller reporting result
-
Null or a reporting result, initially null.
- component seller reporting result
-
Null or a reporting result, initially null.
A reporting result is a struct with the following items:
- report url
-
Null or a URL, initially null. Set by
sendReportTo(url)
. - reporting beacon map
-
Null or an ordered map whose keys are strings and whose values are URLs, initially null. Set by
registerAdBeacon(map)
. - reporting macro map
-
Null or an ordered map whose keys are strings and whose values are strings, initially null. Set by
registerAdMacro(name, value)
.
10. Privacy Considerations
Protected Audience aims to advance the privacy of remarketing and custom audience advertising on the web, so naturally privacy considerations are paramount to Protected Audience’s design. Partitioning data by site is the central mechanism to prevent joining a user’s identity across sites:
-
Interest group definitions come from just one site, the site that called
joinAdInterestGroup()
. -
Bidding (
generateBid()
) and scoring (scoreAd()
) scripts are exposed to interest group data from the joining site, and data from the site that will display the ad, but these scripts are run in strict isolation to prevent leaking this cross-site information. -
The browser can enforce that trusted bidding and scoring signals are fetched from servers complying with certain privacy requirements, e.g. not performing event-level logging.
-
Ads are rendered in
fencedframe
s that isolate them from the surrounding page to prevent cross-site leakage. -
Reporting is strictly controlled by the browser to prevent cross-site leaks: Inputs to event-level reporting functions,
reportWin()
andreportResult()
, only contain limited cross-site information, e.g. the k-anonymous ad URL. Event-level reporting is meant to be a temporary stepping stone to more private mechanisms like Private Aggregation API.
11. Security Considerations
Protected Audience involves the browser running untrusted JavaScript downloaded from multiple parties, so security concerns are top of mind. Fortunately Protected Audience is a highly constrained API not attempting to be a general purpose execution environment. Execution of this JavaScript is controlled and limited as follows:
-
Protected Audience requires the origin of the scripts’ URLs to match that of the origin of the interest group owner, which is in turn required to match the origin of the context calling the
joinAdInterestGroup()
. -
URL schemes are required to be HTTPS.
-
Redirects are disallowed.
-
Responses are required to contain the
Ad-Auction-Allowed: ?1
header. -
Fetches are uncredentialed.
Protected Audience has the browser pass in several “browserSignals” to the bidding script that give the script unforgeable information about the context that the script is being executed in. This way bidders and sellers have the choice to only participate in auctions where they are comfortable working with the involved parties.
The execution environment available to these scripts is the absolute minimum necessary to calculate
a bid. It supports only ECMAScript. It does not support network, storage, timer, date, DOM, Workers, postMessage, Navigator or Window APIs.
Protected Audience adds Permission-Policies to control access to the Protected Audience APIs to give sites and embedders the ability to clamp down on use of the APIs as they see fit.