Attribution Reporting

Draft Community Group Report , 6

This version:
https://wicg.github.io/attribution-reporting-api
Issue Tracking:
GitHub
Inline In Spec
Editors:
( Google Inc. )
( Google Inc. )
( Google Inc. )
Not Ready For Implementation

This spec is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement this spec, please contact the editors.


Abstract

An API to report that an event may have been caused by another cross-site event. These reports are designed to transfer little enough data between sites that the sites can’t use them to track individual users.

Status of this document

This specification was published by the Web Platform Incubator Community Group . It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups .

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 event-level 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 an attribution destination 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 event-level 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 attributionsrc attribute is a string representing the URL of the resource that will register an attribution source when the a is navigated.

img

The attributionsrc attribute is a string representing the URL of the resource that will register an attribution source or attribution trigger when set.

script

The attributionsrc attribute 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. Navigation

This section ensures that an attribution source associated with a navigation results in a top-level navigation whose final URL is same site with the attribution destination .

2.2.1. Navigation Params

A navigation params struct has an item:

attribution source

null or an attribution source declared when initiating a navigation

2.2.2. Navigate algorithm

Modify the navigate algorithm to accept a new optional parameter attributionSource of type attribution source defaulting to null.

In navigate , within step

  1. This is the step that attempts to obtain resource, if necessary. Jump to the first appropriate substep: ...

in the case where

If resource is a response

modify the substep

  1. Let navigationParams be a new navigation params whose request is null, response is resource ...

to set the attribution source of navigationParams to attributionSource .

In the case where

If resource is a request whose URL’s scheme is "javascript"

modify the substep

  1. Let navigationParams be a new navigation params whose request is resource, ...

to set the attribution source of navigationParams to attributionSource .

In the case where

If resource is a request whose URL’s scheme is a fetch scheme

modify the substep to pass attributionSource to the process a navigate fetch algorithm.

Note: The final case, where the request is not a javascript or fetch scheme, does not need to be handled as it will not result in the navigation of a top-level browsing context.

2.2.3. Process a navigate fetch

Modify the process a navigate fetch algorithm to accept a new optional parameter attributionSource of type attribution source defaulting to null.

In process a navigate fetch , modify the step

  1. Otherwise, if locationURL is a URL whose scheme is a fetch scheme, then run process a navigate fetch with a new request ...

to also pass attributionSource into the process a navigate fetch algorithm.

Modify the step

  1. Let navigationParams be a new navigation params whose request is request, response is response, ...

to set the attribution source of navigationParams to attributionSource .

2.2.4. Document creation

At the time create and initialize a Document object is invoked, the user agent knows the final URL used for the navigation and can validate the attribution destination .

In create and initialize a Document object , before

  1. Let permissionsPolicy be the result of creating a permissions policy from a response given browsingContext ...

add the following step:

  1. Execute maybe process a navigation attribution source with navigationParams and browsingContext .

Attribution source information declared on the a element needs to be passed to the navigate algorithm.

In follow the hyperlink after

  1. Let historyHandling be "replace" if windowType is not "existing or none"; otherwise, "default".

add the following steps:

  1. Let attributionSource be null.

  2. If subject is an a element, set attributionSource to the result of running obtain an attribution source from an anchor with subject .

Modify the step:

  1. Queue an element task on the DOM manipulation task source given subject to navigate target to request ...

to call navigate with attributionSource set to attributionSource .

2.4. Window open steps

Attribution source information declared via window.open() needs to be passed to the navigate algorithm.

In window open steps after

  1. If target browsing context is null, then return null.

add the following steps:

  1. Let attributionSource be the result of running obtain an attribution source from window features with tokenizedFeatures and source browsing context .

Modify the step:

  1. Navigate target browsing context to request , with exceptionsEnabled set to true and the source browsing context set to source browsing context .

to also pass attributionSource into the navigate algorithm.

Modify the step:

  1. Navigate target browsing context to request , with exceptionsEnabled set to true and the source browsing context set to source browsing context .

to also pass attributionSource into the navigate algorithm.

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. Source type

A source type is either " navigation " or " event ".

5.5. Attribution source

An attribution source is a struct with the following items:

source identifier

A string .

source origin

An origin .

event ID

A non-negative 64-bit integer.

attribution destination

A site .

reporting endpoint

An origin .

source type

A source type .

expiry

A length of time.

event 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 .

dedup keys

ordered set of dedup keys associated with this attribution source .

randomized response

