1. Introduction
This section is non-normative
This specification describes how web browsers can provide a mechanism to the web that supports measuring and attributing conversions (e.g. purchases) to ads a user interacted with on another site. This mechanism should remove one need for cross-site identifiers like third-party cookies.
1.1. Overview
Pages/embedded sites are given the ability to register attribution sources and attribution triggers, which can be linked by the User Agent to generate and send attribution reports containing information from both of those events.
A reporter https://reporter.example embedded on https://source.example is able to
measure whether an iteraction on the page lead to an action on https://destination.example by registering an attribution source with attribution destinations of « https://destination.example ». Reporters are able to register sources through a variety
of surfaces, but ultimately the reporter is required to provide the User Agent with an
HTTP-response header which allows the source to be eligible for attribution.
At a later point in time, the reporter, now embedded on https://destination.example,
may register an attribution trigger. Reporters can register triggers by sending an
HTTP-response header containing information about the action/event that occurred. Internally,
the User Agent attempts to match the trigger to previously registered source events based on
where the sources/triggers were registered and configurations provided by the reporter.
If the User Agent is able to attribute the trigger to a source, it will generate and send an attribution report to the reporter via an HTTP POST request at a later point in time.
2. HTML monkeypatches
2.1. API for elements
interface mixin { [HTMLAttributionSrcElementUtils CEReactions ]attribute USVString ; };attributionSrc HTMLAnchorElement includes HTMLAttributionSrcElementUtils ;HTMLImageElement includes HTMLAttributionSrcElementUtils ;HTMLScriptElement includes HTMLAttributionSrcElementUtils ;
Add the following content attributes:
a-
attributionsrc- URL for attribution registration img-
attributionsrc- URL for attribution registration script-
attributionsrc- URL for attribution registration
Add the following content attribute descriptions:
a-
The
attributionsrcattribute is a string representing the URL of the resource that will register an attribution source when theais navigated. img-
The
attributionsrcattribute is a string representing the URL of the resource that will register an attribution source or attribution trigger when set. script-
The
attributionsrcattribute is a string representing the URL of the resource that will register an attribution source or attribution trigger when set.
The IDL attribute attributionSrc must reflect the respective content attribute of the same
name.
2.2. Window open steps
3. Fetch monkeypatches
Specify monkeypatches for source/trigger registration.
4. Permissions Policy integration
This specification defines a policy-controlled feature identified by the string "attribution-reporting". Its default allowlist is 'self'.
Note: In the Chromium implementation the default allowlist is temporarily set to * to ease testing.
5. Structures
5.1. Trigger state
A trigger state is a struct with the following items:
- trigger data
-
A non-negative 64-bit integer.
- report window
-
A non-negative integer.
5.2. Randomized source response
A randomized source response is null or a set of trigger states.
5.3. Attribution filtering
A filter value is an ordered set of strings.
A filter map is an ordered map whose keys are strings and whose values are filter values.
5.4. Suitable origin
A suitable origin is an origin that is suitable.
5.5. Source type
A source type is one of the following:
- "
navigation" -
The source was associated with a top-level navigation.
- "
event" -
The source was not associated with a top-level navigation.
5.6. Attribution source
An attribution source is a struct with the following items:
- source identifier
-
A string.
- source origin
- event ID
-
A non-negative 64-bit integer.
- attribution destinations
-
An ordered set of sites.
- reporting endpoint
- source type
-
A source type.
- expiry
-
A length of time.
- event report window
-
A length of time.
- aggregatable report window
-
A length of time.
- priority
-
A 64-bit integer.
- source time
-
A point in time.
- number of event-level reports
-
Number of event-level reports created for this attribution source.
- event-level attributable (default true)
-
A boolean.
- dedup keys
-
ordered set of dedup keys associated with this attribution source.
- randomized response
- randomized trigger rate
-
A number between 0 and 1 (both inclusive).
- filter data
-
A filter map.
- debug key
-
Null or a non-negative 64-bit integer.
- aggregation keys
-
An ordered map whose keys are strings and whose values are non-negative 128-bit integers.
- aggregatable budget consumed
-
A non-negative integer, total value of all aggregatable contributions created with this attribution source.
- aggregatable dedup keys
-
ordered set of aggregatable dedup keys associated with this attribution source.
- debug reporting enabled
-
A boolean.
5.7. Aggregatable trigger data
An aggregatable trigger data is a struct with the following items:
- key piece
-
A non-negative 128-bit integer.
- source keys
-
An ordered set of strings.
- filters
-
A filter map.
- negated filters
-
A filter map.
5.8. Event-level trigger configuration
An event-level trigger configuration is a struct with the following items:
- trigger data
-
A non-negative 64-bit integer.
- dedup key
-
Null or a non-negative 64-bit integer.
- priority
-
A 64-bit integer.
- filters
-
A filter map.
- negated filters
-
A filter map.
5.9. Attribution trigger
An attribution trigger is a struct with the following items:
- attribution destination
-
A site.
- trigger time
-
A point in time.
- reporting endpoint
- filters
-
A filter map.
- negated filters
-
A filter map.
- debug key
-
Null or a non-negative 64-bit integer.
- event-level trigger configurations
- aggregatable trigger data
- aggregatable values
-
An ordered map whose keys are strings and whose values are non-negative 32-bit integers.
- aggregatable dedup key
-
Null or a non-negative 64-bit integer.
- serialized private state token
- debug reporting enabled
-
A boolean.
5.10. Attribution report
An attribution report is a struct with the following items:
- reporting endpoint
- report time
-
A point in time.
- delivered (default false)
-
A boolean.
- report ID
-
A string.
- source debug key
-
Null or a non-negative 64-bit integer.
- trigger debug key
-
Null or a non-negative 64-bit integer.
5.11. Event-level report
An event-level report is an attribution report with the following additional items:
- event ID
-
A non-negative 64-bit integer.
- source type
-
A source type.
- trigger data
-
A non-negative 64-bit integer.
- randomized trigger rate
-
A number between 0 and 1 (both inclusive).
- trigger priority
-
A 64-bit integer.
- trigger time
-
A point in time.
- source identifier
-
A string.
- attribution destinations
-
An ordered set of sites.
5.12. Aggregatable contribution
An aggregatable contribution is a struct with the following items:
- key
-
A non-negative 128-bit integer.
- value
-
A non-negative 32-bit integer.
5.13. Aggregatable report
An aggregatable report is an attribution report with the following additional items:
- source time
-
A point in time.
- original report time
-
A point in time.
- contributions
- effective attribution destination
-
A site.
- serialized private state token
5.14. Attribution rate-limits
A rate-limit scope is one of the following:
- "
source" - "
attribution"
An attribution rate-limit record is a struct with the following items:
- scope
- source site
-
A site.
- attribution destination
-
A site.
- reporting endpoint
- time
-
A point in time.
expiry time
Null or a point in time.
5.15. Attribution debug data
A debug data type is a non-empty string that specifies the set of data that is contained in the body of an attribution debug data.
A source debug data type is a debug data type for source registrations. Possible values are:
- "
source-destination-limit" - "
source-noised" - "
source-storage-limit" - "
source-unknown-error"
A trigger debug data type is a debug data type for trigger registrations. Possible values are:
- "
trigger-aggregate-deduplicated" - "
trigger-aggregate-no-contributions" - "
trigger-aggregate-insufficient-budget" - "
trigger-aggregate-storage-limit" - "
trigger-aggregate-report-window-passed" - "
trigger-attributions-per-source-destination-limit" - "
trigger-event-deduplicated" - "
trigger-event-excessive-reports" - "
trigger-event-low-priority" - "
trigger-event-no-matching-configurations" - "
trigger-event-noise" - "
trigger-event-report-window-passed" - "
trigger-event-storage-limit" - "
trigger-no-matching-source" - "
trigger-no-matching-filter-data" - "
trigger-reporting-origin-limit" - "
trigger-unknown-error"
An attribution debug data is a struct with the following items:
- data type
- body
5.16. Attribution debug report
An attribution debug report is a struct with the following items:
- data
-
A list of attribution debug data.
- reporting endpoint
5.17. Triggering result
A triggering status is one of the following:
- "
dropped" - "
cache full" - "
attributed"
A triggering result is a tuple with the following items:
- status
- debug data
-
Null or an attribution debug data.
6. Storage
A user agent holds an attribution source cache, which is an ordered set of attribution sources.
A user agent holds an event-level report cache, which is an ordered set of event-level reports.
A user agent holds an aggregatable report cache, which is an ordered set of aggregatable reports.
A user agent holds an attribution rate-limit cache, which is an ordered set of attribution rate-limit records.
The above caches are collectively known as the attribution caches. The attribution caches are shared among all environment settings objects.
Note: This would ideally use storage bottles to provide access to the attribution caches. However attribution data is inherently cross-site, and operations on storage would need to span across all storage bottle maps.
7. Vendor-Specific Values
Source event ID cardinality is a positive integer that controls the maximum value that can be used as an event id.
Max source expiry is a positive length of time that controls the maximum value that can be used as an expiry. It must be greater than or equal to 30 days.
Max entries per filter map is a positive integer that controls the maximum size of a filter map.
Max values per filter entry is a positive integer that controls the maximum size of a filter map entry.
Max aggregation keys per attribution is a positive integer that controls the maximum size of an attribution source's aggregation keys, the maximum size of an aggregatable trigger data's source keys, and the maximum size of an attribution trigger's aggregatable values.
Max aggregatable trigger data per trigger is a positive integer that controls the maximum size of an attribution trigger's aggregatable trigger data.
Max bytes per aggregation key identifier is a positive integer that controls the maximum length or code point length of an aggregation key identifier.
Max pending sources per source origin is a positive integer that controls how many attribution sources can be in the attribution source cache per source origin.
Navigation-source trigger data cardinality is a positive integer
that controls the valid range of trigger data for triggers that are
attributed to an attribution source whose source type is "navigation":
0 <= trigger data < navigation-source trigger data cardinality.
Event-source trigger data cardinality is a positive integer that
controls the valid range of trigger data for triggers that are attributed to an attribution source whose source type is "event":
0 <= trigger data < event-source trigger data cardinality.
Randomized navigation-source trigger rate is a double between 0 and
1 (both inclusive) that controls the randomized response probability of an attribution source whose source type is
"navigation".
Randomized event-source trigger rate is a double between 0 and 1
(both inclusive) that controls the randomized response probability of an attribution source whose source type is "event".
Max event-level reports per attribution destination is a positive integer that controls how many event-level reports can be in the event-level report cache per site in attribution destinations.
Max aggregatable reports per attribution destination is a positive integer that controls how many aggregatable reports can be in the aggregatable report cache per effective attribution destination.
Max attributions per navigation source is a positive integer that
controls how many times a single attribution source whose source type is "navigation" can create an event-level report.
Max attributions per event source is a positive integer that
controls how many times a single attribution source whose source type is "event" can create an event-level report.
Max destinations covered by unexpired sources is a positive integer that controls the maximum number of distinct sites across all attribution destinations for unexpired attribution sources with a given (source site, reporting endpoint).
Attribution rate-limit window is a positive length of time that controls the rate-limiting window for attribution.
Max source reporting endpoints per rate-limit window is a positive integer that controls the maximum number of distinct reporting endpoints for a (source site, attribution destination) that can create attribution sources per attribution rate-limit window.
Max attribution reporting endpoints per rate-limit window is a positive integer that controls the maximum number of distinct reporting endpoints for a (source site, attribution destination) that can create event-level reports per attribution rate-limit window.
Max attributions per rate-limit window is a positive integer that controls the maximum number of attributions for a (source site, attribution destination, reporting endpoint) per attribution rate-limit window.
Max source cache size is a positive integer that controls how many attribution sources can be in the attribution source cache.
Max event-level report cache size is a positive integer that controls how many event-level reports can be in the event-level report cache.
Max aggregatable report cache size is a positive integer that controls how many aggregatable reports can be in the aggregatable report cache.
Allowed aggregatable budget per source is a positive integer that controls the total required aggregatable budget of all aggregatable reports created for an attribution source.
Min aggregatable report delay is a non-negative length of time that controls the minimum delay to deliver an aggregatable report.
Randomized aggregatable report delay is a positive length of time that controls the random delay to deliver an aggregatable report.
8. General Algorithms
To check if an origin is suitable given an origin origin:
-
If origin is not a potentially trustworthy origin, return false.
-
If origin’s scheme is not "
http" or "https", return false. -
Return true.
8.1. Parsing filter data
To parse filter data given a value:
-
If value is not a map, return null.
-
If value’s size is greater than the user agent’s max entries per filter map, return null.
-
Let result be a new filter map.
-
For each filter → data of value:
-
If data is not a list, return null.
-
Let set be a new ordered set.
-
For each d of data:
-
If set’s size is greater than the user agent’s max values per filter entry, return null.
-
Set result[filter] to set.
-
-
Return result.
Determine whether to limit length or code point length for filter and d above.
8.2. Cookie-based debugging
To check if cookie-based debugging is allowed given a suitable origin reportingOrigin:
-
Return blocked.
Check for "ar_debug" cookie on reportingOrigin and return allowed if it exists, is Secure, is HttpOnly, and is SameSite=None.
8.3. Obtaining a randomized response
To obtain a randomized response given trueValue, a set possibleValues, and a double randomPickRate:
-
Assert: randomPickRate is between 0 and 1 (both inclusive).
-
Let r be a random double between 0 (inclusive) and 1 (exclusive) with uniform probability.
-
If r is less than randomPickRate, return a random item from possibleValues with uniform probability.
-
Otherwise, return trueValue.
8.4. Parsing aggregation key piece
To parse an aggregation key piece given a string input, perform the following steps. This algorithm will return either a non-negative 128-bit integer or an error.
-
If input’s code point length is not between 3 and 34 (both inclusive), return an error.
-
If the first character is not a U+0030 DIGIT ZERO (0), return an error.
-
If the second character is not a U+0058 LATIN CAPITAL LETTER X character (X) and not a U+0078 LATIN SMALL LETTER X character (x), return an error.
-
Let value be the code point substring from 2 to the end of input.
-
If the characters within value are not all ASCII hex digits, return an error.
-
Interpret value as a hexadecimal number and return as a non-negative 128-bit integer.
8.5. Can attribution rate-limit record be removed
Given an attribution rate-limit record record:
-
If record’s time is after the current time, return false.
-
If record’s scope is "
attribution", return true. -
If record’s expiry time is after the current time, return false.
-
Return true.
8.6. Obtaining and delivering an attribution debug report
To obtain and deliver a debug report given a list of attribution debug data data and a suitable origin reportingEndpoint:
-
Let debugReport be an attribution debug report with the items:
- data
-
data
- reporting endpoint
-
reportingEndpoint
-
Queue a task to attempt to deliver a verbose debug report with debugReport.
9. Source Algorithms
9.1. Obtaining an attribution source’s expiry time
An attribution source source’s expiry time is source’s source time + source’s expiry.
9.2. Obtaining an attribution source’s event report window time
An attribution source source’s event report window time is source’s source time + source’s event report window.
9.3. Obtaining an attribution source’s aggregatable report window time
An attribution source source’s aggregatable report window time is source’s source time + source’s aggregatable report window.
9.4. Obtaining an attribution source’s source site
An attribution source source’s source site is the result of obtaining a site from source’s source origin.
9.5. Parsing an attribution destination
To parse an attribution destination from a string str:
-
Let url be the result of running the URL parser on the value of the str.
-
If url is failure or null, return null.
-
Return the result of obtaining a site from url’s origin.
9.6. Parsing attribution destinations
To parse attribution destinations from a value val:
-
Let result be an ordered set.
-
If val is a string, append the result of parse an attribution destination to result, and return result.
-
If val is not a list, return null.
-
For each value of val
-
If value is not a string, return null.
-
Let destination be the result of parse an attribution destination with value.
-
If destination is null, return null.
-
append destination to result.
-
-
If result’s size is greater than 3, return null.
-
If result is empty, return null.
-
return result.
confirm that the maximum destinations size is workable.
9.7. Obtaining a randomized source response
To obtain a randomized source response given a positive integer triggerDataCardinality, a positive integer maxAttributionsPerSource, a positive integer numReportWindows, and a double randomPickRate:
-
For each integer triggerData between 0 (inclusive) and triggerDataCardinality (exclusive):
-
For each integer reportWindow between 0 (inclusive) and numReportWindows (exclusive):
-
Let state be a new trigger state with the items:
- trigger data
-
triggerData
- report window
-
reportWindow
-
Append state to possibleTriggerStates.
-
-
-
For each integer attributions between 0 (inclusive) and maxAttributionsPerSource (inclusive):
-
Append to possibleValues all distinct attributions-length combinations of possibleTriggerStates.
-
-
Return the result of obtaining a randomized response with null, possibleValues, and randomPickRate.
9.8. Obtaining an attribution source from an a element
To obtain an attribution source from an anchor given an a element anchor:
-
If anchor does not have an
attributionsrcattribute, return null. -
Return null.
Specify the steps for making attributionsrc request.
9.9. Obtaining an attribution source from window features
To obtain an attribution source from window features given an ordered map tokenizedFeatures:
-
If tokenizedFeatures["attributionsrc"] does not exist, return null.
-
Let decodedSrcBytes be the result of percent-decoding tokenizedFeatures["attributionsrc"].
-
Let decodedSrc be the UTF-8 decode without BOM of decodedSrcBytes.
-
Return null.
Check for transient activation. Issue: Specify the steps for making an attributionsrc request with decodedSrc.
9.10. Parsing source-registration JSON
To obtain a source expiry given a value:
-
If value is not a string, return null.
-
Let expirySeconds be the result of applying the rules for parsing integers to value.
-
If expirySeconds is an error, return null.
-
Let expiry be expirySeconds seconds.
-
If expiry is less than 1 day, set expiry to 1 day.
-
If expiry is greater than the user agent’s max source expiry, set expiry to that value.
-
Return expiry.
To parse aggregation keys given an ordered map map:
-
Let aggregationKeys be a new ordered map.
-
If map["
aggregation_keys"] does not exist, return aggregationKeys. -
Let values be map["
aggregation_keys"]. -
If values is not an ordered map, return null.
-
If values’s size is greater than the user agent’s max aggregation keys per attribution, return null.
-
For each key → value of values:
-
If value is not a string, return null.
-
Let keyPiece be the result of running parse an aggregation key piece with value.
-
If keyPiece is an error, return null.
-
Set aggregationKeys[key] to keyPiece.
-
-
Return aggregationKeys.
Determine whether to limit length or code point length for key above using max bytes per aggregation key identifier.
To parse source-registration JSON given a string json, a suitable origin sourceOrigin, a suitable origin reportingOrigin, and a source type sourceType:
-
Let value be the result of running parse a JSON string to an Infra value with json.
-
If value is not an ordered map, return null.
-
Let sourceEventId be 0.
-
If value["
source_event_id"] exists and is a string:-
Set sourceEventId to the result of applying the rules for parsing non-negative integers to value["
source_event_id"] modulo the user agent’s source event ID cardinality. -
If sourceEventId is an error, set sourceEventId to 0.
-
-
If value["
destination"] does not exist, return null. -
Let attributionDestinations be the result of running parse attribution destinations with value["
destination"]. -
If attributionDestinations is null, return null.
-
Let expiry be the result of running obtain a source expiry on value["
expiry"]. -
If expiry is null, set expiry to 30 days.
-
Let eventReportWindow be the result of running obtain a source expiry on value["
event_report_window"]. -
If eventReportWindow is null or greater than expiry, set eventReportWindow to expiry.
-
Let aggregatableReportWindow be the result of running obtain a source expiry on value["
aggregatable_report_window"]. -
If aggregatableReportWindow is null or greater than expiry, set aggregatableReportWindow to expiry.
-
Let priority be 0.
-
If value["
priority"] exists and is a string:-
Set priority to the result of applying the rules for parsing integers to value["
priority"]. -
If priority is an error, set priority to 0.
-
-
Let filterData be a new filter map.
-
If value["
filter_data"] exists:-
Set filterData to the result of running parse filter data with value["
filter_data"]. -
If filterData is null, return null.
-
If filterData["
source_type"] exists, return null.
-
-
Set filterData["
source_type"] to « sourceType ». -
Let debugKey be null.
-
If value["
debug_key"] exists and is a string:-
Set debugKey to the result of applying the rules for parsing non-negative integers to value["
debug_key"]. -
If debugKey is an error, set debugKey to null.
-
If the result of running check if cookie-based debugging is allowed with reportingOrigin is blocked, set debugKey to null.
-
-
Let aggregationKeys be the result of running parse aggregation keys with value.
-
If aggregationKeys is null, return null.
-
If aggregatableExpiry is null, set aggregatableExpiry to expiry.
-
Let triggerDataCardinality be the user agent’s navigation-source trigger data cardinality.
-
Let randomizedTriggerRate be the user agent’s randomized navigation-source trigger rate.
-
Let maxAttributionsPerSource be the user agent’s max attributions per navigation source.
-
If sourceType is "
event":-
Round expiry away from zero to the nearest day (86400 seconds).
-
Set triggerDataCardinality to the user agent’s event-source trigger data cardinality.
-
Set randomizedTriggerRate’s to the user agent’s randomized event-source trigger rate.
-
Set maxAttributionsPerSource to the user agent’s max attributions per event source.
-
-
Let numReportWindows be the result of running obtain the number of report windows with sourceType.
-
Let debugReportingEnabled be false.
-
If value["
debug_reporting"] exists and is a boolean, set debugReportingEnabled to value["debug_reporting"]. -
Let source be a new attribution source struct whose items are:
- source identifier
-
A new unique string
- source origin
-
sourceOrigin
- event ID
-
sourceEventId
- attribution destinations
-
attributionDestinations
- reporting endpoint
-
reportingOrigin
- expiry
-
expiry
- event report window
-
eventReportWindow
- aggregatable report window
-
aggregatableReportWindow
- priority
-
priority
- source time
-
The current time
- source type
-
sourceType
- randomized response
-
The result of obtaining a randomized source response with triggerDataCardinality, maxAttributionsPerSource, numReportWindows, and randomizedTriggerRate.
- randomized trigger rate
-
randomizedTriggerRate
- filter data
-
filterData
- debug key
-
debugKey
- aggregation keys
-
aggregationKeys
- aggregatable budget consumed
-
0
- debug reporting enabled
-
debugReportingEnabled
-
Return source.
Ensure that all sites in attributionDestinations have HTTP/HTTPS schemes.
9.11. Checking unexpired destination limit
To check if an attribution source exceeds the unexpired destination limit given an attribution source source, run the following steps:
-
Let unexpiredSources be all attribution rate-limit records record in the attribution rate-limit cache where all of the following are true:
-
record’s source site and source’s source site are equal
-
record’s reporting endpoint and source’s reporting endpoint are equal
-
record’s expiry time is greater than source’s source time
-
For each attribution rate-limit record unexpiredRecord of unexpiredSources:
-
append unexpiredRecord’s attribution destination to unexpiredDestinations.
-
-
Let newDestinations be the result of taking the union of unexpiredDestinations and source’s attribution destinations.
-
Return whether newDestinations’s size is greater than or equal to the user agent’s max destinations covered by unexpired sources.
9.12. Processing an attribution source
To obtain a fake report given an attribution source source and a trigger state triggerState:
-
Let fakeConfig be a new event-level trigger configuration with the items:
- trigger data
-
triggerState’s trigger data
- dedup key
-
null
- priority
-
0
- filters
-
«[ "
source_type" → « source’s source type » ]»
-
Let fakeTrigger be a new attribution trigger with the items:
- attribution destinations
-
source’s attribution destinations
- trigger time
-
source’s source time
- reporting endpoint
-
source’s reporting endpoint
- filters
-
«[]»
- debug key
-
null
- event-level trigger configurations
-
« fakeConfig »
- aggregatable trigger data
-
«»
- aggregatable values
-
«[]»
- aggregatable dedup key
-
null
- debug reporting enabled
-
false
-
Let fakeReport be the result of running obtain an event-level report with source, fakeTrigger, and fakeConfig.
-
Set fakeReport’s report time to the result of running obtain the report time at a window with source and triggerState’s report window.
-
Return fakeReport.
To check if debug reporting is allowed given a source debug data type dataType and a suitable origin reportingOrigin:
-
If dataType is:
- "
source-destination-limit" -
Return allowed.
- "
source-noised"- "
source-storage-limit"- "
source-unknown-error" - "
-
Return the result of running check if cookie-based debugging is allowed with reportingOrigin.
- "
To obtain and deliver a debug report on source registration given a source debug data type dataType and an attribution source source:
-
If source’s debug reporting enabled is false, return.
-
If the result of running check if debug reporting is allowed with dataType and source’s reporting endpoint is blocked, return.
-
Let body be a new map with the following key/value pairs:
- "
attribution_destination" -
source’s attribution destinations, serialized.
- "
source_event_id" -
source’s event ID, serialized.
- "
source_site" -
source’s source site, serialized.
- "
-
If source’s debug key is not null, set body["
source_debug_key"] to source’s debug key, serialized. -
If dataType is:
- "
source-destination-limit" -
Set body["
limit"] to the user agent’s max destinations covered by unexpired sources, serialized. - "
source-storage-limit" -
Set body["
limit"] to the user agent’s max pending sources per source origin, serialized.
- "
-
Let data be a new attribution debug data with the items:
-
Run obtain and deliver a debug report with « data » and source’s reporting endpoint.
To process an attribution source given an attribution source source:
-
Let cache be the user agent’s attribution source cache.
-
Remove all entries in cache where the entry’s expiry time is less than the current time.
-
If the size of cache is greater than or equal to the user agent’s max source cache size, return.
-
Let pendingSourcesForSourceOrigin be the set of all attribution sources pendingSource of cache where pendingSource’s source origin and source’s source origin are same origin.
-
If pendingSourcesForSourceOrigin’s size is greater than or equal to the user agent’s max pending sources per source origin:
-
Run obtain and deliver a debug report on source registration with "
source-storage-limit" and source. -
Return.
-
-
If the result of running check if an attribution source exceeds the unexpired destination limit with source is true:
-
Run obtain and deliver a debug report on source registration with "source-destination-limit" and source.
-
Return.
-
-
For each destination in source’s attribution destinations
-
Let rateLimitRecord be a new attribution rate-limit record with the items:
- scope
-
"
source" - source site
-
source’s source site
- attribution destination
-
destination
- reporting endpoint
-
source’s reporting endpoint
- time
-
source’s source time
- expiry time
-
source’s expiry time
-
If the result of running should processing be blocked by reporting-endpoint limit with rateLimitRecord is blocked, return.
-
Append rateLimitRecord to the attribution rate-limit cache.
-
-
Remove all entries from the attribution rate-limit cache if the result of running can attribution rate-limit record be removed with the entry is true.
-
If source’s randomized response is not null and is a set:
-
For each trigger state triggerState of source’s randomized response:
-
Let fakeReport be the result of running obtain a fake report with source and triggerState.
-
Append fakeReport to the event-level report cache.
-
-
If source’s randomized response is not empty, then set source’s event-level attributable value to false.
-
Run obtain and deliver a debug report on source registration with "
source-noised" and source.
-
-
Append source to cache.
Should fake reports respect the user agent’s max event-level reports per attribution destination?
10. Triggering Algorithms
10.1. Creating an attribution trigger
To parse event triggers given an ordered map map:
-
Let eventTriggers be a new set.
-
If map["
event_trigger_data"] does not exist, return eventTriggers. -
Let values be map["
event_trigger_data"]. -
If values is not a list, return null.
-
For each value of values:
-
If value is not an ordered map, return null.
-
Let triggerData be 0.
-
If value["
trigger_data"] exists and is a string:-
Set triggerData to the result of applying the rules for parsing non-negative integers to value["
trigger_data"]. -
If triggerData is an error, set triggerData to 0.
-
-
Let dedupKey be null.
-
If value["
deduplication_key"] exists and is a string:-
Set dedupKey to the result of applying the rules for parsing non-negative integers to value["
deduplication_key"]. -
If dedupKey is an error, set dedupKey to null.
-
-
Let priority be 0.
-
If value["
priority"] exists and is a string:-
Set priority to the result of applying the rules for parsing integers to value["
priority"]. -
If priority is an error, set priority to 0.
-
-
Let filters be a new filter map.
-
If value["
filters"] exists:-
Set filters to the result of running parse filter data with value["
filters"]. -
If filters is null, return null.
-
-
Let negatedFilters be a new filter map.
-
If value["
not_filters"] exists:-
Set negatedFilters to the result of running parse filter data with value["
not_filters"]. -
If negatedFilters is null, return null.
-
-
Let eventTrigger be a new event-level trigger configuration with the items:
- trigger data
-
triggerData
- dedup key
-
dedupKey
- priority
-
priority
- filters
-
filters
- negated filters
-
negatedFilters
-
Append eventTrigger to eventTriggers.
-
-
Return eventTriggers.
Allow the user agent to return null if values’s size is greater than some constant.
To parse aggregatable trigger data given an ordered map map:
-
Let aggregatableTriggerData be a new list.
-
If map["
aggregatable_trigger_data"] does not exist, return aggregatableTriggerData. -
Let values be map["
aggregatable_trigger_data"]. -
If values is not a list, return null.
-
If values’s size is greater than the user agent’s max aggregatable trigger data per trigger, return null.
-
For each value of values:
-
If value is not an ordered map, return null.
-
If value["
key_piece"] does not exist or is not a string, return null. -
Let keyPiece be the result of running parse an aggregation key piece with value["
key_piece"]. -
If keyPiece is an error, return null.
-
Let sourceKeys be a new ordered set.
-
If value["
source_keys"] exists: -
Let filters be a new filter map.
-
If value["
filters"] exists:-
Set filters to the result of running parse filter data with value["
filters"]. -
If filters is null, return null.
-
-
Let negatedFilters be a new filter map.
-
If value["
not_filters"] exists:-
Set negatedFilters to the result of running parse filter data with value["
not_filters"]. -
If negatedFilters is null, return null.
-
-
Let aggregatableTrigger be a new aggregatable trigger data with the items:
- key piece
-
keyPiece
- source keys
-
sourceKeys
- filters
-
filters
- negated filters
-
negatedFilters
-
Append aggregatableTrigger to aggregatableTriggerData.
-
-
Return aggregatableTriggerData.
Determine whether to limit length or code point length for sourceKey above using max bytes per aggregation key identifier.
To parse aggregatable values given an ordered map map:
-
If map["
aggregatable_values"] does not exist, return «[]». -
Let values be map["
aggregatable_values"]. -
If values is not an ordered map, return null.
-
If values’s size is great than the user agent’s max aggregation keys per attribution, return null.
-
For each key → value of values:
-
If value is not an integer, return null.
-
If value is less than or equal to 0, return null.
-
-
Return values.
Determine whether to limit length or code point length for key above using max bytes per aggregation key identifier.
To serialize a private state token given a string encodedBlindedPrivateStateToken:
-
If encodedBlindedPrivateStateToken is null, return null.
-
Let decoded be the result of forgiving-base64 decoding encodedBlindedPrivateStateToken.
-
If decoded is failure, return null.
-
Let tokens be the result of finishing issuance of decoded.
properly define the "finishing issuance" operation.
-
If tokens is null, or has size not equal to 1, return null.
-
Let token be tokens[0].
-
Let redeemedBytes be the result of "beginning redemption" with token, the empty byte sequence (data), and 0 (the null timestamp).
properly define "begin redemption" operation. Consider running the algorithm at report sending time.
-
Return the result of forgiving-base64 encoding redeemedBytes.
To create an attribution trigger given a string json, a site destination, a suitable origin reportingOrigin, and a string privateStateToken:
-
Let value be the result of running parse a JSON string to an Infra value with json.
-
If value is not an ordered map, return null.
-
Let eventTriggers be the result of running parse event triggers with value.
-
If eventTriggers is null, return null.
-
Let aggregatableTriggerData be the result of running parse aggregatable trigger data with value.
-
If aggregatableTriggerData is null, return null.
-
Let aggregatableValues be the result of running parse aggregatable values with value.
-
If aggregatableValues is null, return null.
-
Let aggregatableDedupKey be null.
-
If value["
aggregatable_deduplication_key"] exists and is a string:-
Set aggregatableDedupKey to the result of applying the rules for parsing non-negative integers to value["
aggregatable_deduplication_key"]. -
If aggregatableDedupKey is an error, set aggregatableDedupKey to null.
-
-
Let debugKey be null.
-
If value["
debug_key"] exists and is a string:-
Set debugKey to the result of applying the rules for parsing non-negative integers to value["
debug_key"]. -
If debugKey is an error, set debugKey to null.
-
If the result of running check if cookie-based debugging is allowed with reportingOrigin is blocked, set debugKey to null.
-
-
Let filters be a new filter map.
-
If value["
filters"] exists:-
Set filters to the result of running parse filter data with value["
filters"]. -
If filters is null, return null.
-
-
Let negatedFilters be a new filter map.
-
If value["
not_filters"] exists:-
Set negatedFilters to the result of running parse filter data with value["
not_filters"]. -
If negatedFilters is null, return null.
-
-
Let debugReportingEnabled be false.
-
If value["
debug_reporting"] exists and is a boolean, set debugReportingEnabled to value["debug_reporting"]. -
Let trigger be a new attribution trigger with the items:
- attribution destination
-
destination
- trigger time
-
The current time.
- reporting endpoint
-
reportingOrigin
- filters
-
filters
- negated filters
-
negatedFilters
- debug key
-
debugKey
- event-level trigger configurations
-
eventTriggers
- aggregatable trigger data
-
aggregatableTriggerData
- aggregatable values
-
aggregatableValues
- aggregatable dedup key
-
aggregatableDedupKey
- serialized private state token
-
The result of serializing a private state token with privateStateToken
- debug reporting enabled
-
debugReportingEnabled
-
Return trigger.
10.2. Does filter data match
To match filter values given a filter value a and a filter value b:
-
If b is empty, then:
-
If a is empty, then return true.
-
Otherwise, return false.
-
-
Let i be the intersection of a and b.
-
If i is empty, then return false.
-
Return true.
To match filter values with negation given a filter value a and a filter value b:
-
If b is empty, then:
-
If a is not empty, then return true.
-
Otherwise, return false.
-
-
Let i be the intersection of a and b.
-
If i is not empty, then return false.
-
Return true.
To match an attribution source’s filter data against filters given an attribution source source, a filter map filters, and a boolean isNegated:
-
Let sourceData be source’s filter data.
-
For each key → filterValues of filters:
-
Let sourceValues be sourceData[key].
-
If isNegated is:
- false
- If the result of running match filter values with sourceValues and filterValues is false, return false.
- true
- If the result of running match filter values with negation with sourceValues and filterValues is false, return false.
-
Return true.
10.3. Should attribution be blocked by rate limit
Given an attribution trigger trigger and attribution source sourceToAttribute:
-
Let matchingRateLimitRecords be all attribution rate-limit records record of attribution rate-limit cache where all of the following are true:
-
record’s scope is "
attribution" -
record’s source site and sourceToAttribute’s source site are equal
-
record’s attribution destination and trigger’s attribution destination are equal
-
record’s reporting endpoint and trigger’s reporting endpoint are same origin
-
record’s time is at least attribution rate-limit window before trigger’s trigger time
-
-
If matchingRateLimitRecords’s size is greater than or equal to max attributions per rate-limit window, return blocked.
-
Return allowed.
10.4. Should processing be blocked by reporting-endpoint limit
Given an attribution rate-limit record newRecord:
-
Let max be max source reporting endpoints per rate-limit window.
-
If newRecord’s scope is "
attribution", set max to max attribution reporting endpoints per rate-limit window. -
Let matchingRateLimitRecords be all attribution rate-limit records record in the attribution rate-limit cache where all of the following are true:
-
record’s source site and newRecord’s source site are equal
-
record’s attribution destination and newRecord’s attribution destination are equal
-
record’s time is at least attribution rate-limit window before newRecord’s time
-
Let distinctReportingEndpoints be a new empty ordered set.
-
For each record of matchingRateLimitRecords, append record’s reporting endpoint to distinctReportingEndpoints.
-
If distinctReportingEndpoints contains newRecord’s reporting endpoint, return allowed.
-
If distinctReportingEndpoints’s size is greater than or equal to max, return blocked.
-
Return allowed.
10.5. Creating aggregatable contributions
To create aggregatable contributions given an attribution source source and an attribution trigger trigger, run the following steps:
-
Let aggregationKeys be the result of cloning source’s aggregation keys.
-
For each triggerData of trigger’s aggregatable trigger data:
-
If the result of running match an attribution source’s filter data against filters with source, triggerData’s filters, and isNegated set to false is false, continue.
-
If the result of running match an attribution source’s filter data against filters with source, triggerData’s negated filters, and isNegated set to true is false, continue.
-
For each sourceKey of triggerData’s source keys:
-
-
Let aggregatableValues be trigger’s aggregatable values.
-
Let contributions be a new empty list.
-
For each id → key of aggregationKeys:
-
Return contributions.
10.6. Can source create aggregatable contributions
To check if an attribution source can create aggregatable contributions given an aggregatable report report and an attribution source sourceToAttribute, run the following steps:
-
Let remainingAggregatableBudget be allowed aggregatable budget per source minus sourceToAttribute’s aggregatable budget consumed.
-
Assert: remainingAggregatableBudget is greater than or equal to 0.
-
If report’s required aggregatable budget is greater than remainingAggregatableBudget, return false.
-
Return true.
10.7. Obtaining debug data on trigger registration
To obtain debug data body on trigger registration given a trigger debug data type dataType, an attribution trigger trigger, an optional attribution source sourceToAttribute, and an optional attribution report report:
-
If dataType is:
- "
trigger-attributions-per-source-destination-limit" -
Set body["
limit"] to the user agent’s max attributions per rate-limit window, serialized. - "
trigger-reporting-origin-limit" -
Set body["
limit"] to the user agent’s max attribution reporting endpoints per rate-limit window, serialized. - "
trigger-event-storage-limit" -
Set body["
limit"] to max event-level reports per attribution destination, serialized. - "
trigger-aggregate-storage-limit" -
Set body["
limit"] to max aggregatable reports per attribution destination, serialized. - "
trigger-aggregate-insufficient-budget" -
Set body["
limit"] to allowed aggregatable budget per source, serialized. - "
trigger-event-low-priority"- "
trigger-event-excessive-reports" - "
-
-
Assert: report is not null and is an event-level report.
-
Return the result of running obtain an event-level report body with report.
-
- "
-
Set body["
attribution_destination"] to trigger’s attribution destination, serialized. -
If trigger’s debug key is not null, set body["
trigger_debug_key"] to trigger’s debug key, serialized. -
If sourceToAttribute is not null:
-
Set body["
source_event_id"] to source’s event ID, serialized. -
Set body["
source_site"] to source’s source site, serialized. -
If sourceToAttribute’s debug key is not null, set body["
source_debug_key"] to sourceToAttribute’s debug key, serialized.
-
-
Return body.
To obtain debug data on trigger registration given a trigger debug data type dataType, an attribution trigger trigger, an optional attribution source sourceToAttribute, and an optional attribution report report:
-
If trigger’s debug reporting enabled is false, return null.
-
If the result of running check if cookie-based debugging is allowed with trigger’s reporting endpoint is blocked, return null.
-
Let data be a new attribution debug data with the items:
- data type
-
dataType.
- body
-
The result of running obtain debug data body on trigger registration with dataType, trigger, sourceToAttribute and report.
-
Return data.
10.8. Triggering event-level attribution
To trigger event-level attribution given an attribution trigger trigger, an attribution source sourceToAttribute, an attribution rate-limit record rateLimitRecord and a boolean topLevelFiltersMatch, run the following steps:
-
If sourceToAttribute’s randomized response is not null and is not empty:
-
Assert: sourceToAttribute’s event-level attributable is false.
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-noise", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If topLevelFiltersMatch is false:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-no-matching-filter-data", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If sourceToAttribute’s event report window time is less than the current time:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-report-window-passed", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
Let matchedConfig be null.
-
For each event-level trigger configuration config of trigger’s event-level trigger configurations:
-
If the result of running match an attribution source’s filter data against filters with sourceToAttribute, config’s filters, and isNegated set to false is false, continue.
-
If the result of running match an attribution source’s filter data against filters with sourceToAttribute, config’s negated filters, and isNegated set to true is false, continue.
-
Set matchedConfig to config.
-
-
If matchedConfig is null:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-no-matching-configurations", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If matchedConfig’s dedup key is not null and sourceToAttribute’s dedup keys contains it:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-deduplicated", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
Let numMatchingReports be the number of entries in the event-level report cache whose attribution destinations contains trigger’s attribution destination.
-
If numMatchingReports is greater than or equal to the user agent’s max event-level reports per attribution destination:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-storage-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the result of running should attribution be blocked by rate limit with trigger and sourceToAttribute is blocked:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-attributions-per-source-destination-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the result of running should processing be blocked by reporting-endpoint limit with rateLimitRecord is blocked:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-reporting-origin-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
Let report be the result of running obtain an event-level report with sourceToAttribute, trigger, and matchedConfig.
-
If sourceToAttribute’s event-level attributable value is false:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-excessive-reports", trigger, sourceToAttribute and report. -
Return the triggering result ("
dropped", debugData).
-
-
Let maxAttributionsPerSource be the user agent’s max attributions per navigation source.
-
If sourceToAttribute’s source type is "
event", set maxAttributionsPerSource to the user agent’s max attributions per event source. -
If sourceToAttribute’s number of event-level reports value is equal to maxAttributionsPerSource, then:
-
Let matchingReports be all entries in the event-level report cache where all of the following are true:
-
entry’s report time and report’s report time are equal.
-
entry’s source identifier is report’s source identifier
-
-
If matchingReports is empty:
-
Set sourceToAttribute’s event-level attributable value to false.
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-excessive-reports", trigger, sourceToAttribute and report. -
Return the triggering result ("
dropped", debugData).
-
-
Set matchingReports to the result of sorting matchingReports in ascending order, with a being less than b if any of the following are true:
-
a’s trigger priority is less than b’s trigger priority.
-
a’s trigger priority is equal to b’s trigger priority and a’s trigger time is greater than b’s trigger time.
-
-
Let lowestPriorityReport be the first item in matchingReports.
-
If report’s trigger priority is less than or equal to lowestPriorityReport’s trigger priority:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-event-low-priority", trigger, sourceToAttribute and report. -
Return the triggering result ("
dropped", debugData).
-
-
Remove lowestPriorityReport from the event-level report cache.
-
Decrement sourceToAttribute’s number of event-level reports value by 1.
-
-
If the size of the event-level report cache is greater than or equal to the user agent’s max event-level report cache size, return the triggering result ("
cache full", null). -
Let debugData be null.
-
If sourceToAttribute’s randomized response is:
- null
-
Append report to the event-level report cache.
- not null
-
Set debugData to the result of running obtain debug data on trigger registration with "
trigger-event-noise", trigger, sourceToAttribute and report set to null.
-
Increment sourceToAttribute’s number of event-level reports value by 1.
-
If matchedConfig’s dedup key is not null, append it to sourceToAttribute’s dedup keys.
-
If report’s source debug key is not null and report’s trigger debug key is not null, queue a task to attempt to deliver a debug report with report.
-
Return the triggering result ("
attributed", debugData).
10.9. Triggering aggregatable attribution
To trigger aggregatable attribution given an attribution trigger trigger, an attribution source sourceToAttribute, an attribution rate-limit record rateLimitRecord and a boolean topLevelFiltersMatch, run the following steps:
-
If sourceToAttribute’s aggregation keys is empty, return the triggering result ("
dropped", null). -
If trigger’s aggregatable trigger data is empty and trigger’s aggregatable values is empty, return the triggering result ("
dropped", null). -
If topLevelFiltersMatch is false:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-no-matching-filter-data", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If sourceToAttribute’s aggregatable report window time is less than the current time:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-aggregate-report-window-passed", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
Let report be the result of running obtain an aggregatable report with sourceToAttribute and trigger.
-
If report’s contributions is empty:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-aggregate-no-contributions", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If trigger’s aggregatable dedup key is not null and sourceToAttribute’s aggregatable dedup keys contains it:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-aggregate-deduplicated", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
Let numMatchingReports be the number of entries in the aggregatable report cache whose effective attribution destination equals trigger’s attribution destination.
-
If numMatchingReports is greater than or equal to the user agent’s max aggregatable reports per attribution destination:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-aggregate-storage-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the result of running should attribution be blocked by rate limit with trigger and sourceToAttribute is blocked:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-attributions-per-source-destination-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the result of running should processing be blocked by reporting-endpoint limit with rateLimitRecord is blocked:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-reporting-origin-limit", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the result of running check if an attribution source can create aggregatable contributions with report and sourceToAttribute is false:
-
Let debugData be the result of running obtain debug data on trigger registration with "
trigger-aggregate-insufficient-budget", trigger, sourceToAttribute and report set to null. -
Return the triggering result ("
dropped", debugData).
-
-
If the size of the aggregatable report cache is greater than or equal to the user agent’s max aggregatable report cache size, return the triggering result ("
cache full", null). -
Add report to the aggregatable report cache.
-
Increment sourceToAttribute’s aggregatable budget consumed value by report’s required aggregatable budget.
-
If trigger’s aggregatable dedup key is not null, append it to sourceToAttribute’s aggregatable dedup keys.
-
If report’s source debug key is not null and report’s trigger debug key is not null, queue a task to attempt to deliver a debug report with report.
-
Return the triggering result ("
attributed", null).
10.10. Triggering attribution
To obtain and deliver a debug report on trigger registration given a trigger debug data type dataType, an attribution trigger trigger and an optional attribution source sourceToAttribute:
-
Let debugData be the result of running obtain debug data on trigger registration with dataType, trigger, sourceToAttribute and report set to null.
-
If debugData is null, return.
-
Run obtain and deliver a debug report with « debugData » and trigger’s reporting endpoint.
To trigger attribution given an attribution trigger trigger, run the following steps:
-
Let attributionDestination be trigger’s attribution destination.
-
Let matchingSources be all entries in the attribution source cache where all of the following are true:
-
entry’s attribution destinations contains attributionDestination.
-
entry’s reporting endpoint and trigger’s reporting endpoint are same origin.
-
entry’s expiry time is greater than the current time.
-
-
If matchingSources is empty:
-
Run obtain and deliver a debug report on trigger registration with "
trigger-no-matching-source", trigger and sourceToAttribute set to null. -
Return.
-
-
Set matchingSources to the result of sorting matchingSources in descending order, with a being less than b if any of the following are true:
-
a’s priority is equal to b’s priority and a’s source time is less than b’s source time.
-
Let sourceToAttribute be the first item in matchingSources.
-
Let topLevelFiltersMatch be the result of running match an attribution source’s filter data against filters with sourceToAttribute, trigger’s filters, and isNegated set to false.
-
If topLevelFiltersMatch is true, set topLevelFiltersMatch to the result of running match an attribution source’s filter data against filters with sourceToAttribute, trigger’s negated filters, and isNegated set to true.
-
Let rateLimitRecord be a new attribution rate-limit record with the items:
- scope
- source site
-
sourceToAttribute’s source site
- attribution destination
-
attributionDestination
- reporting endpoint
-
sourceToAttribute’s reporting endpoint
- time
-
trigger’s trigger time
- expiry time
-
null
-
Let eventLevelResult be the result of running trigger event-level attribution with trigger, sourceToAttribute, rateLimitRecord and topLevelFiltersMatch.
-
Let aggregatableResult be the result of running trigger aggregatable attribution with trigger, sourceToAttribute, rateLimitRecord and topLevelFiltersMatch.
-
Let eventLevelDebugData be eventLevelResult’s debug data.
-
Let aggregatableDebugData be aggregatableResult’s debug data.
-
If eventLevelDebugData is not null, then append eventLevelDebugData to debugDataList.
-
If aggregatableDebugData is not null:
-
If debugDataList is not empty, then run obtain and deliver a debug report with debugDataList and trigger’s reporting endpoint.
-
If both eventLevelResult’s status and aggregatableResult’s status are "
dropped", return. -
Remove sourceToAttribute from matchingSources.
-
For each item of matchingSources:
-
Remove item from the attribution source cache.
-
-
If neither eventLevelResult’s status nor aggregatableResult’s status is "
attributed", return. -
Append rateLimitRecord to the attribution rate-limit cache.
-
Remove all entries from the attribution rate-limit cache if the result of running can attribution rate-limit record be removed with the entry is true.
10.11. Establishing report delivery time
To obtain early deadlines given a source type sourceType:
-
If sourceType is "
event", return «». -
Return « 2 days, 7 days ».
To obtain the number of report windows given a source type sourceType:
-
Let earlyDeadlines be the result of running obtain early deadlines with sourceType.
-
Return the size of earlyDeadlines + 1.
To obtain a report time from deadline given a time sourceTime and a length of time deadline:
-
Return sourceTime + deadline + 1 hour.
To obtain the report time at a window given an attribution source source and a non-negative integer window:
-
Let earlyDeadlines be the result of running obtain early deadlines with source’s source type.
-
Let deadline be source’s event report window.
-
If earlyDeadlines[window] exists, set deadline to it.
-
Return the result of running obtain a report time from deadline with source’s source time and deadline.
To obtain an event-level report delivery time given an attribution source source and a time triggerTime:
-
Let deadlineToUse be source’s event report window.
-
Let earlyDeadlines be the result of running obtain early deadlines with source’s source type.
-
For each earlyDeadline of earlyDeadlines:
-
Let time be source’s source time + earlyDeadline.
-
If time is less than triggerTime, continue.
-
If earlyDeadline is greater than or equal to deadlineToUse, continue.
-
Set deadlineToUse to earlyDeadline.
-
-
Return the result of running obtain a report time from deadline with source’s source time and deadlineToUse.
To obtain an aggregatable report delivery time given a point in time triggerTime, perform the following steps. They return a point in time.
-
Let r be a random double between 0 (inclusive) and 1 (exclusive) with uniform probability.
-
Return triggerTime + min aggregatable report delay + r * randomized aggregatable report delay.
10.12. Obtaining an event-level report
To obtain an event-level report given an attribution source source, an attribution trigger trigger, and an event-level trigger configuration config:
-
Let triggerDataCardinality be the user agent’s navigation-source trigger data cardinality.
-
If source’s source type is "
event", set triggerDataCardinality to the user agent’s event-source trigger data cardinality. -
Let report be a new event-level report struct whose items are:
- event ID
-
source’s event ID.
- trigger data
-
The remainder when dividing config’s trigger data by triggerDataCardinality.
- randomized trigger rate
-
source’s randomized trigger rate.
- reporting endpoint
-
source’s reporting endpoint.
- attribution destinations
-
source’s attribution destinations.
- reporting time
-
The result of running obtain an event-level report delivery time with source and trigger’s trigger time.
- trigger priority
-
config’s priority.
- trigger time
-
trigger’s trigger time.
- source identifier
-
source’s source identifier.
- report id
-
The result of generating a random UUID.
- source debug key
-
source’s debug key.
- trigger debug key
-
trigger’s debug key.
-
Return report.
10.13. Obtaining an aggregatable report’s required budget
An aggregatable report report’s required aggregatable budget is the total value of report’s contributions.
10.14. Obtaining an aggregatable report
To obtain an aggregatable report given an attribution source source and an attribution trigger trigger:
-
Let reportTime be the result of running obtain an aggregatable report delivery time with trigger’s trigger time.
-
Let report be a new aggregatable report struct whose items are:
- reporting endpoint
-
source’s reporting endpoint.
- effective attribution destination
-
trigger’s attribution destination.
- source time
-
source’s source time.
- original report time
-
reportTime.
- report time
-
reportTime.
- report id
-
The result of generating a random UUID.
- source debug key
-
source’s debug key.
- trigger debug key
-
trigger’s debug key.
- contributions
-
The result of running create aggregatable contributions with source and trigger.
- serialized private state token
-
trigger’s serialized private state token
-
Return report.
11. Report delivery
The user agent MUST periodically iterate over its event-level report cache and aggregatable report cache and run queue a report for delivery on each item.
To queue a report for delivery given an attribution report report, run the following steps in parallel:
-
If report’s delivered value is true, return.
-
Set report’s delivered value to true.
-
If report’s report time is less than the current time, add an implementation-defined random amount to report time.
Note: On startup, it is possible the user agent will need to send many reports whose report times passed while the browser was closed. Adding random delay prevents temporal joining of reports from different source origins.
-
Wait until report’s report time is the current time.
-
Optionally, wait a further implementation-defined length of time.
Note: This is intended to allow user agents to optimize device resource usage.
-
Run attempt to deliver a report with report.
11.1. Serialize an integer
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
11.2. Serialize attribution destinations
To serialize attribution destinations destinations, run the following steps:
-
Let destinationStrings be a list
-
For each destination in destinations:
-
Assert: destination is not the opaque origin.
-
append destination serialized to destinationStrings
-
-
If destinationStrings’s size is equal to 1, return destinationStrings[0].
-
Return destinationStrings.
11.3. Encode an unsigned k-bit integer
To encode an unsigned k-bit integer, represent it as a big-endian byte sequence of length k / 8, left padding with zero as necessary.
11.4. Obtaining an aggregatable report’s debug mode
An aggregatable report report’s debug mode is the result of running the following steps:
-
If report’s source debug key is null, return disabled.
-
If report’s trigger debug key is null, return disabled.
-
Return enabled.
11.5. Obtaining an aggregatable report’s shared info
An aggregatable report report’s shared info is the result of running the following steps:
-
Let reportingOrigin be report’s reporting endpoint.
-
Let sharedInfo be an ordered map of the following key/value pairs:
- "
api" -
"
attribution-reporting" - "
attribution destination" -
report’s effective attribution destination, serialized
- "
report_id" -
report’s report ID
- "
reporting_origin" -
reportingOrigin, serialized
- "
scheduled_report_time" -
report’s original report time in seconds since the UNIX epoch, serialized
- "
source_registration_time" -
report’s source time in seconds since the UNIX epoch, rounded down to a multiple of a whole day (86400 seconds), serialized
- "
version" -
A string, API version.
- "
-
If report’s debug mode is enabled, set sharedInfo["
debug_mode"] to "enabled". -
Return the string resulting from executing serialize an infra value to a json string on sharedInfo.
11.6. Obtaining an aggregatable report’s aggregation service payloads
To obtain the public key for encryption, asynchronously return a user-agent-determined public key or an error in the event that the user agent failed to obtain the public key.
Note: The user agent might enforce weekly key rotation. If there are multiple keys, the user agent might independently pick a key uniformly at random for every encryption operation. The key should be uniquely identifiable.
An aggregatable report report’s plaintext payload is the result of running the following steps:
-
For each contribution of report’s contributions:
-
Let payload be a map of the following key/value pairs:
- "
data" -
payloadData
- "
operation" -
"
histogram"
- "
-
Return the byte sequence resulting from CBOR encoding payload.
To obtain the encrypted payload given an aggregatable report report and a public key pkR, run the following steps:
-
Let plaintext be report’s plaintext payload.
-
Let encodedSharedInfo be report’s shared info, encoded.
-
Let info be the concatenation of «"
aggregation_service", encodedSharedInfo». -
Set up HPKE sender’s context with pkR and info.
-
Return the byte sequence or an error resulting from encrypting plaintext with the sender’s context.
To obtain the aggregation service payloads given an aggregatable report report, run the following steps:
-
Let pkR be the result of running obtain the public key for encryption.
-
If pkR is an error, return pkR.
-
Let encryptedPayload be the result of running obtain the encrypted payload with report and pkR.
-
If encryptedPayload is an error, return encryptedPayload.
-
Let aggregationServicePayload be a map of the following key/value pairs:
- "
payload" -
encryptedPayload, base64 encoded
- "
key_id" -
A string identifying pkR
- "
-
If report’s debug mode is enabled, set aggregationServicePayload["
debug_cleartext_payload"] to report’s plaintext payload, base64 encoded. -
Append aggregationServicePayload to aggregationServicePayloads.
-
Return aggregationServicePayloads.
11.7. Serialize attribution report body
To obtain an event-level report body given an attribution report report, run the following steps:
-
Let data be a map of the following key/value pairs:
- "
attribution_destination" -
report’s attribution destinations, serialized.
- "
randomized_trigger_rate" -
report’s randomized trigger rate
- "
source_type" -
report’s source type
- "
source_event_id" -
report’s event ID, serialized
- "
trigger_data" -
report’s trigger data, serialized
- "
report_id" -
report’s report ID
- "
-
If report’s source debug key is not null, set data["
source_debug_key"] to report’s source debug key, serialized. -
If report’s trigger debug key is not null, set data["
trigger_debug_key"] to report’s trigger debug key, serialized. -
Return data.
To serialize an event-level report report, run the following steps:
-
Let data be the result of running obtain an event-level report body with report.
-
Return the byte sequence resulting from executing serialize an infra value to JSON bytes on data.
To serialize an aggregatable report report, run the following steps:
-
Assert: report’s effective attribution destination is not the opaque origin.
-
Let aggregationServicePayloads be the result of running obtain the aggregation service payloads.
-
If aggregationServicePayloads is an error, return aggregationServicePayloads.
-
Let data be a map of the following key/value pairs:
- "
shared_info" -
report’s shared info.
- "
aggregation_service_payloads" -
aggregationServicePayloads
- "
-
If report’s source debug key is not null, set data["
source_debug_key"] to report’s source debug key, serialized. -
If report’s trigger debug key is not null, set data["
trigger_debug_key"] to report’s trigger debug key, serialized. -
Return the byte sequence resulting from executing serialize an infra value to JSON bytes on data.
To serialize an attribution report report, run the following steps:
-
If report is an:
- event-level report
- Return the result of running serialize an event-level report with report.
- aggregatable report
- Return the result of running serialize an aggregatable report with report.
Note: The inclusion of "report_id" in the report body is intended to allow the report recipient
to perform deduplication and prevent double counting, in the event that the user agent retries
reports on failure. To prevent the report recipient from learning additional information about
whether a user is online, retries might be limited in number and subject to random delays.
11.8. Serialize attribution debug report body
To serialize an attribution debug report report, run the following steps:
-
Return the byte sequence resulting from executing serialize an Infra value to JSON bytes on collection.
11.9. Get report request URL
To generate a report URL given a suitable origin reportingOrigin and a list of strings path:
-
Let reportUrl be a new URL record.
-
Let fullPath be «"
.well-known", "attribution-reporting"». -
Append path to fullPath.
-
Set reportUrl’s path to path.
-
Return reportUrl.
To generate an attribution report URL given an attribution report report and an optional boolean isDebugReport (default false):
-
If isDebugReport is true, append "
debug" to path. -
If report is an:
- event-level report
- Append "
report-event-attribution" to path. - aggregatable report
- Append "
report-aggregate-attribution" to path.
-
Return the result of running generate a report URL with report’s reporting endpoint and path.
To generate an attribution debug report URL given an attribution debug report report:
-
Let path be «"
debug", "verbose"». -
Return the result of running generate a report URL with report’s reporting endpoint and path.
11.10. Creating a report request
To create a report request given a URL url, a byte sequence body, and a header list newHeaders (defaults to an empty list):
-
Let headers be a new header list containing a header named "
Content-Type" whose value is "application/json". -
For each header in newHeaders:
-
append header to headers.
-
-
Let request be a new request with the following properties:
- method
-
"
POST" - URL
-
url
- header list
-
headers
- body
- referrer
-
"
no-referrer" - client
-
null - window
-
"
no-window" - service-workers mode
-
"
none" - initiator
-
""
- mode
-
"
cors" - unsafe-request flag
-
set
- credentials mode
-
"
omit" - cache mode
-
"
no-store"
-
Return request.
11.11. Issuing a report request
This algorithm constructs a request and attempts to deliver it to a suitable origin.
To remove a report from the cache given an attribution report report:
-
If report is an:
- event-level report
- Queue a task to remove report from the event-level report cache.
- aggregatable report
- Queue a task to remove report from the aggregatable report cache.
To attempt to deliver a report given an attribution report report, run the following steps:
-
Let url be the result of executing generate an attribution report URL on report.
-
Let data be the result of executing serialize an attribution report on report.
-
If data is an error, run remove a report from the cache with report and return.
-
Let newHeaders be a new header list.
-
If report is an aggregatable report
-
If report’s serialized private state token is not null, append a new header named "
Sec-Attribution-Reporting-Private-State-Token" to newHeaders whose value is report’s serialized private state token.
-
-
Let request be the result of executing create a report request on url, data, and newHeaders.
-
Queue a task to fetch request with processResponse being remove a report from the cache with report.
This fetch should use a network partition key for an opaque origin. [Issue #220]
A user agent MAY retry this algorithm in the event that there was an error.
11.12. Issuing a debug report request
To attempt to deliver a debug report given an attribution report report:
-
Let url be the result of executing generate an attribution report URL on report with isDebugReport set to true.
-
Let data be the result of executing serialize an attribution report on report.
-
If data is an error, return.
-
Let request be the result of executing create a report request on url and data.
-
Fetch request.
11.13. Issuing a verbose debug request
To attempt to deliver a verbose debug report given an attribution debug report report:
-
Let url be the result of executing generate an attribution debug report URL on report.
-
Let data be the result of executing serialize an attribution debug report on report.
-
Let request be the result of executing create a report request on url and data.
-
Fetch request.
This fetch should use a network partition key for an opaque origin. [Issue #220]
A user agent MAY retry this algorithm in the event that there was an error.
12. Security considerations
TODO13. Privacy consideration
TODO13.1. Clearing attribution storage
A user agent’s attribution caches contain data about a user’s web activity. When a user agent clears an origin’s storage, it MUST also remove entries in the attribution caches whose source origin, attribution destinations, reporting endpoint, attribution destinations, or reporting endpoint is the same as the cleared origin.
A user agent MAY clear attribution cache entries at other times. For example, when a user agent clears an origin from a user’s browsing history.