forked from WICG/attribution-reporting-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.bs
980 lines (767 loc) · 48.7 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
<pre class='metadata'>
Title: Attribution Reporting
Shortname: attribution-reporting
Level: 1
Status: CG-DRAFT
Group: wicg
Repository: WICG/conversion-measurement-api
URL: https://wicg.github.io/conversion-measurement-api
Editor: Charlie Harrison, Google Inc. https://google.com, [email protected]
Editor: John Delaney, Google Inc. https://google.com, [email protected]
Editor: Andrew Paseltiner, Google Inc. https://google.com, [email protected]
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.
Markup Shorthands: markdown on
Complain About: accidental-2119 on, missing-example-ids on
Assume Explicit For: on
</pre>
<pre class=link-defaults>
spec:html; type:element; text:a
</pre>
<pre class="anchors">
spec: uuid; type: dfn; urlPrefix: https://wicg.github.io/uuid/
text: generate a random UUID; url: #dfn-generate-a-random-uuid
</pre>
Introduction {#intro}
=====================
<em>This section is non-normative</em>
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.
## Overview ## {#overview}
A page can register an [=attribution source=] on a site by providing
<{a/attributionsourceeventid}> and <{a/attributiondestination}> attributes on an <{a}> element.
When such an <{a}> element is clicked, and the resulting navigation commits in a document within the [=same site=] as
the <{a/attributiondestination}>, the [=attribution source=] is stored in UA storage.
Alternatively, a page can register an [=attribution source=] on a site by providing a
<{a/registerattributionsource}> attribute on an <{a}> element. When such an <{a}> element is added
to the page, the [=attribution source=] is stored in UA storage.
At a later point, the <{a/attributiondestination}> site may fire an HTTP request to
trigger attribution, which matches an [=attribution trigger=] with any previously
stored sources. If a matching source exists, it is scheduled to be
reported at a later time, possibly multiple days in the future.
Reports are sent to reporting endpoints that are configured in the attribution source
and attribution trigger.
# HTML monkeypatches # {#html-monkeypatches}
<h3 id="longlong-reflection"> long long reflection </h3>
Add the following rules for <a spec=html>reflecting</a> <a spec=html>content attributes</a>:
If a reflecting IDL attribute has a signed integer type ({{long long}}) then, on getting, the content attribute must be
parsed according to the <a spec="html">rules for parsing integers</a>, and if that is successful, and the value is in the
range of the IDL attribute's type, the resulting value must be returned. If, on the other hand, it fails or returns
an out of range value, or if the attribute is absent, then the default value must be returned instead, or 0 if there
is no default value. On setting, the given value must be converted to the shortest possible string representing the
number as a valid integer and then that string must be used as the new content attribute value.
If a reflecting IDL attribute has a signed integer type ({{long long}}) that is <dfn>limited to only non-negative numbers</dfn> then,
on getting, the content attribute must be parsed according to the <a spec="html">rules for parsing non-negative integers</a>, and if
that is successful, and the value is in the range of the IDL attribute's type, the resulting value must be returned.
If, on the other hand, it fails or returns an out of range value, or if the attribute is absent, the default value
must be returned instead, or −1 if there is no default value. On setting, if the value is negative, the user agent
must throw an {{"IndexSizeError"}} {{DOMException}}. Otherwise, the given value must be converted to the shortest possible
string representing the number as a valid non-negative integer and then that string must be used as the new content
attribute value.
<h3 id="monkeypatch-anchor"><a> element</h3>
Add the following <a spec=html>content attributes</a> to the <{a}> element:
: <{a/attributionsourceeventid}>
:: Identifies the declared attribution source
: <{a/attributiondestination}>
:: Site which can attribute an event to the declared attribution source
: <{a/attributionreportto}>
:: [=url/origin=] to receive attribution reports
: <{a/attributionexpiry}>
:: Length of time the attribution souce is valid
: <{a/attributionsourcepriority}>
:: The priority of this source relative to other sources when triggering attribution
: <{a/registerattributionsource}>
:: Registers an [=attribution source=] with a source type "<code>event</code>"
Extend the <{a}> element's <a spec=html>DOM interface</a> to include the following interface:
<pre class="idl">
partial interface HTMLAnchorElement {
[CEReactions] attribute USVString attributionDestination;
[CEReactions] attribute DOMString attributionSourceEventId;
[CEReactions] attribute USVString attributionReportTo;
[CEReactions] attribute long long attributionExpiry;
[CEReactions] attribute long long attributionSourcePriority;
[CEReactions] attribute boolean registerAttributionSource;
};
</pre>
The IDL attributes {{HTMLAnchorElement/attributionDestination}}, {{HTMLAnchorElement/attributionSourceEventId}},
{{HTMLAnchorElement/attributionReportTo}}, {{HTMLAnchorElement/attributionSourcePriority}},
{{HTMLAnchorElement/registerAttributionSource}} must <a spec=html>reflect</a> the respective
content attributes of the same name.
The IDL attribute {{HTMLAnchorElement/attributionExpiry}} must reflect the <{a/attributionexpiry}>
content attribute, [=limited to only non-negative numbers=].
The <dfn for="a" element-attr>attributiondestination</dfn> attribute is a string
representing an [=url/origin=] that is intended to be [=same site=] with the origin
of the final navigation URL resulting from running <a spec="html">follow the hyperlink</a>
with the <{a}> element.
The <dfn for="a" element-attr>attributionsourceeventid</dfn> attribute is a string
containing information about the `attribution source` and will be supplied in the
[=attribution report=].
The <dfn for="a" element-attr>attributionreportto</dfn> attribute optionally declares the
[=origin=] to send the [=attribution report=] for this source.
The <dfn for="a" element-attr>attributionexpiry</dfn> attribute optionally defines the amount
of time in milliseconds the attribution source should be considered for reporting.
The <dfn for="a" element-attr>attributionsourcepriority</dfn> attribute optionally defines the
priority of a source relative to other sources when triggering attribution. If not specified, 0 is used as the
priority. An [=attribution trigger=] with a given [=attribution trigger/reporting endpoint=] and [=attribution trigger/attribution destination=]
will always be attributed to the source with the highest priority value that has the same [=attribution source/reporting endpoint=]
and [=attribution source/attribution destination=].
The <dfn for="a" element-attr>registerattributionsource</dfn> attribute, if present, registers an
additional source whose [=attribution source/source type=] is "<code>event</code>".
Note: One simple priority scheme would be to use the current millisecond timestamp as the priority value.
<h3 id="monkeypatch-navigation">Navigation</h3>
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 source/attribution destination=].
<h4 id="monkeypatch-navigation-params">Navigation Params</h4>
A <a spec="HTML">navigation params</a> struct has an item:
: <dfn for="navigation params">attribution source</dfn>
:: null or an [=attribution source=] declared when initiating a navigation
<h4 id="monkeypatch-navigate-algorithm">Navigate algorithm</h4>
Modify the <a spec="html">navigate</a> algorithm to accept a new optional parameter
<var>attributionSource</var> of type [=attribution source=] defaulting to null.
In <a spec="html">navigate</a>, within step
> 19. 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
> 7. Let navigationParams be a new navigation params whose request is null, response is resource
> ...
to set the [=navigation params/attribution source=] of |navigationParams| to |attributionSource|.
In the case where
> If resource is a request whose URL's scheme is "javascript"
modify the substep
> 4. Let navigationParams be a new navigation params whose request is resource,
> ...
to set the [=navigation params/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 <a spec="html">process a navigate fetch</a> 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.
<h4 id="monkeypatch-navigate-fetch">Process a navigate fetch</h4>
Modify the <a spec="html">process a navigate fetch</a> algorithm to accept a new optional parameter
<var>attributionSource</var> of type [=attribution source=] defaulting to null.
In <a spec="html">process a navigate fetch</a>, modify the step
> 15. 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 <a spec="html">process a navigate fetch</a> algorithm.
Modify the step
> 19. Let navigationParams be a new navigation params whose request is request, response is response,
> ...
to set the [=navigation params/attribution source=] of |navigationParams| to |attributionSource|.
<h4 id="monkeypatch-document-creation">Document creation</h4>
At the time <a spec="html">create and initialize a <code>Document</code> object</a> is invoked, the user agent knows the final URL used for the
navigation and can validate the [=attribution source/attribution destination=].
In <a spec="html">create and initialize a <code>Document</code> object</a>, before
> 2. 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|.
<h3 id="monkeypatch-following-hyperlink">Follow the hyperlink</h4>
Attribution source information declared on the <{a}> element needs to be passed to the
<a spec="html">navigate</a> algorithm.
In <a spec="html">follow the hyperlink</a> after
> 14. Let historyHandling be "replace" if windowType is not "existing or none"; otherwise, "default".
add the following steps:
1. Let <var>attributionSource</var> be null.
1. 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:
> 15. Queue an element task on the DOM manipulation task source given subject to navigate target to request
> ...
to call <a spec="html">navigate</a> with |attributionSource| set to |attributionSource|.
# Fetch monkeypatches # {#fetch-monkeypatches}
In <a spec="FETCH">main fetch</a>, within the step:
> 17. If response is not a network error and any of the following returns blocked
> ...
add the following check to the list:
* [=should internalResponse to request be blocked as attribution trigger=]
# Attribution Reporting API
<pre class="idl">
dictionary AttributionSourceParams {
required USVString attributionDestination;
required DOMString attributionSourceEventId;
USVString attributionReportTo;
long long attributionExpiry;
long long attributionSourcePriority;
};
[Exposed=Window, SecureContext]
interface AttributionReporting {
Promise<undefined> registerAttributionSource(AttributionSourceParams params);
};
[SecureContext]
partial interface Window {
readonly attribute AttributionReporting attributionReporting;
};
</pre>
The
<dfn method for=AttributionReporting><code>registerAttributionSource(<var>params</var>)</code></dfn>
method steps are:
1. Let |source| be the result of running [=obtain an attribution source from params=] with |params|
and the [=relevant settings object=] of [=this=].
1. If |source| is null, return [=a promise rejected with=] the {{undefined}} value.
1. Set |source| to the result of running [=obtain an event attribution source from a source=] with |source|.
1. [=Queue a task=] to [=process an attribution source=] with |source|.
1. Return [=a promise resolved with=] the {{undefined}} value.
Note: This function returns a promise even though the promise is always resolved or rejected by the
time the function returns; in the future, the promise may be resolved with a value that provides
finer-grained detail about other errors that occurred during the [=process an attribution source=]
step.
# Permissions Policy integration # {#permission-policy-integration}
This specification defines a [=policy-controlled feature=] identified by the string "<code><dfn>attribution-reporting</dfn></code>". Its [=default allowlist=] is *.
# Structures # {#structures}
<h3 dfn-type=dfn>Attribution source</h3>
An attribution source is a [=struct=] with the following items:
<dl dfn-for="attribution source">
: <dfn>source identifier</dfn>
:: A [=string=].
: <dfn>source origin</dfn>
:: An [=url/origin=].
: <dfn>event id</dfn>
:: A non-negative 64-bit integer.
: <dfn>attribution destination</dfn>
:: A [=site=].
: <dfn>reporting endpoint</dfn>
:: An [=url/origin=].
: <dfn>source type</dfn>
:: Either "<code>navigation</code>" or "<code>event</code>".
: <dfn>expiry</dfn>
:: A length of time.
: <dfn>priority</dfn>
:: A 64-bit integer.
: <dfn>source time</dfn>
:: A point in time.
: <dfn>number of reports</dfn>
:: Number of [=attribution reports=] created for this [=attribution source=].
: <dfn>dedup keys</dfn>
:: [=ordered set=] of [=attribution trigger/dedup keys=] associated with this [=attribution source=].
: <dfn>attribution mode</dfn>
:: Either "<code>truthfully</code>", "<code>never</code>", or "<code>falsely</code>".
</dl>
<h3 dfn-type=dfn>Attribution trigger</h3>
An attribution trigger is a [=struct=] with the following items:
<dl dfn-for="attribution trigger">
: <dfn>attribution destination</dfn>
:: A [=site=].
: <dfn>trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>event source trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>trigger time</dfn>
:: A point in time.
: <dfn>reporting endpoint</dfn>
:: An [=url/origin=].
: <dfn>dedup key</dfn>
:: Null or a 64-bit integer.
: <dfn>priority</dfn>
:: A 64-bit integer.
</dl>
<h3 dfn-type=dfn>Attribution report</h3>
An attribution report is a [=struct=] with the following items:
<dl dfn-for="attribution report">
: <dfn>event id</dfn>
:: A non-negative 64-bit integer.
: <dfn>source type</dfn>
:: Either "<code>navigation</code>" or "<code>event</code>".
: <dfn>trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>reporting endpoint</dfn>
:: An [=url/origin=].
: <dfn>attribution destination</dfn>
:: A [=site=].
: <dfn>report time</dfn>
:: A point in time.
: <dfn>trigger priority</dfn>
:: A 64-bit integer.
: <dfn>trigger time</dfn>
:: A point in time.
: <dfn>source identifier</dfn>
:: A string.
: <dfn>delivered</dfn> (default false)
:: A boolean.
: <dfn>report id</dfn>
:: A string.
</dl>
<h3 dfn-type=dfn>Attribution rate-limit record</h3>
An attribution rate-limit record is a [=struct=] with the following items:
<dl dfn-for="attribution rate-limit record">
: <dfn>source site</dfn>
:: A [=site=].
: <dfn>attribution destination</dfn>
:: A [=site=].
: <dfn>source type</dfn>
:: Either "<code>navigation</code>" or "<code>event</code>".
: <dfn>trigger time</dfn>
:: A point in time.
</dl>
# Storage # {#storage}
A user agent holds an <dfn>attribution source cache</dfn>, which is an [=ordered set=] of [=attribution sources=].
A user agent holds an <dfn>attribution report cache</dfn>, which is an [=ordered set=] of [=attribution reports=].
A user agent holds an <dfn>attribution rate-limit cache</dfn>, which is an [=ordered set=] of [=attribution rate-limit records=].
The above caches are collectively known as the <dfn>attribution caches</dfn>. The [=attribution caches=] are
shared among all [=environment settings objects=].
Note: This would ideally use <a spec=storage>storage bottles</a> 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.
# Source Algorithms # {#source-algorithms}
<h3 id="obtaining-attribution-source-expiry-time">Obtaining an attribution source's expiry time</h3>
An [=attribution source=] |source|'s <dfn for="attribution source">expiry time</dfn> is |source|'s [=attribution source/source time=] + |source|'s [=attribution source/expiry=].
<h3 algorithm id="parsing-data-fields">Parsing data fields</h3>
This section defines how to parse strings into integers for
[=attribution source/event id=], [=attribution trigger/trigger data=], and [=attribution trigger/event source trigger data=].
To <dfn>parse attribution data</dfn> given a [=string=] |input| modulo an integer
|maxData| perform the following steps. They return a non-negative integer:
1. Let |decodedInput| be the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to |input|.
1. If |decodedInput| is an error, return zero.
1. If |decodedInput| is greater than 2<sup>64</sup>, return zero.
1. Let |clampedDecodedInput| be the remainder when dividing |decodedInput| by |maxData|.
1. Return |clampedDecodedInput|.
<h3 algorithm id="parsing-attribution-destination">Parsing an attribution destination</h3>
To <dfn>parse an attribution destination</dfn> from a string |str|:
1. Let |url| be the result of running the [=URL parser=] on the value of
the |str|.
1. If |url| is failure or null, return null.
1. If |url|'s [=url/origin=] is an [=opaque origin=], return null.
1. Return the result of [=obtain a site|obtaining a site=] from |url|'s
[=url/origin=].
<h3 algorithm id="obtaining-attribution-source-anchor">Obtaining an attribution source from an <code>a</code> element</h3>
To <dfn>obtain an attribution source from an anchor</dfn> given an <{a}> element |anchor|:
1. If anchor does not have both an <{a/attributiondestination}> attribute and an <{a/attributionsourceeventid}> attribute, return null.
1. Let |params| be an {{AttributionSourceParams}} with the following key/value pairs:
: {{AttributionSourceParams/attributionDestination}}
:: |anchor|'s <{a/attributiondestination}> attribute
: {{AttributionSourceParams/attributionSourceEventId}}
:: |anchor|'s <{a/attributionsourceeventid}> attribute
: {{AttributionSourceParams/attributionReportTo}}
:: |anchor|'s <{a/attributionreportto}> attribute
: {{AttributionSourceParams/attributionExpiry}}
:: |anchor|'s <{a/attributionexpiry}> attribute
: {{AttributionSourceParams/attributionSourcePriority}}
:: |anchor|'s <{a/attributionsourcepriority}> attribute
1. Return the result of running [=obtain an attribution source from params=] with |params| and
|anchor|'s [=relevant settings object=].
<h3 algorithm id="obtaining-event-attribution-source-anchor">Obtaining an event attribution source from an <code>a</code> element</h3>
To <dfn>obtain an event attribution source from an anchor</dfn> given an <{a}> element |anchor|, run the following steps:
1. If |anchor| does not have a <{a/registerattributionsource}> attribute, return null.
1. Let |source| be the result of running [=obtain an attribution source from an anchor=] with |anchor|.
1. If |source| is null, return null.
1. Return the result of running [=obtain an event attribution source from a source=] with |source|.
<h3 algorithm id="obtaining-event-attribution-source-source">Obtaining an event attribution source from a source</h3>
To <dfn>obtain an event attribution source from a source</dfn> given an [=attribution source=] |source|, run the following steps:
1. Let |resultSource| be a shallow clone of |source|.
1. Set |resultSource|'s [=attribution source/source identifier=] to a new unique opaque string.
1. Set |resultSource|'s [=attribution source/source type=] to "<code>event</code>".
1. Round |resultSource|'s [=attribution source/expiry=] away from zero to the nearest day (86400 seconds).
1. Set |resultSource|'s [=attribution source/attribution mode=] to one of
"<code>truthfully</code>", "<code>never</code>", or "<code>falsely</code>", with
[=implementation-defined=] probability.
1. Return |resultSource|.
<h3 algorithm id="obtaining-attribution-source-params">Obtaining an attribution source from {{AttributionSourceParams}}</h3>
To <dfn>obtain an attribution source from params</dfn> given an {{AttributionSourceParams}} |params|
and an [=environment settings object=] |settings|, run the following steps:
1. Let |sourceIdentifier| be a new unique string.
1. Let |currentTime| be the current time.
1. Assert: |params|["{{AttributionSourceParams/attributionDestination}}"] and
|params|["{{AttributionSourceParams/attributionSourceEventId}}"] [=map/exist=].
1. If |settings|'s [=environment settings object/responsible document=] is
not [=allowed to use=] the [=attribution-reporting=] [=policy-controlled feature=], return null.
1. Let |attributionDestination| be the result of running
[=parse an attribution destination=] with |params|["{{AttributionSourceParams/attributionDestination}}"].
1. If |attributionDestination| is null, return null.
1. Let |sourceOrigin| be |settings|'s [=environment/top-level origin=].
1. If |sourceOrigin| is an [=opaque origin=], return null.
1. Let |reportingOrigin| be |sourceOrigin|.
1. If |params|["{{AttributionSourceParams/attributionReportTo}}"] [=map/exists=], then:
1. Let |reportingUrl| be the result of running the
[=URL parser=] with |params|["{{AttributionSourceParams/attributionReportTo}}"].
1. If |reportingUrl| is failure or null, return null.
1. If |reportingUrl|'s [=url/origin=] is an [=opaque origin=], return null.
1. Set |reportingOrigin| to |reportingUrl|'s [=url/origin=].
1. Let |expiry| be 30 days.
1. If |params|["{{AttributionSourceParams/attributionExpiry}}"] [=map/exists=],
then set |expiry| to that value.
1. Let |priority| be 0.
1. If |params|["{{AttributionSourceParams/attributionSourcePriority}}"] [=map/exists=],
then set |priority| to that value.
1. Let |source| be a new [=attribution source=] struct whose items are:
: [=attribution source/source identifier=]
:: |sourceIdentifier|
: [=attribution source/source origin=]
:: |sourceOrigin|
: [=attribution source/event id=]
:: The result of running [=parse attribution data=] with
|params|["{{AttributionSourceParams/attributionSourceEventId}}"] modulo [=max event id value=].
: [=attribution source/attribution destination=]
:: |attributionDestination|
: [=attribution source/reporting endpoint=]
:: |reportingOrigin|
: [=attribution source/expiry=]
:: |expiry|
: [=attribution source/priority=]
:: |priority|
: [=attribution source/source time=]
:: |currentTime|
: [=attribution source/source type=]
:: "<code>navigation</code>"
: [=attribution source/attribution mode=]
:: "<code>truthfully</code>"
1. Return |source|.
<dfn>Max event id value</dfn> is a vendor-specific integer which controls
the maximum value which can be used as an [=attribution source/event id=].
<h3 id="processing-an-attribution-source">Processing an attribution source</h3>
To <dfn>maybe process a navigation attribution source</dfn> given a <a spec="HTML">navigation params</a>
|navigationParams| and [=browsing context=] |browsingContext|, run the following steps:
1. If |browsingContext| is not a <a spec="html">top-level browsing context</a>, return.
1. Let <var>attributionSource</var> be |navigationParams|'s [=navigation params/attribution source=].
1. If |attributionSource| is null, return.
1. If |attributionSource|'s [=attribution source/attribution destination=] is not [=same site=] to |navigationParams|'s
<a href="https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigation-params-origin">origin</a>, return.
1. [=Queue a task=] to [=process an attribution source=] with |attributionSource|.
To <dfn>process an attribution source</dfn> given an [=attribution source=] |source|:
1. Let |cache| be the user agent's [=attribution source cache=].
1. [=list/Remove=] all entries in |cache| where all of the following are true:
* the entry's [=attribution source/attribution destination=] and |source|'s [=attribution source/attribution destination=] are equal.
* the entry's [=attribution source/reporting endpoint=] is [=same origin=] with |source|'s [=attribution source/reporting endpoint=].
* the entry's [=attribution source/number of reports=] value is greater than 0.
Note: This causes the user agent to favor triggering newer [=attribution sources=] over sources that have already been triggered.
1. [=list/Remove=] all entries in |cache| where the entry's [=attribution source/expiry time=] is less than the current time.
1. If the [=list/size=] of |cache| is greater than or equal to the user agent's
[=max source cache size=], return.
1. If |source|'s [=attribution source/attribution mode=] is "<code>falsely</code>", then:
1. Assert: |source|'s [=attribution source/source type=] is "<code>event</code>".
1. If the [=list/size=] of the [=attribution report cache=] is greater than or equal to the user
agent's [=max report cache size=], return.
1. Let |fakeTrigger| be a new [=attribution trigger=] with the items:
: [=attribution trigger/attribution destination=]
:: |source|'s [=attribution source/attribution destination=]
: [=attribution trigger/trigger data=]
:: 0
: [=attribution trigger/event source trigger data=]
:: A random value between 0 (inclusive) and the user agent's
[=max event source trigger data value=] (exclusive)
: [=attribution trigger/trigger time=]
:: |source|'s [=attribution source/source time=]
: [=attribution trigger/reporting endpoint=]
:: |source|'s [=attribution source/reporting endpoint=]
: [=attribution trigger/dedup key=]
:: null
: [=attribution trigger/priority=]
:: 0
1. Let |fakeReport| be the result of running [=obtain a report=] with |source| and |fakeTrigger|.
1. Add |fakeReport| to the [=attribution report cache=].
1. Return.
1. [=set/Append=] |source| to |cache|.
Issue: Should fake reports respect the user agent's [=max reports per attribution destination=]?
<dfn>Max source cache size</dfn> is a vendor-specific integer which controls how many
[=attribution sources=] can be in the [=attribution source cache=].
# Triggering Algorithms # {#trigger-algorithms}
<h3 algorithm id="noising-data-fields">Noising trigger data</h3>
This section defines how to noise [=attribution trigger/trigger data=] and
[=attribution trigger/event source trigger data=].
To <dfn>noise trigger data</dfn> given an integer |input|, integer |maxData|, and double |noiseRate|,
run the following steps:
1. Assert: |input| is between 0 (inclusive) and |maxData| exclusive.
1. Assert: |noiseRate| is between 0 and 1 (both inclusive).
1. Let |r| be a random double between 0 (inclusive) and 1 (exclusive).
1. If |r| is greater than or equal to |noiseRate|, return |input|.
1. Return a random integer between 0 (inclusive) and |maxData| (exclusive).
<h3 algorithm id="attribution-trigger-creation">Creating an attribution trigger</h3>
To <dfn>obtain an attribution trigger</dfn> given a [=URL=] |url| and an
[=environment settings object=] |environment|, run the following steps:
1. Let |triggerData| be 0.
1. If |url|'s [=url/query=] has a "`trigger-data`" field, set |triggerData| to the result of running [=parse attribution data=] with
the value associated with the field modulo the user agent's [=max trigger data value=].
1. Set |triggerData| to the result of running [=noise trigger data=] with |triggerData|, the
user agent's [=max trigger data value=], and the user agent's [=trigger data noise rate=].
1. Let |eventSourceTriggerData| be 0.
1. If |url|'s [=url/query=] has an "`event-source-trigger-data`" field, set |eventSourceTriggerData| to the result of running [=parse attribution data=] with
the value associated with the field modulo the user agent's [=max event source trigger data value=].
1. Set |eventSourceTriggerData| to the result of running [=noise trigger data=] with
|eventSourceTriggerData|, the user agent's [=max event source trigger data value=], and the
user agent's [=event source trigger data noise rate=].
1. Let |dedupKey| be null.
1. If |url|'s [=url/query=] has a "`dedup-key`" field, and applying the <a spec="html">rules for
parsing integers</a> to the field's value results in an integer, then set |dedupKey| to that
value.
1. Let |triggerPriority| be 0.
1. If |url|'s [=url/query=] has a "`priority`" field, and applying the
<a spec="html">rules for parsing integers</a> to the field's value results
in an integer, set |triggerPriority| to that value.
1. Let |trigger| be a new [=attribution trigger=] with the items:
: [=attribution trigger/attribution destination=]
:: The result of [=obtain a site|obtaining a site=] from |environment|'s [=environment/top-level origin=].
: [=attribution trigger/trigger data=]
:: |triggerData|.
: [=attribution trigger/event source trigger data=]
:: |eventSourceTriggerData|.
: [=attribution trigger/trigger time=]
:: The current time.
: [=attribution trigger/reporting endpoint=]
:: |url|'s [=url/origin=].
: [=attribution trigger/dedup key=]
:: |dedupKey|.
: [=attribution trigger/priority=]
:: |triggerPriority|.
1. Return |trigger|.
<dfn>Max trigger data value</dfn> is a vendor-specific integer which controls the potential values of [=attribution trigger/trigger data=].
<dfn>Max event source trigger data value</dfn> is a vendor-specific integer which controls the potential values of [=attribution trigger/event source trigger data=].
<dfn>Trigger data noise rate</dfn> is a vendor-specific double between 0 and 1 (both inclusive) which controls noising of [=attribution trigger/trigger data=].
<dfn>Event source trigger data noise rate</dfn> is a vendor-specific double between 0 and 1 (both inclusive) which controls noising of [=attribution trigger/event source trigger data=].
Issue: Formalize how to parse the query similar to URLSearchParams.
<h3 dfn id="should-block-response">Should internalResponse to request be blocked as attribution trigger</h3>
Given a [=request=] |request|:
1. If |request|'s [=request/current URL's=] [=url/origin=] is an [=opaque origin=], return <strong>allowed</strong>.
1. If |request|'s [=request/current URL's=] [=url/path=] is not equal to « ".well-known","attribution-reporting","trigger-attribution" »,
return <strong>allowed</strong>.
1. Let |environment| be |request|'s [=request/window=].
1. If |environment| is not an [=environment settings object=], return <strong>allowed</strong>.
1. If |environment|'s [=environment settings object/responsible document=] is not [=allowed to use=] the [=attribution-reporting=] [=policy-controlled feature=],
return <strong>allowed</strong>.
1. If |environment|'s [=environment settings object/origin=] is not a [=potentially trustworthy origin=], return <strong>allowed</strong>.
1. If |environment|'s [=environment/top-level origin=] is an [=opaque origin=], return <strong>allowed</strong>.
1. If |environment|'s [=environment/top-level origin=] is not a [=potentially trustworthy origin=], return <strong>allowed</strong>.
1. If |request|'s [=request/current URL's=] [=url/origin=] is not a [=potentially trustworthy origin=], return <strong>allowed</strong>.
1. If |request|'s [=request/redirect count=] is less than 1, return <strong>allowed</strong>.
1. Let |previousUrl| be the second to last [=URL=] in |request|'s
[=request/URL list=].
1. If |request|'s [=request/current URL's=] [=url/origin=] is not [=same origin=] with
|previousUrl|'s [=url/origin=], return <strong>allowed</strong>.
Note: The restriction to require a redirect is necessary to ensure that the
request's origin is aware and in control of the conversion registration. This could also be done with a
<a href="https://github.com/WICG/conversion-measurement-api/issues/91">header-based mechanism</a>.
1. Let |trigger| be the result of running [=obtain an attribution trigger=] with |request|'s [=request/current URL=] and |environment|.
1. [=Queue a task=] to [=trigger attribution=] with |trigger|.
1. Return <strong>blocked</strong>.
<h3 dfn id="should-rate-limit-attribution">Should attribution be blocked by rate limit</h3>
Given an [=attribution trigger=] |trigger| and [=attribution source=] |sourceToAttribute|:
1. Let |sourceSite| be the result of [=obtain a site|obtaining a site=] from |sourceToAttribute|'s
[=attribution source/source origin=].
1. Let |matchingRateLimitRecords| be all entries in the [=attribution rate-limit cache=] where all of the following are true:
* entry's [=attribution rate-limit record/source site=] and |sourceSite| are equal
* entry's [=attribution rate-limit record/attribution destination=] and |trigger|'s [=attribution trigger/attribution destination=] are equal
* entry's [=attribution rate-limit record/source type=] and |sourceToAttribute|'s [=attribution source/source type=] are equal
* entry's [=attribution rate-limit record/trigger time=] is at least [=attribution rate-limit window=] before |trigger|'s [=attribution trigger/trigger time=]
1. If the [=list/size=] of |matchingRateLimitRecords| is greater than or equal to [=max attributions per rate-limit window=], return <strong>blocked</strong>.
1. Return <strong>allowed</strong>.
<dfn>Attribution rate-limit window</dfn> is a vendor-specific duration that controls the
rate-limiting window for attribution.
<dfn>Max attributions per rate-limit window</dfn> is a vendor-specific integer that controls
the maximum number of attributions for a ([=attribution rate-limit record/source site=],
[=attribution rate-limit record/attribution destination=],
[=attribution rate-limit record/source type=]) per [=attribution rate-limit window=].
<h3 algorithm id="triggering-attribution">Triggering attribution</h3>
To <dfn>trigger attribution</dfn> given an [=attribution trigger=] |trigger| run the following steps:
1. Let |attributionDestination| be |trigger|'s [=attribution trigger/attribution destination=].
1. Let |matchingSources| be all entries in the [=attribution source cache=] where all of the following are true:
* entry's [=attribution source/attribution destination=] and |attributionDestination| are equal.
* entry's [=attribution source/reporting endpoint=] and |trigger|'s [=attribution trigger/reporting endpoint=] are equal.
* entry's [=attribution source/expiry time=] is greater than the current time.
1. If |matchingSources| is empty, return.
1. Set |matchingSources| to the result of [=list/sort in descending order|sorting=] |matchingSources|
in descending order, with |a| being less than |b| if any of the following are true:
* |a|'s [=attribution source/priority=] is less than |b|'s [=attribution source/priority=].
* |a|'s [=attribution source/priority=] is equal to |b|'s [=attribution source/priority=] and |a|'s
[=attribution source/source time=] is less than |b|'s [=attribution source/source time=].
1. Let |sourceToAttribute| be the first item in |matchingSources|.
1. Assert: |sourceToAttribute|'s [=attribution source/attribution mode=] is
"<code>truthfully</code>" or "<code>never</code>".
1. If |trigger|'s [=attribution trigger/dedup key=] is not null and |sourceToAttribute|'s
[=attribution source/dedup keys=] [=list/contains=] it, return.
1. Let |numMatchingReports| be the number of entries in the [=attribution report cache=] whose
[=attribution report/attribution destination=] equals |attributionDestination|.
1. If |numMatchingReports| is greater than or equal to the user agent's
[=max reports per attribution destination=], return.
1. If the result of running [=should attribution be blocked by rate limit=] with |trigger| and
|sourceToAttribute| is <strong>blocked</strong>, return.
1. Let |report| be the result of running [=obtain a report=] with |sourceToAttribute| and |trigger|.
1. If |sourceToAttribute|'s [=attribution source/number of reports=] value is equal to the
user agent's [=max reports per source=] value, then:
1. Let |matchingReports| be all entries in the [=attribution report cache=] where all of the following are true:
* entry's [=attribution report/report time=] and |report|'s [=attribution report/report time=] are equal.
* entry's [=attribution report/source identifier=] [=string/is=] |report|'s [=attribution report/source identifier=]
1. If |matchingReports| is empty, then [=list/remove=] |sourceToAttribute| from the [=attribution source cache=] and return.
1. Set |matchingReports| to the result of [=list/sort in ascending order|sorting=] |matchingReports|
in ascending order, with |a| being less than |b| if any of the following are true:
* |a|'s [=attribution report/trigger priority=] is less than |b|'s [=attribution report/trigger priority=].
* |a|'s [=attribution report/trigger priority=] is equal to |b|'s [=attribution report/trigger priority=]
and |a|'s [=attribution report/trigger time=] is greater than |b|'s [=attribution report/trigger time=].
1. Let |lowestPriorityReport| be the first item in |matchingReports|.
1. If |report|'s [=attribution report/trigger priority=] is less than or equal to |lowestPriorityReport|'s [=attribution report/trigger priority=], return.
1. Remove |lowestPriorityReport| from the [=attribution report cache=].
1. Decrement |sourceToAttribute|'s [=attribution source/number of reports=] value by 1.
1. [=list/Remove=] |sourceToAttribute| from |matchingSources|.
1. For each |item| of |matchingSources|:
1. [=list/Remove=] |item| from the [=attribution source cache=].
1. If the [=list/size=] of the [=attribution report cache=] is greater than or equal to the user
agent's [=max report cache size=], return.
1. If |sourceToAttribute|'s [=attribution source/attribution mode=] is "<code>truthfully</code>",
add |report| to the [=attribution report cache=].
1. Increment |sourceToAttribute|'s [=attribution source/number of reports=] value by 1.
1. If |trigger|'s [=attribution trigger/dedup key=] is not null, [=list/append=] it to |sourceToAttribute|'s
[=attribution source/dedup keys=].
1. Let |rateLimitRecord| be a new [=attribution rate-limit record=] with the items:
: [=attribution rate-limit record/source site=]
:: The result of [=obtain a site|obtaining a site=] from |sourceToAttribute|'s [=attribution source/source origin=].
: [=attribution rate-limit record/attribution destination=]
:: |attributionDestination|
: [=attribution rate-limit record/source type=]
:: |sourceToAttribute|'s [=attribution source/source type=]
: [=attribution rate-limit record/trigger time=]
:: |trigger|'s [=attribution trigger/trigger time=]
1. Add |rateLimitRecord| to the [=attribution rate-limit cache=].
1. Remove all entries from the [=attribution rate-limit cache=] whose
[=attribution rate-limit record/trigger time=] is at least [=attribution rate-limit window=]
before the current time.
<dfn>Max reports per attribution destination</dfn> is a vendor-specific integer which controls how
many [=attribution reports=] can be in the [=attribution report cache=] for an
[=attribution report/attribution destination=].
<dfn>Max reports per source</dfn> is a vendor-specific integer which controls how many [=attribution reports=] can be created for an [=attribution source=].
<dfn>Max report cache size</dfn> is a vendor-specific integer which controls how many
[=attribution reports=] can be in the [=attribution report cache=].
Note: This parameter represents a privacy/utility tradeoff. Lower values mean that less trigger-side data
can be associated with a source event id. Larger values allow for more attribution triggers to be reported.
<h3 algorithm id="delivery-time">Establishing report delivery time</h3>
To <dfn>obtain a report delivery time</dfn> given an [=attribution source=] |source| and a
[=attribution trigger/trigger time=] |triggerTime|, perform the following steps. They
return a point in time.
1. If |source|'s [=attribution source/source type=] is "<code>event</code>", return |source|'s
[=attribution source/expiry time=] + 1 hour.
1. Let |timeToTrigger| be the difference between
|triggerTime| and [=attribution source/source time=].
Note: |timeToTrigger| is less than |source|'s [=attribution source/expiry=] because it is not normally possible to
convert an expired attribution source.
1. If:
<dl class="switch">
<dt>|timeToTrigger| <= (2 days - 1 hour)</dt>
<dd>return [=attribution source/source time=] + 2 days.</dd>
<dt> |source|'s [=attribution source/expiry=] > (2 days - 1 hour)
- and |source|'s [=attribution source/expiry=] < (7 days - 1 hour)
- and |timeToTrigger| <= |source|'s [=attribution source/expiry=]
</dt>
<dd>return |source|'s [=attribution source/expiry time=] + 1 hour.</dd>
<dt>|timeToTrigger| <= (7 days - 1 hour)</dt>
<dd>return [=attribution source/source time=] + 7 days.</dd>
<dt>Otherwise</dt>
<dd>return |source|'s [=attribution source/expiry time=] + 1 hour.</dd>
</dl>
<h3 algorithm id="obtaining-a-report">Obtaining a report</h3>
To <dfn>obtain a report</dfn> given an [=attribution source=] |source| and an [=attribution trigger=] |trigger|:
1. Let |triggerData| be |trigger|'s [=attribution trigger/trigger data=].
1. If |source|'s [=attribution source/source type=] is "<code>event</code>", set |triggerData| to |trigger|'s [=attribution trigger/event source trigger data=].
1. Let |report| be a new [=attribution report=] struct whose items are:
: [=attribution report/event id=]
:: |source|'s [=attribution source/event id=].
: [=attribution report/trigger data=]
:: |triggerData|.
: [=attribution report/reporting endpoint=]
:: |source|'s [=attribution source/reporting endpoint=].
: [=attribution report/attribution destination=]
:: |source|'s [=attribution source/attribution destination=].
: [=attribution report/reporting time=]
:: The result of running [=obtain a report delivery time=] with |source| and |trigger|'s [=attribution trigger/trigger time=].
: [=attribution report/trigger priority=]
:: |trigger|'s [=attribution trigger/priority=].
: [=attribution report/trigger time=]
:: |trigger|'s [=attribution trigger/trigger time=].
: [=attribution report/source identifier=]
:: |source|'s [=attribution source/source identifier=].
: [=attribution report/report id=]
:: The result of [=generating a random UUID=].
1. Return |report|.
# Report delivery # {#report-delivery}
The user agent MUST periodically [=set/iterate=] over its [=attribution report cache=] and run [=queue a report for delivery=] on each item.
To <dfn>queue a report for delivery</dfn> given an [=attribution report=] |report|, run the following steps [=in parallel=]:
1. If |report|'s [=attribution report/delivered=] value is true, return.
1. Set |report|'s [=attribution report/delivered=] value to true.
1. If |report|'s [=attribution report/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 [=attribution source/source origin=]s.
1. Wait until |report|'s [=attribution report/report time=] is the current time.
1. Optionally, wait a further [=implementation-defined=] length of time.
Note: This is intended to allow user agents to optimize device resource usage.
1. Run [=attempt to deliver a report=] with |report|.
<h3 id="serialize-integer">Serialize an integer</h3>
To <dfn>serialize an integer</dfn>, represent it as a string of the shortest possible decimal number.
Issue: This would ideally be replaced by a more descriptive algorithm in Infra. See
<a href="https://github.com/whatwg/infra/issues/201">infra/201</a>
<h3 id="serialize-report-body">Serialize attribution report body</h3>
To <dfn>serialize an [=attribution report=]</dfn> |report|, run the following steps:
1. Let |destination| be |report|'s [=attribution report/attribution destination=].
1. Assert: |destination| is not an [=opaque origin=].
1. Let |data| be a [=map=] of the following key/value pairs:
: "`attribution_destination`"
:: |destination|, <a href="https://html.spec.whatwg.org/multipage/origin.html#serialization-of-a-site">serialized</a>
: "`source_type`"
:: |report|'s [=attribution report/source type=]
: "`source_event_id`"
:: |report|'s [=attribution report/event id=], [=serialize an integer|serialized=]
: "`trigger_data`"
:: |report|'s [=attribution report/trigger data=], [=serialize an integer|serialized=]
: "`report_id`"
:: |report|'s [=attribution report/report id=]
1. 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 should be limited in number and subject to random delays.
<h3 id="get-report-url">Get report request URL</h3>
To <dfn>generate a report URL</dfn> for a given [=attribution report=] |report|, run the following steps:
1. Let |reportUrl| be a new [=URL record=].
1. Let |reportingOrigin| be |report|'s [=attribution report/reporting endpoint=].
1. Assert: |reportingOrigin| is not an [=opaque origin=].
1. Set |reportUrl|'s [=url/scheme=] to |reportingOrigin|'s [=origin/scheme=].
1. Set |reportUrl|'s [=url/host=] to |reportingOrigin|'s [=origin/host=].
1. Set |reportUrl|'s [=url/port=] to |reportingOrigin|'s [=origin/port=].
1. Set |reportUrl|'s [=url/path=] to «"`.well-known`", "`attribution-reporting`", "`report-attribution`"».
1. Return |reportUrl|.
<h3 id="issue-report-request">Issuing a report request</h3>
This algorithm constructs a [=request=] and attempts to deliver it to
|report|'s [=attribution report/reporting endpoint=].
To <dfn>attempt to deliver a report</dfn> given an [=attribution report=] |report|, run the following steps:
1. Let |body| be the result of executing [=serialize an attribution report=] on |report|.
1. Let |url| be the result of executing [=generate a report URL=] on |report|.
1. 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 [=body/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`"
1. [=Queue a task=] to [=fetch=] |request| with [=fetch/processResponse=] being these steps:
1. [=Queue a task=] to remove |report| from the [=attribution report cache=].
Issue(220): This fetch should use a network partition key for an opaque origin.
A user agent MAY retry this algorithm in the event that there was an error.
# Security considerations # {#security-considerations}
TODO
# Privacy consideration # {#privacy-considerations}
TODO
<h3 id="clearing-attribution-storage">Clearing attribution storage</h3>
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 [=attribution source/source origin=],
[=attribution source/attribution destination=], [=attribution source/reporting endpoint=],
[=attribution report/attribution destination=], or [=attribution report/reporting endpoint=]
is the [=same origin|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.