A randomized source 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 expiry A length of time.

5.6. 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.7. 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.8. Attribution trigger

An attribution trigger is a struct with the following items:

attribution destination

A site .

trigger time

A point in time.

reporting endpoint

An origin .

filters

A filter map .

negated filters

A filter map .

debug key

Null or a non-negative 64-bit integer.

event-level trigger configurations

A set of event-level trigger configuration .

aggregatable trigger data

A list of 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.

5.9. Event-level report

An event-level report is a struct with the following 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).

reporting endpoint

An origin .

attribution destination

A site .

report time

A point in time.

trigger priority

A 64-bit integer.

trigger time

A point in time.

source identifier

A string.

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.10. 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.11. Attribution rate-limit record

An attribution rate-limit record is a struct with the following items:

scope

Either " source " or " attribution ".

source site

A site .

attribution destination

A site .

reporting endpoint

An origin .

time

A point in time.

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 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 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 reports per attribution destination is a positive integer that controls how many event-level reports can be in the event-level report cache per 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 pending sources is a positive integer that controls the maximum number of distinct attribution destinations for pending 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 report cache size is a positive integer that controls how many event-level reports can be in the event-level report cache .

8. General Algorithms

8.1. Parsing filter data

To parse filter data given a value and a string registrationType :

  1. Assert: registrationType is either " source " or " trigger ".

  2. If value is not a map , return null.

  3. If registrationType is " source " and value [" source_type "] exists , return null.

  4. If value ’s size is greater than the user agent’s max entries per filter map , return null.

  5. Let result be a new filter map .

  6. For each filter data of value :

    1. If data is not a list , return null.

    2. Let set be a new ordered set .

    3. For each d of data :

      1. If d is not a string , return null.

      2. Append d to set .

    4. If set ’s size is greater than the user agent’s max values per filter entry , return null.

    5. Set result [ filter ] to set .

  7. Return result .

Determine whether to limit length or code point length for filter and d above.

8.2. Debug keys

To check if a debug key is allowed given an origin reportingOrigin :

  1. Assert : reportingOrigin is a potentially trustworthy origin .

  2. 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 :

  1. Assert : randomPickRate is between 0 and 1 (both inclusive).

  2. Let r be a random double between 0 (inclusive) and 1 (exclusive) with uniform probability.

  3. If r is less than randomPickRate , return a random item from possibleValues with uniform probability.

  4. 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.

  1. If input ’s code point length is not between 3 and 34 (both inclusive), return an error.

  2. If the first character is not a U+0030 DIGIT ZERO (0), return an error.

  3. 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.

  4. Let value be the code point substring from 2 to the end of input .

  5. If the characters within value are not all ASCII hex digits , return an error.

  6. Interpret value as a hexadecimal number and return as a non-negative 128-bit integer.

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 source site

An attribution source source ’s source site is the result of obtaining a site from source ’s source origin .

9.3. 9.4. Parsing an attribution destination

To parse an attribution destination from a string str :

  1. Let url be the result of running the URL parser on the value of the str .

  2. If url is failure or null, return null.

  3. If url ’s origin is not a potentially trustworthy origin , return null.

  4. Return the result of obtaining a site from url ’s origin .

9.4. 9.5. 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 :

  1. Let possibleTriggerStates be a new empty set .

  2. For each integer triggerData between 0 (inclusive) and triggerDataCardinality (exclusive):

    1. For each integer reportWindow between 0 (inclusive) and numReportWindows (exclusive):

      1. Let state be a new trigger state with the items:

        trigger data

        triggerData

        report window

        reportWindow

      2. Append state to possibleTriggerStates .

  3. Let possibleValues be a new empty set .

  4. For each integer attributions between 0 (inclusive) and maxAttributionsPerSource (inclusive):

    1. Append to possibleValues all distinct attributions -length combinations of possibleTriggerStates .

  5. Return the result of obtaining a randomized response with null, possibleValues , and randomPickRate .

9.5. 9.6. Obtaining an attribution source from an a element

To obtain an attribution source from an anchor given an a element anchor :

  1. If anchor does not have an attributionsrc attribute, return null.

  2. Return null.

Specify the steps for making attributionsrc request.

9.6. 9.7. Obtaining an attribution source from window features

To obtain an attribution source from window features given an ordered map tokenizedFeatures and a browsing context sourceBrowsingContext :

  1. If tokenizedFeatures ["attributionsrc"] does not exist , return null.

  2. If sourceBrowsingContext ’s active window does not have transient activation , return null.

  3. Let decodedSrcBytes be the result of percent-decoding tokenizedFeatures ["attributionsrc"].

  4. Let decodedSrc be the UTF-8 decode without BOM of decodedSrcBytes .

  5. Return null.

Specify the steps for making an attributionsrc request with decodedSrc .

9.7. 9.8. Parsing source-registration JSON

To obtain a source expiry given a value :

  1. If value is not a string , return null.

  2. Let expirySeconds be the result of applying the rules for parsing integers to value .

  3. If expirySeconds is an error, return null.

  4. Let expiry be expirySeconds seconds.

  5. If expiry is less than 1 day, set expiry to 1 day.

  6. If expiry is greater than the user agent’s max source expiry , set expiry to that value.

  7. Return expiry .

To parse aggregation keys given an ordered map map :

  1. Let aggregationKeys be a new ordered map .

  2. If map [" aggregation_keys "] does not exist , return aggregationKeys .

  3. Let values be map [" aggregation_keys "].

  4. If values is not an ordered map , return null.

  5. If values ’s size is greater than the user agent’s max aggregation keys per attribution , return null.

  6. For each key value of values :

    1. If value is not a string , return null.

    2. Let keyPiece be the result of running parse an aggregation key piece with value .

    3. If keyPiece is an error, return null.

    4. Set aggregationKeys [ key ] to keyPiece .

  7. Return aggregationKeys .

To parse source-registration JSON given a string json , an origin sourceOrigin , an origin reportingOrigin , and a source type sourceType :

  1. Assert : sourceOrigin is a potentially trustworthy origin .

  2. Assert : reportingOrigin is a potentially trustworthy origin .

  3. Let value be the result of running parse a JSON string to an Infra value with json .

  4. If value is not an ordered map , return null.

  5. Let sourceEventId be 0.

  6. If value [" source_event_id "] exists and is a string :

    1. 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 .

    2. If sourceEventId is an error, set sourceEventId to 0.

  7. If value [" destination "] does not exist or is not a string , return null.

  8. Let attributionDestination be the result of running parse an attribution destination with value [" destination "].

  9. If attributionDestination is null, return null.

  10. Let expiry be the result of running obtain a source expiry on value [" expiry "].

  11. If expiry is null, set expiry to 30 days.

  12. Let eventReportWindow be the result of running obtain a source expiry on value [" event_report_window "].

  13. If eventReportWindow is null, set eventReportWindow to expiry .

  14. Let priority be 0.

  15. If value [" priority "] exists and is a string :

    1. Set priority to the result of applying the rules for parsing integers to value [" priority "].

    2. If priority is an error, set priority to 0.

  16. Let filterData be a new filter map .

  17. If value [" filter_data "] exists :

    1. Set filterData to the result of running parse filter data with value [" filter_data "] and registrationType set to " source ".

    2. If filterData is null, return null.

  18. Set filterData [" source_type "] to « sourceType ».

  19. Let debugKey be null.

  20. If value [" debug_key "] exists and is a string :

    1. Set debugKey to the result of applying the rules for parsing non-negative integers to value [" debug_key "].

    2. If debugKey is an error, set debugKey to null.

    3. If the result of running check if a debug key is allowed with reportingOrigin is blocked , set debugKey to null.

  21. Let aggregationKeys be the result of running parse aggregation keys with value .

  22. If aggregationKeys is null, return null.

  23. Let aggregatableExpiry be the result of running obtain a source expiry on value [" aggregatable_expiry "]. If aggregatableExpiry is null, set aggregatableExpiry to expiry .

  24. Let triggerDataCardinality be the user agent’s navigation-source trigger data cardinality .

  25. Let randomizedTriggerRate be the user agent’s randomized navigation-source trigger rate .

  26. Let maxAttributionsPerSource be the user agent’s max attributions per navigation source .

  27. If sourceType is " event ":

    1. Round expiry away from zero to the nearest day (86400 seconds).

    2. Set triggerDataCardinality to the user agent’s event-source trigger data cardinality .

    3. Set randomizedTriggerRate ’s to the user agent’s randomized event-source trigger rate .

    4. Set maxAttributionsPerSource to the user agent’s max attributions per event source .

  28. Let numReportWindows be the result of running obtain the number of report windows with sourceType .

  29. Let source be a new attribution source struct whose items are:

    source identifier

    A new unique string

    source origin

    sourceOrigin

    event ID

    sourceEventId

    attribution destination

    attributionDestination

    reporting endpoint

    reportingOrigin

    expiry

    expiry

    event report window

    eventReportWindow

    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 expiry aggregatableExpiry
  30. Return source .

Ensure that attributionDestination ’s scheme is HTTP/HTTPS.

9.8. 9.9. Checking pending destination limit

To check if an attribution source exceeds the pending destination limit given an attribution source source , run the following steps:

  1. Let pendingSources be all entries in the attribution source cache where all of the following are true:

  2. Let distinctDestinations be a new empty set .

  3. For each attribution source pendingSource of pendingSources :

    1. If source ’s attribution destination and pendingSource ’s attribution destination are equal, then return false.

    2. If distinctDestinations contains pendingSource ’s attribution destination , continue .

    3. Append pendingSource ’s attribution destination to distinctDestinations .

  4. If distinctDestinations ’s size is greater than or equal to the user agent’s max destinations covered by pending sources , then return true.

  5. Return false.

Determine whether to change this limit to be time boudned, see Source event limits should be time bounded .

9.9. 9.10. Processing an attribution source

To maybe process a navigation attribution source given a navigation params navigationParams and browsing context browsingContext , run the following steps:

  1. If browsingContext ’s active window does not have transient activation , return.

  2. If browsingContext is not a top-level browsing context , return.

  3. Let attributionSource be navigationParams ’s attribution source .

  4. If attributionSource is null, return.

  5. If attributionSource ’s attribution destination is not same site to navigationParams ’s origin , return.

  6. Queue a task to process an attribution source with attributionSource .

To obtain a fake report given an attribution source source and a trigger state triggerState :

  1. 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 » ]»

  2. Let fakeTrigger be a new attribution trigger with the items:

    attribution destination

    source ’s attribution destination

    trigger time

    source ’s source time

    reporting endpoint

    source ’s reporting endpoint

    filters

    «[]»

    debug key

    null

    event-level trigger configurations

    « fakeConfig »

  3. Let fakeReport be the result of running obtain an event-level report with source , fakeTrigger , and fakeConfig .

  4. Set fakeReport ’s report time to the result of running obtain the report time at a window with source and triggerState ’s report window .

  5. Return fakeReport .

To process an attribution source given an attribution source source :

  1. Let cache be the user agent’s attribution source cache .

  2. Remove all entries in cache where the entry’s expiry time is less than the current time.

  3. If the size of cache is greater than or equal to the user agent’s max source cache size , return.

  4. 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 .

  5. If pendingSourcesForSourceOrigin ’s size is greater than or equal to the user agent’s max pending sources per source origin , return.

  6. If the result of running check if an attribution source exceeds the pending destination limit with source is true, return.

  7. Let rateLimitRecord be a new attribution rate-limit record with the items:

    scope

    " source "

    source site

    source ’s source site

    attribution destination

    source ’s attribution destination

    reporting endpoint

    source ’s reporting endpoint

    time

    source ’s source time

  8. If the result of running should processing be blocked by reporting-endpoint limit with rateLimitRecord is blocked , return.

  9. Append rateLimitRecord to the attribution rate-limit cache .

  10. Remove all entries from the attribution rate-limit cache whose time is at least attribution rate-limit window before the current time.

  11. If source ’s randomized response is not null and is a set :

    1. For each trigger state triggerState of source ’s randomized response :

      1. Let fakeReport be the result of running obtain a fake report with source and triggerState .

      2. Append fakeReport to the event-level report cache .

    2. If source ’s randomized response is not empty , return.

  12. Append source to cache .

Should fake reports respect the user agent’s max reports per attribution destination ?

10. Triggering Algorithms

10.1. Creating an attribution trigger

To parse event triggers given an ordered map map :

  1. Let eventTriggers be a new set .

  2. If map [" event_trigger_data "] does not exist , return eventTriggers .

  3. Let values be map [" event_trigger_data "].

  4. If values is not a list , return null.

  5. For each value of values :

    1. If value is not an ordered map , return null.

    2. Let triggerData be 0.

    3. If value [" trigger_data "] exists and is a string :

      1. Set triggerData to the result of applying the rules for parsing non-negative integers to value [" trigger_data "].

      2. If triggerData is an error, set triggerData to 0.

    4. Let dedupKey be null.

    5. If value [" deduplication_key "] exists and is a string :

      1. Set dedupKey to the result of applying the rules for parsing non-negative integers to value [" deduplication_key "].

      2. If dedupKey is an error, set dedupKey to null.

    6. Let priority be 0.

    7. If value [" priority "] exists and is a string :

      1. Set priority to the result of applying the rules for parsing integers to value [" priority "].

      2. If priority is an error, set priority to 0.

    8. Let filters be a new filter map .

    9. If value [" filters "] exists :

      1. Set filters to the result of running parse filter data with value [" filters "] and registrationType set to " trigger ".

      2. If filters is null, return null.

    10. Let negatedFilters be a new filter map .

    11. If value [" not_filters "] exists :

      1. Set negatedFilters to the result of running parse filter data with value [" not_filters "] and registrationType set to " trigger ".

      2. If negatedFilters is null, return null.

    12. 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

    13. Append eventTrigger to eventTriggers .

  6. 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 :

  1. Let aggregatableTriggerData be a new list .

  2. If map [" aggregatable_trigger_data "] does not exist , return aggregatableTriggerData .

  3. Let values be map [" aggregatable_trigger_data "].

  4. If values is not a list , return null.

  5. If values ’s size is greater than the user agent’s max aggregatable trigger data per trigger , return null.

  6. For each value of values :

    1. If value is not an ordered map , return null.

    2. If value [" key_piece "] does not exist or is not a string , return null.

    3. Let keyPiece be the result of running parse an aggregation key piece with value [" key_piece "].

    4. If keyPiece is an error, return null.

    5. If value [" source_keys "] does not exist or is not a list , return null.

    6. If value [" source_keys "]'s size is greater than the user agent’s max aggregation keys per attribution , return null.

    7. Let sourceKeys be a new set .

    8. For each sourceKey of value [" source_keys "]:

      1. If sourceKey is not a string , return null.

      2. Append sourceKey to sourceKeys .

    9. Let filters be a new filter map .

    10. If value [" filters "] exists :

      1. Set filters to the result of running parse filter data with value [" filters "] and " trigger ".

      2. If filters is null, return null.

    11. Let negatedFilters be a new filter map .

    12. If value [" not_filters "] exists :

      1. Set negatedFilters to the result of running parse filter data with value [" not_filters "] and " trigger ".

      2. If negatedFilters is null, return null.

    13. Let aggregatableTrigger be a new aggregatable trigger data with the items:

      key piece

      keyPiece

      source keys

      sourceKeys

      filters

      filters

      negated filters

      negatedFilters

    14. Append aggregatableTrigger to aggregatableTriggerData .

  7. Return aggregatableTriggerData .

To parse aggregatable values given an ordered map map :

  1. If map [" aggregatable_values "] does not exist , return «[]».

  2. Let values be map [" aggregatable_values "].

  3. If values is not an ordered map , return null.

  4. If values ’s size is great than the user agent’s max aggregation keys per attribution , return null.

  5. For each key value of values :

    1. If value is not an integer, return null.

    2. If value is less than or equal to 0, return null.

  6. Return values .

To parse trigger-registration JSON given a string json , a site destination , and an origin reportingOrigin :

  1. Assert : reportingOrigin is a potentially trustworthy origin .

  2. Let value be the result of running parse a JSON string to an Infra value with json .

  3. If value is not an ordered map , return null.

  4. Let eventTriggers be the result of running parse event triggers with value .

  5. If eventTriggers is null, return null.

  6. Let aggregatableTriggerData be the result of running parse aggregatable trigger data with value .

  7. If aggregatableTriggerData is null, return null.

  8. Let aggregatableValues be the result of running parse aggregatable values with value .

  9. If aggregatableValues is null, return null.

  10. Let aggregatableDedupKey be null.

  11. If value [" aggregatable_deduplication_key "] exists and is a string :

    1. Set aggregatableDedupKey to the result of applying the rules for parsing non-negative integers to value [" aggregatable_deduplication_key "].

    2. If aggregatableDedupKey is an error, set aggregatableDedupKey to null.

  12. Let debugKey be null.

  13. If value [" debug_key "] exists and is a string :

    1. Set debugKey to the result of applying the rules for parsing non-negative integers to value [" debug_key "].

    2. If debugKey is an error, set debugKey to null.

    3. If the result of running check if a debug key is allowed with reportingOrigin is blocked , set debugKey to null.

  14. Let filters be a new filter map .

  15. If value [" filters "] exists:

    1. Set filters to the result of running parse filter data with value [" filters "] and registrationType set to " trigger ".

    2. If filters is null, return null.

  16. Let negatedFilters be a new filter map .

  17. If value [" not_filters "] exists:

    1. Set negatedFilters to the result of running parse filter data with value [" not_filters "] and registrationType set to " trigger ".

    2. If negatedFilters is null, return null.

  18. 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

  19. Return trigger .

10.2. Does filter data match

To match filter values given a filter value a and a filter value b :

  1. If b is empty , then:

    1. If a is empty , then return true.

    2. Otherwise, return false.

  2. Let i be the intersection of a and b .

  3. If i is empty , then return false.

  4. Return true.

To match filter values with negation given a filter value a and a filter value b :

  1. If b is empty , then:

    1. If a is not empty , then return true.

    2. Otherwise, return false.

  2. Let i be the intersection of a and b .

  3. If i is not empty , then return false.

  4. 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 :

  1. Let sourceData be source ’s filter data .

  2. For each key filterValues of filters :

    1. If sourceData [ key ] does not exist , continue .

    2. Let sourceValues be sourceData [ key ].

    3. 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.
  3. Return true.

10.3. Should attribution be blocked by rate limit

Given an attribution trigger trigger and attribution source sourceToAttribute :

  1. Let matchingRateLimitRecords be all attribution rate-limit records record of attribution rate-limit cache where all of the following are true:

  2. If matchingRateLimitRecords ’s size is greater than or equal to max attributions per rate-limit window , return blocked .

  3. Return allowed .

10.4. Should processing be blocked by reporting-endpoint limit

Given an attribution rate-limit record newRecord :

  1. Let max be max source reporting endpoints per rate-limit window .

  2. If newRecord ’s scope is " attribution ", set max to max attribution reporting endpoints per rate-limit window .

  3. Let matchingRateLimitRecords be all attribution rate-limit records record in the attribution rate-limit cache where all of the following are true:

  4. Let distinctReportingEndpoints be a new empty ordered set .

  5. For each record of matchingRateLimitRecords , append record ’s reporting endpoint to distinctReportingEndpoints .

  6. If distinctReportingEndpoints contains newRecord ’s reporting endpoint , return allowed .

  7. If distinctReportingEndpoints ’s size is greater than or equal to max , return blocked .

  8. 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:

  1. Let aggregationKeys be source ’s aggregation keys .

  2. For each triggerData of trigger ’s aggregatable trigger data :

    1. 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 .

    2. 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 .

    3. For each sourceKey of triggerData ’s source keys :

      1. If aggregationKeys [ sourceKey ] does not exist , continue .

      2. Set aggregationKeys [ sourceKey ] to aggregationKeys [ sourceKey ] XOR triggerData ’s key piece .

  3. Let aggregatableValues be trigger ’s aggregatable values .

  4. Let contributions be a new empty list .

  5. For each id key of aggregationKeys :

    1. If aggregatableValues [ id ] does not exist , continue .

    2. Let contribution be a new aggregatable contribution with the items:

      key

      key

      value

      aggregatableValues [ id ]

    3. Append contribution to contributions .

  6. Return contributions .

Use create aggregatable contributions in trigger attribution .

10.6. Triggering attribution

To trigger attribution given an attribution trigger trigger run the following steps:

  1. Let attributionDestination be trigger ’s attribution destination .

  2. Let matchingSources be all entries in the attribution source cache where all of the following are true:

  3. If matchingSources is empty, return.

  4. Set matchingSources to the result of sorting matchingSources in descending order, with a being less than b if any of the following are true:

  5. Let sourceToAttribute be the first item in matchingSources .

  6. Assert : sourceToAttribute ’s randomized response is null or an empty set .

  7. If sourceToAttribute ’s event report window time is less than the current time, return.

  8. If the result of running match an attribution source’s filter data against filters with sourceToAttribute , trigger ’s filters , and isNegated set to false is false, return.

  9. If the result of running match an attribution source’s filter data against filters with sourceToAttribute , trigger ’s negated filters , and isNegated set to true is false, return.

  10. Let matchedConfig be null.

  11. For each event-level trigger configuration config of trigger ’s event-level trigger configurations :

    1. 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 .

    2. 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 .

    3. Set matchedConfig to config .

    4. Break .

  12. If matchedConfig is null, return.

  13. If matchedConfig ’s dedup key is not null and sourceToAttribute ’s dedup keys contains it, return.

  14. Let numMatchingReports be the number of entries in the event-level report cache whose attribution destination equals attributionDestination .

  15. If numMatchingReports is greater than or equal to the user agent’s max reports per attribution destination , return.

  16. If the result of running should attribution be blocked by rate limit with trigger and sourceToAttribute is blocked , return.

  17. Let rateLimitRecord be a new attribution rate-limit record with the items:

    scope

    " attribution "

    source site

    sourceToAttribute ’s source site

    attribution destination

    attributionDestination

    reporting endpoint

    sourceToAttribute ’s reporting endpoint

    time

    trigger ’s trigger time

  18. If the result of running should processing be blocked by reporting-endpoint limit with rateLimitRecord is blocked , return.

  19. Let report be the result of running obtain an event-level report with sourceToAttribute , trigger , and matchedConfig .

  20. Let maxAttributionsPerSource be the user agent’s max attributions per navigation source .

  21. If sourceToAttribute ’s source type is " event ", set maxAttributionsPerSource to the user agent’s max attributions per event source .

  22. If sourceToAttribute ’s number of event-level reports value is equal to maxAttributionsPerSource , then:

    1. Let matchingReports be all entries in the event-level report cache where all of the following are true:

    2. If matchingReports is empty, then remove sourceToAttribute from the attribution source cache and return.

    3. Set matchingReports to the result of sorting matchingReports in ascending order, with a being less than b if any of the following are true:

    4. Let lowestPriorityReport be the first item in matchingReports .

    5. If report ’s trigger priority is less than or equal to lowestPriorityReport ’s trigger priority , return.

    6. Remove lowestPriorityReport from the event-level report cache .

    7. Decrement sourceToAttribute ’s number of event-level reports value by 1.

  23. Remove sourceToAttribute from matchingSources .

  24. For each item of matchingSources :

    1. Remove item from the attribution source cache .

  25. If the size of the event-level report cache is greater than or equal to the user agent’s max report cache size , return.

  26. If sourceToAttribute ’s randomized response is null, append report to the event-level report cache .

  27. Increment sourceToAttribute ’s number of event-level reports value by 1.

  28. If matchedConfig ’s dedup key is not null, append it to sourceToAttribute ’s dedup keys .

  29. Append rateLimitRecord to the attribution rate-limit cache .

  30. Remove all entries from the attribution rate-limit cache whose time is at least attribution rate-limit window before the current time.

  31. 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 .

10.7. Establishing report delivery time

To obtain an expiry deadline given an attribution source source : Return the maximum of source ’s expiry and 2 days (172800 seconds). To obtain early deadlines given a source type sourceType :

  1. If sourceType is " event ", return «».

  2. Return « (2 days - 1 hour), (7 days - 1 hour) ».

To obtain the number of report windows given a source type sourceType :

  1. Let earlyDeadlines be the result of running obtain early deadlines with sourceType .

  2. Return the size of earlyDeadlines + 1.

To obtain a report time from deadline given a time sourceTime and a length of time deadline :

  1. Return sourceTime + deadline + 1 hour.

To obtain the report time at a window given an attribution source source and a non-negative integer window :

  1. Let earlyDeadlines be the result of running obtain early deadlines with source ’s source type .

  2. Let deadline be the result of running obtain an expiry deadline with source . ’s event report window .

  3. If earlyDeadlines [ window ] exists , set deadline to it.

  4. 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 :

  1. Let deadlineToUse be the result of running obtain an expiry deadline with source . ’s event report window .

  2. Let earlyDeadlines be the result of running obtain early deadlines with source ’s source type .

  3. For each earlyDeadline of earlyDeadlines :

    1. Let time be source ’s source time + earlyDeadline .

    2. If time is less than triggerTime , continue .

    3. If earlyDeadline is greater than or equal to deadlineToUse , continue .

    4. Set deadlineToUse to earlyDeadline .

    5. Break .

  4. Return the result of running obtain a report time from deadline with source ’s source time and deadlineToUse .

10.8. 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 :

  1. Let triggerDataCardinality be the user agent’s navigation-source trigger data cardinality .

  2. If source ’s source type is " event ", set triggerDataCardinality to the user agent’s event-source trigger data cardinality .

  3. 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 destination

    source ’s attribution destination .

    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 .

  4. Return report .

11. Report delivery

The user agent MUST periodically iterate over its event-level report cache and run queue a report for delivery on each item.

To queue a report for delivery given an event-level report report , run the following steps in parallel :

  1. If report ’s delivered value is true, return.

  2. Set report ’s delivered value to true.

  3. 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 origin s.

  4. Wait until report ’s report time is the current time.

  5. Optionally, wait a further implementation-defined length of time.

    Note: This is intended to allow user agents to optimize device resource usage.

  6. 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 report body

To serialize an event-level report report , run the following steps:

  1. Let destination be report ’s attribution destination .

  2. Assert : destination is not an opaque origin .

  3. Let data be a map of the following key/value pairs:

    " attribution_destination "

    destination , 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

  4. If report ’s source debug key is not null, set data [" source_debug_key "] to report ’s source debug key , serialized .

  5. If report ’s trigger debug key is not null, set data [" trigger_debug_key "] to report ’s trigger debug key , serialized .

  6. Return the byte sequence resulting from executing serialize an infra value to JSON bytes on data .

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.3. Get report request URL

To generate a report URL given a event-level report report and an optional boolean isDebugReport (default false):

  1. Let reportUrl be a new URL record .

  2. Let reportingOrigin be report ’s reporting endpoint .

  3. Assert : reportingOrigin is not an opaque origin .

  4. Set reportUrl ’s scheme to reportingOrigin ’s scheme .

  5. Set reportUrl ’s host to reportingOrigin ’s host .

  6. Set reportUrl ’s port to reportingOrigin ’s port .

  7. Let path be «" .well-known ", " attribution-reporting "».

  8. If isDebugReport is true, append " debug " to path .

  9. Append " report-event-attribution " to path .

  10. Set reportUrl ’s path to path .

  11. Return reportUrl .

11.4. Creating a report request

To create a report request given an event-level report report :

  1. Let body be the result of executing serialize an event-level report on report .

  2. Let request be a new request with the following properties:

    method

    " POST "

    URL

    url

    header list

    A new header list containing a header named " Content-Type " whose value is " application/json "

    body

    A body whose source is 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 "

  3. Return request .

11.5. Issuing a report request

This algorithm constructs a request and attempts to deliver it to report ’s reporting endpoint .

To attempt to deliver a report given an event-level report report , run the following steps:

  1. Let url be the result of executing generate a report URL on report .

  2. Let request be the result of executing create a report request on report .

  3. Queue a task to fetch request with processResponse being these steps:

    1. Queue a task to remove report from the event-level report cache .

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.6. Issuing a debug report request

To attempt to deliver a debug report given an event-level report report :

  1. Let url be the result of executing generate a report URL on report with isDebugReport set to true.

  2. Let request be the result of executing create a report request on report .

  3. 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

TODO

13. Privacy consideration

TODO

13.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 destination , reporting endpoint , attribution destination , 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.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example" , like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note" , like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[ENCODING]
Anne van Kesteren. Encoding Standard . Living Standard. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch Standard . Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard . Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard . Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy . URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels . March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SECURE-CONTEXTS]
Mike West. Secure Contexts . URL: https://w3c.github.io/webappsec-secure-contexts/
[URL]
Anne van Kesteren. URL Standard . Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard . Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[STORAGE]
Anne van Kesteren. Storage Standard . Living Standard. URL: https://storage.spec.whatwg.org/

IDL Index

interface mixin HTMLAttributionSrcElementUtils {
    [CEReactions] attribute USVString attributionSrc;
};
HTMLAnchorElement includes HTMLAttributionSrcElementUtils;
HTMLImageElement includes HTMLAttributionSrcElementUtils;
HTMLScriptElement includes HTMLAttributionSrcElementUtils;

Issues Index

Specify monkeypatches for source/trigger registration.
Determine whether to limit length or code point length for filter and d above.
Check for " ar_debug " cookie on reportingOrigin and return allowed if it exists, is Secure , is HttpOnly , and is SameSite=None .
Specify the steps for making attributionsrc request.
Specify the steps for making an attributionsrc request with decodedSrc .
Ensure that attributionDestination ’s scheme is HTTP/HTTPS.
Determine whether to change this limit to be time boudned, see Source event limits should be time bounded .
Should fake reports respect the user agent’s max reports per attribution destination ?
Allow the user agent to return null if values ’s size is greater than some constant.
Use create aggregatable contributions in trigger attribution .
This would ideally be replaced by a more descriptive algorithm in Infra. See infra/201
This fetch should use a network partition key for an opaque origin. [Issue #220]
This fetch should use a network partition key for an opaque origin. [Issue #220]
#attribution-source-aggregatable-expiry Referenced in: 9.7. Parsing source-registration JSON #obtain-an-expiry-deadline Referenced in: 10.7. Establishing report delivery time (2)