forked from WICG/attribution-reporting-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.bs
1444 lines (1170 loc) · 68.1 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
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class='metadata'>
Title: Attribution Reporting
Shortname: attribution-reporting
Level: 1
Status: CG-DRAFT
Group: wicg
Repository: WICG/attribution-reporting-api
URL: https://wicg.github.io/attribution-reporting-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
spec:html; type:element; text:script
</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}
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 source/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.
# HTML monkeypatches # {#html-monkeypatches}
<h3 id="monkeypatch-attributionsrc">API for elements</h3>
<pre class="idl">
interface mixin HTMLAttributionSrcElementUtils {
[CEReactions] attribute USVString attributionSrc;
};
HTMLAnchorElement includes HTMLAttributionSrcElementUtils;
HTMLImageElement includes HTMLAttributionSrcElementUtils;
HTMLScriptElement includes HTMLAttributionSrcElementUtils;
</pre>
Add the following <a spec=html>content attributes</a>:
: <{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 <dfn for="a" element-attr>attributionsrc</dfn> attribute is a [=string=]
representing the [=URL=] of the resource that will register an
[=attribution source=] when the <{a}> is navigated.
: <{img}>
:: The <dfn for="img" element-attr>attributionsrc</dfn> attribute is a
[=string=] representing the [=URL=] of the resource that will register an
[=attribution source=] or [=attribution trigger=] when set.
: <{script}>
:: The <dfn for="script" element-attr>attributionsrc</dfn> attribute is a
[=string=] representing the [=URL=] of the resource that will register an
[=attribution source=] or [=attribution trigger=] when set.
The IDL attribute {{HTMLAttributionSrcElementUtils/attributionSrc}}
must <a spec=html>reflect</a> the respective content attribute of the same
name.
<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|.
<h3 id="monkeypatch-window-open">Window open steps</h4>
Attribution source information declared via `window.open()` needs to be passed to
the <a spec="html">navigate</a> algorithm.
In <a spec="html">window open steps</a> after
> 10. 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 <var ignore="">tokenizedFeatures</var> and |source browsing context|.
Modify the step:
> 3. [=Navigate=] |target browsing context| to |request|, with <var>[=exceptionsEnabled=]</var> set to true and the [=source browsing context=] set to |source browsing context|.
to also pass |attributionSource| into the <a spec="html">navigate</a> algorithm.
Modify the step:
> 5. [=Navigate=] |target browsing context| to |request|, with <var>[=exceptionsEnabled=]</var> set to true and the [=source browsing context=] set to |source browsing context|.
to also pass |attributionSource| into the <a spec="html">navigate</a> algorithm.
# Fetch monkeypatches # {#fetch-monkeypatches}
Issue: Specify monkeypatches for source/trigger registration.
# Permissions Policy integration # {#permission-policy-integration}
This specification defines a [=policy-controlled feature=] identified by the string "<code><dfn noexport>attribution-reporting</dfn></code>". Its [=default allowlist=] is `'self'`.
Note: In the Chromium implementation the [=default allowlist=] is temporarily set to `*` to ease testing.
# Structures # {#structures}
<h3 dfn-type=dfn>Trigger state</h3>
A trigger state is a [=struct=] with the following items:
<dl dfn-for="trigger state">
: <dfn>trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>report window</dfn>
:: A non-negative integer.
</dl>
<h3 dfn-type=dfn>Randomized source response</h3>
A randomized source response is null or a [=set=] of [=trigger states=].
<h3 id="attribution-filtering">Attribution filtering</h3>
A <dfn>filter value</dfn> is an [=ordered set=] of [=strings=].
A <dfn>filter map</dfn> is an [=ordered map=] whose [=map/key|keys=] are [=strings=] and whose
[=map/value|values=] are [=filter values=].
<h3 dfn-type=dfn>Source type</h3>
A source type is either "`navigation`" or "`event`".
<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>
:: A [=source type=].
: <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 event-level reports</dfn>
:: Number of [=event-level reports=] created for this [=attribution source=].
: <dfn>dedup keys</dfn>
:: [=ordered set=] of [=event-level trigger configuration/dedup keys=] associated with this [=attribution source=].
: <dfn>randomized response</dfn>
:: A [=randomized source response=].
: <dfn>randomized trigger rate</dfn>
:: A number between 0 and 1 (both inclusive).
: <dfn>filter data</dfn>
:: A [=filter map=].
: <dfn>debug key</dfn>
:: Null or a non-negative 64-bit integer.
: <dfn>aggregation keys</dfn>
:: An [=ordered map=] whose [=map/key|keys=] are [=strings=] and whose [=map/value|values=] are
non-negative 128-bit integers.
</dl>
<h3 dfn-type=dfn>Attribution aggregatable trigger data</h3>
An attribution aggregatable trigger data is a [=struct=] with the following items:
<dl dfn-for="attribution aggregatable trigger data">
: <dfn>key piece</dfn>
:: A non-negative 128-bit integer.
: <dfn>source keys</dfn>
:: An [=ordered set=] of [=strings=].
: <dfn>filters</dfn>
:: A [=filter map=].
: <dfn>negated filters</dfn>
:: A [=filter map=].
</dl>
<h3 dfn-type=dfn>Event-level trigger configuration</h3>
An event-level trigger configuration is a [=struct=] with the following items:
<dl dfn-for="event-level trigger configuration">
: <dfn>trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>dedup key</dfn>
:: Null or a non-negative 64-bit integer.
: <dfn>priority</dfn>
:: A 64-bit integer.
: <dfn>filters</dfn>
:: A [=filter map=].
: <dfn>negated filters</dfn>
:: A [=filter map=].
</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 time</dfn>
:: A point in time.
: <dfn>reporting endpoint</dfn>
:: An [=url/origin=].
: <dfn>filters</dfn>
:: A [=filter map=].
: <dfn>negated filters</dfn>
:: A [=filter map=].
: <dfn>debug key</dfn>
:: Null or a non-negative 64-bit integer.
: <dfn>event-level trigger configurations</dfn>
:: A [=set=] of [=event-level trigger configuration=].
: <dfn>aggregatable trigger data</dfn>
:: A [=list=] of [=attribution aggregatable trigger data=].
: <dfn>aggregatable values</dfn>
:: An [=ordered map=] whose [=map/key|keys=] are [=strings=] and whose
[=map/value|values=] are non-negative 32-bit integers.
</dl>
<h3 dfn-type=dfn>Event-level report</h3>
An event-level report is a [=struct=] with the following items:
<dl dfn-for="event-level report">
: <dfn>event ID</dfn>
:: A non-negative 64-bit integer.
: <dfn>source type</dfn>
:: A [=source type=].
: <dfn>trigger data</dfn>
:: A non-negative 64-bit integer.
: <dfn>randomized trigger rate</dfn>
:: A number between 0 and 1 (both inclusive).
: <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=].
: <dfn>source debug key</dfn>
:: Null or a non-negative 64-bit integer.
: <dfn>trigger debug key</dfn>
:: Null or a non-negative 64-bit integer.
</dl>
<h3 dfn-type=dfn>Aggregatable contribution</h3>
An aggregatable contribution is a [=struct=] with the following items:
<dl dfn-for="aggregatable contribution">
: <dfn>key</dfn>
:: A non-negative 128-bit integer.
: <dfn>value</dfn>
:: A non-negative 32-bit integer.
</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>scope</dfn>
:: Either "`source`" or "`attribution`".
: <dfn>source site</dfn>
:: A [=site=].
: <dfn>attribution destination</dfn>
:: A [=site=].
: <dfn>reporting endpoint</dfn>
:: An [=url/origin=].
: <dfn>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>event-level report cache</dfn>, which is an [=ordered set=] of [=event-level 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.
# Vendor-Specific Values # {#vendor-specific-values}
<dfn>Source event ID cardinality</dfn> is a positive integer that controls the
maximum value that can be used as an [=attribution source/event id=].
<dfn>Max source expiry</dfn> is a positive length of time that controls the
maximum value that can be used as an [=attribution source/expiry=]. It must be
greater than or equal to 30 days.
<dfn>Max entries per filter map</dfn> is a positive integer that controls the
maximum [=map/size=] of a [=filter map=].
<dfn>Max values per filter entry</dfn> is a positive integer that
controls the maximum [=set/size=] of a [=filter map=] entry.
<dfn>Max pending sources per source origin</dfn> is a positive integer that
controls how many [=attribution sources=] can be in the
[=attribution source cache=] per [=attribution source/source origin=].
<dfn>Navigation-source trigger data cardinality</dfn> is a positive integer
that controls the valid range of
[=event-level trigger configuration/trigger data=] for triggers that are
attributed to an [=attribution source=] whose
[=attribution source/source type=] is "`navigation`":
0 <= [=event-level trigger configuration/trigger data=] < [=navigation-source trigger data cardinality=].
<dfn>Event-source trigger data cardinality</dfn> is a positive integer that
controls the valid range of [=event-level trigger configuration/trigger data=]
for triggers that are attributed to an [=attribution source=] whose
[=attribution source/source type=] is "`event`":
0 <= [=event-level trigger configuration/trigger data=] < [=event-source trigger data cardinality=].
<dfn>Randomized navigation-source trigger rate</dfn> is a double between 0 and
1 (both inclusive) that controls the randomized response probability of an
[=attribution source=] whose [=attribution source/source type=] is
"`navigation`".
<dfn>Randomized event-source trigger rate</dfn> is a double between 0 and 1
(both inclusive) that controls the randomized response probability of an
[=attribution source=] whose [=attribution source/source type=] is "`event`".
<dfn>Max reports per attribution destination</dfn> is a positive integer that
controls how many [=event-level reports=] can be in the
[=event-level report cache=] per
[=event-level report/attribution destination=].
<dfn>Max attributions per navigation source</dfn> is a positive integer that
controls how many times a single [=attribution source=] whose
[=attribution source/source type=] is "`navigation`" can create an
[=event-level report=].
<dfn>Max attributions per event source</dfn> is a positive integer that
controls how many times a single [=attribution source=] whose
[=attribution source/source type=] is "`event`" can create an
[=event-level report=].
<dfn>Max destinations covered by pending sources</dfn> is a positive
integer that controls the maximum number of distinct [=attribution source/attribution destinations=]
for pending [=attribution sources=] with a given ([=attribution source/source site=], [=attribution source/reporting endpoint=]).
<dfn>Attribution rate-limit window</dfn> is a positive length of time that
controls the rate-limiting window for attribution.
<dfn>Max source reporting endpoints per rate-limit window</dfn> is a positive
integer that controls the maximum number of distinct
[=attribution source/reporting endpoint|reporting endpoints=] for a
([=attribution rate-limit record/source site=],
[=attribution rate-limit record/attribution destination=]) that can create
[=attribution sources=] per [=attribution rate-limit window=].
<dfn>Max attribution reporting endpoints per rate-limit window</dfn> is a
positive integer that controls the maximum number of distinct
[=attribution trigger/reporting endpoint|reporting endpoints=] for a
([=attribution rate-limit record/source site=],
[=attribution rate-limit record/attribution destination=]) that can create
[=event-level reports=] per [=attribution rate-limit window=].
<dfn>Max attributions per rate-limit window</dfn> is a positive 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/reporting endpoint=]) per
[=attribution rate-limit window=].
<dfn>Max source cache size</dfn> is a positive integer that controls how many
[=attribution sources=] can be in the [=attribution source cache=].
<dfn>Max report cache size</dfn> is a positive integer that controls how many
[=event-level reports=] can be in the [=event-level report cache=].
# General Algorithms # {#general-algorithms}
<h3 id="parsing-filter-data">Parsing filter data</h3>
To <dfn>parse filter data</dfn> given a |value| and a [=string=]
<dfn for="parse filter data"><var>registrationType</var></dfn>:
1. Assert: |registrationType| is either "`source`" or "`trigger`".
1. If |value| is not a [=map=], return null.
1. If |registrationType| is "`source`" and |value|["`source_type`"]
[=map/exists=], return null.
1. If |value|'s [=map/size=] is greater than the user agent's
[=max entries per filter map=], return null.
1. Let |result| be a new [=filter map=].
1. [=map/iterate|For each=] |filter| → |data| of |value|:
1. If |data| is not a [=list=], return null.
1. Let |set| be a new [=ordered set=].
1. [=list/iterate|For each=] |d| of |data|:
1. If |d| is not a [=string=], return null.
1. [=set/Append=] |d| to |set|.
1. If |set|'s [=set/size=] is greater than the user agent's
[=max values per filter entry=], return null.
1. [=map/Set=] |result|[|filter|] to |set|.
1. Return |result|.
Issue: Determine whether to limit [=string/length=] or
[=string/code point length=] for |filter| and |d| above.
<h3 id="debug-keys">Debug keys</h3>
To <dfn>check if a debug key is allowed</dfn> given an [=origin=]
|reportingOrigin|:
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
1. Return <strong>blocked</strong>.
Issue: Check for "`ar_debug`" cookie on |reportingOrigin| and return
<strong>allowed</strong> if it exists, is `Secure`, is `HttpOnly`, and is
`SameSite=None`.
<h3 id="obtaining-randomized-response">Obtaining a randomized response</h3>
To <dfn>obtain a randomized response</dfn> given |trueValue|, a [=set=] |possibleValues|, and a
double |randomPickRate|:
1. [=Assert=]: |randomPickRate| is between 0 and 1 (both inclusive).
1. Let |r| be a random double between 0 (inclusive) and 1 (exclusive) with uniform probability.
1. If |r| is less than |randomPickRate|, return a random item from |possibleValues| with uniform
probability.
1. Otherwise, return |trueValue|.
# 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 id="obtaining-attribution-source-site">Obtaining an attribution source's source site</h3>
An [=attribution source=] |source|'s <dfn for="attribution source">source site</dfn> is the result
of [=obtain a site|obtaining a site=] from |source|'s [=attribution source/source origin=].
<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 not a [=potentially trustworthy origin=],
return null.
1. Return the result of [=obtain a site|obtaining a site=] from |url|'s
[=url/origin=].
<h3 algorithm id="obtaining-randomized-source-response">Obtaining a randomized source response</h3>
To <dfn>obtain a randomized source response</dfn> given a positive integer
|triggerDataCardinality|, a positive integer |maxAttributionsPerSource|, a positive integer
|numReportWindows|, and a double |randomPickRate|:
1. Let |possibleTriggerStates| be a new [=list/is empty|empty=] [=set=].
1. 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 state/trigger data=]
:: |triggerData|
: [=trigger state/report window=]
:: |reportWindow|
1. [=set/Append=] |state| to |possibleTriggerStates|.
1. Let |possibleValues| be a new [=list/is empty|empty=] [=set=].
1. For each integer |attributions| between 0 (inclusive) and |maxAttributionsPerSource| (inclusive):
1. [=set/Append=] to |possibleValues| all distinct |attributions|-length combinations of
|possibleTriggerStates|.
1. Return the result of [=obtaining a randomized response=] with null, |possibleValues|, and
|randomPickRate|.
<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 an <{a/attributionsrc}> attribute, return null.
1. Return null.
Issue: Specify the steps for making attributionsrc request.
<h3 algorithm id="obtaining-attribution-source-window-features">Obtaining an attribution source from window features</h3>
To <dfn>obtain an attribution source from window features</dfn> given an [=ordered map=] |tokenizedFeatures|
and a [=browsing context=] |sourceBrowsingContext|:
1. If |tokenizedFeatures|["attributionsrc"] does not [=map/exists|exist=], return null.
1. If |sourceBrowsingContext|'s [=browsing context/active window=] does not have [=transient activation=], return null.
1. Let |decodedSrcBytes| be the result of [=string/percent-decode|percent-decoding=] |tokenizedFeatures|["attributionsrc"].
1. Let |decodedSrc| be the [=UTF-8 decode without BOM=] of |decodedSrcBytes|.
1. Return null.
Issue: Specify the steps for making an attributionsrc request with |decodedSrc|.
<h3 algorithm id="parsing-source-registration">Parsing source-registration JSON</h3>
To <dfn>obtain a source expiry</dfn> given an [=ordered map=] |value|:
1. If |value|["`expiry`"] does not [=map/exists|exist=] or is not a [=string=],
return 30 days.
1. Let |expirySeconds| be the result of applying the
<a spec="html">rules for parsing integers</a> to |value|["`expiry`"].
1. If |expirySeconds| is an error, return 30 days.
1. Let |expiry| be |expirySeconds| seconds.
1. If |expiry| is less than 1 day, set |expiry| to 1 day.
1. If |expiry| is greater than the user agent's [=max source expiry=], set
|expiry| to that value.
To <dfn noexport>parse source-registration JSON</dfn> given a [=string=]
|json|, an [=origin=] |sourceOrigin|, an [=origin=] |reportingOrigin|, and a
[=source type=] |sourceType|:
1. [=Assert=]: |sourceOrigin| is a [=potentially trustworthy origin=].
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
1. Let |value| be the result of running
[=parse a JSON string to an Infra value=] with |json|.
1. If |value| is not an [=ordered map=], return null.
1. Let |sourceEventId| be 0.
1. If |value|["`source_event_id`"] [=map/exists=] and is a [=string=]:
1. Set |sourceEventId| to the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to
|value|["`source_event_id`"] modulo the user agent's
[=source event ID cardinality=].
1. If |sourceEventId| is an error, set |sourceEventId| to 0.
1. If |value|["`destination`"] does not [=map/exists|exist=] or is not a
[=string=], return null.
1. Let |attributionDestination| be the result of running
[=parse an attribution destination=] with |value|["`destination`"].
1. If |attributionDestination| is null, return null.
1. Let |expiry| be the result of running [=obtain a source expiry=] on |value|.
1. Let |priority| be 0.
1. If |value|["`priority`"] [=map/exists=] and is a [=string=]:
1. Set |priority| to the result of applying the
<a spec="html">rules for parsing integers</a> to |value|["`priority`"].
1. If |priority| is an error, set |priority| to 0.
1. Let |filterData| be a new [=filter map=].
1. If |value|["`filter_data`"] [=map/exists=]:
1. Set |filterData| to the result of running [=parse filter data=] with
|value|["`filter_data`"] and [=parse filter data/registrationType=] set
to "`source`".
1. If |filterData| is null, return null.
1. [=map/Set=] |filterData|["`source_type`"] to « |sourceType| ».
1. Let |debugKey| be null.
1. If |value|["`debug_key`"] [=map/exists=] and is a [=string=]:
1. Set |debugKey| to the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to
|value|["`debug_key`"].
1. If |debugKey| is an error, set |debugKey| to null.
1. If the result of running [=check if a debug key is allowed=] with
|reportingOrigin| is <strong>blocked</strong>, set |debugKey| to null.
1. Let |triggerDataCardinality| be the user agent's
[=navigation-source trigger data cardinality=].
1. Let |randomizedTriggerRate| be the user agent's
[=randomized navigation-source trigger rate=].
1. Let |maxAttributionsPerSource| be the user agent's
[=max attributions per navigation source=].
1. If |sourceType| is "`event`":
1. Round |expiry| away from zero to the nearest day (86400 seconds).
1. Set |triggerDataCardinality| to the user agent's
[=event-source trigger data cardinality=].
1. Set |randomizedTriggerRate|'s to the user agent's
[=randomized event-source trigger rate=].
1. Set |maxAttributionsPerSource| to the user agent's
[=max attributions per event source=].
1. Let |numReportWindows| be the result of running
[=obtain the number of report windows=] with |sourceType|.
1. Let |source| be a new [=attribution source=] struct whose items are:
: [=attribution source/source identifier=]
:: A new unique [=string=]
: [=attribution source/source origin=]
:: |sourceOrigin|
: [=attribution source/event ID=]
:: |sourceEventId|
: [=attribution source/attribution destination=]
:: |attributionDestination|
: [=attribution source/reporting endpoint=]
:: |reportingOrigin|
: [=attribution source/expiry=]
:: |expiry|
: [=attribution source/priority=]
:: |priority|
: [=attribution source/source time=]
:: The current time
: [=attribution source/source type=]
:: |sourceType|
: [=attribution source/randomized response=]
:: The result of [=obtaining a randomized source response=] with
|triggerDataCardinality|, |maxAttributionsPerSource|,
|numReportWindows|, and |randomizedTriggerRate|.
: [=attribution source/randomized trigger rate=]
:: |randomizedTriggerRate|
: [=attribution source/filter data=]
:: |filterData|
: [=attribution source/debug key=]
:: |debugKey|
: [=attribution source/aggregation keys=]
:: «[]»
1. Return |source|.
Issue: Ensure that |attributionDestination|'s [=origin/scheme=] is HTTP/HTTPS.
Issue: Parse |value|["`aggregation_keys`"].
<h3 id="check-pending-destination-limit">Checking pending destination limit</h3>
To <dfn>check if an [=attribution source=] exceeds the pending destination limit</dfn> 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:
* entry's [=attribution source/source site=] and |source|'s [=attribution source/source site=]
are equal.
* entry's [=attribution source/reporting endpoint=] and |source|'s
[=attribution source/reporting endpoint=] are [=same origin=].
* entry's [=attribution source/number of event-level reports=] is equal to 0.
1. Let |distinctDestinations| be a new [=set/is empty|empty=] [=set=].
1. For each [=attribution source=] |pendingSource| of |pendingSources|:
1. If |source|'s [=attribution source/attribution destination=] and |pendingSource|'s
[=attribution source/attribution destination=] are equal, then return false.
1. If |distinctDestinations| [=set/contains=] |pendingSource|'s
[=attribution source/attribution destination=], [=iteration/continue=].
1. [=set/Append=] |pendingSource|'s [=attribution source/attribution destination=] to
|distinctDestinations|.
1. If |distinctDestinations|'s [=set/size=] is greater than or equal to
the user agent's [=max destinations covered by pending sources=], then return true.
1. Return false.
Issue: Determine whether to change this limit to be time boudned, see
<a href="https://github.com/WICG/attribution-reporting-api/issues/482">Source event limits should be time bounded</a>.
<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|'s [=browsing context/active window=] does not have [=transient activation=], return.
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>obtain a fake report</dfn> given an [=attribution source=] |source| and
a [=trigger state=] |triggerState|:
1. Let |fakeConfig| be a new [=event-level trigger configuration=] with the items:
: [=event-level trigger configuration/trigger data=]
:: |triggerState|'s [=trigger state/trigger data=]
: [=event-level trigger configuration/dedup key=]
:: null
: [=event-level trigger configuration/priority=]
:: 0
: [=event-level trigger configuration/filters=]
:: «[ "`source_type`" → « |source|'s [=attribution source/source type=] » ]»
1. Let |fakeTrigger| be a new [=attribution trigger=] with the items:
: [=attribution trigger/attribution destination=]
:: |source|'s [=attribution source/attribution destination=]
: [=attribution trigger/trigger time=]
:: |source|'s [=attribution source/source time=]
: [=attribution trigger/reporting endpoint=]
:: |source|'s [=attribution source/reporting endpoint=]
: [=attribution trigger/filters=]
:: «[]»
: [=attribution trigger/debug key=]
:: null
: [=attribution trigger/event-level trigger configurations=]
:: « |fakeConfig| »
1. Let |fakeReport| be the result of running [=obtain an event-level report=] with |source|,
|fakeTrigger|, and |fakeConfig|.
1. Set |fakeReport|'s [=event-level report/report time=] to the result of
running [=obtain the report time at a window=] with |source| and
|triggerState|'s [=trigger state/report window=].
1. Return |fakeReport|.
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 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. Let |pendingSourcesForSourceOrigin| be the [=set=] of all
[=attribution sources=] |pendingSource| of |cache| where |pendingSource|'s
[=attribution source/source origin=] and |source|'s
[=attribution source/source origin=] are [=same origin=].
1. If |pendingSourcesForSourceOrigin|'s [=list/size=] is greater than or equal
to the user agent's [=max pending sources per source origin=], return.
1. If the result of running [=check if an attribution source exceeds the pending destination limit=]
with |source| is true, return.
1. Let |rateLimitRecord| be a new [=attribution rate-limit record=] with the items:
: [=attribution rate-limit record/scope=]
:: "`source`"
: [=attribution rate-limit record/source site=]
:: |source|'s [=attribution source/source site=]
: [=attribution rate-limit record/attribution destination=]
:: |source|'s [=attribution source/attribution destination=]
: [=attribution rate-limit record/reporting endpoint=]
:: |source|'s [=attribution source/reporting endpoint=]
: [=attribution rate-limit record/time=]
:: |source|'s [=attribution source/source time=]
1. If the result of running [=should processing be blocked by reporting-endpoint limit=] with
|rateLimitRecord| is <strong>blocked</strong>, return.
1. [=set/Append=] |rateLimitRecord| to the [=attribution rate-limit cache=].
1. [=list/Remove=] all entries from the [=attribution rate-limit cache=] whose
[=attribution rate-limit record/time=] is at least [=attribution rate-limit window=]
before the current time.
1. If |source|'s [=attribution source/randomized response=] is not null and is a [=set=]:
1. [=map/iterate|For each=] [=trigger state=] |triggerState| of |source|'s
[=attribution source/randomized response=]:
1. Let |fakeReport| be the result of running [=obtain a fake report=]
with |source| and |triggerState|.
1. [=set/Append=] |fakeReport| to the [=event-level report cache=].
1. If |source|'s [=attribution source/randomized response=] is not [=set/is empty|empty=], return.
1. [=set/Append=] |source| to |cache|.
Issue: Should fake reports respect the user agent's [=max reports per attribution destination=]?
# Triggering Algorithms # {#trigger-algorithms}
<h3 algorithm id="attribution-trigger-creation">Creating an attribution trigger</h3>
To <dfn>parse event triggers</dfn> given an [=ordered map=] |map|:
1. Let |eventTriggers| be a new [=set=].
1. If |map|["`event_trigger_data`"] does not [=map/exists|exist=], return
|eventTriggers|.
1. Let |values| be |map|["`event_trigger_data`"].
1. If |values| is not a [=list=], return null.
1. [=list/iterate|For each=] |value| of |values|:
1. If |value| is not an [=ordered map=], return null.
1. Let |triggerData| be 0.
1. If |value|["`trigger_data`"] [=map/exists=] and is a [=string=]:
1. Set |triggerData| to the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to
|value|["`trigger_data`"].
1. If |triggerData| is an error, set |triggerData| to 0.
1. Let |dedupKey| be null.
1. If |value|["`deduplication_key`"] [=map/exists=] and is a [=string=]:
1. Set |dedupKey| to the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to
|value|["`deduplication_key`"].
1. If |dedupKey| is an error, set |dedupKey| to null.
1. Let |priority| be 0.
1. If |value|["`priority`"] [=map/exists=] and is a [=string=]:
1. Set |priority| to the result of applying the
<a spec="html">rules for parsing integers</a> to
|value|["`priority`"].
1. If |priority| is an error, set |priority| to 0.
1. Let |filters| be a new [=filter map=].
1. If |value|["`filters`"] [=map/exists=]:
1. Set |filters| to the result of running [=parse filter data=] with
|value|["`filters`"] and [=parse filter data/registrationType=] set
to "`trigger`".
1. If |filters| is null, return null.
1. Let |negatedFilters| be a new [=filter map=].
1. If |value|["`not_filters`"] [=map/exists=]:
1. Set |negatedFilters| to the result of running [=parse filter data=]
with |value|["`not_filters`"] and
[=parse filter data/registrationType=] set to "`trigger`".
1. If |negatedFilters| is null, return null.
1. Let |eventTrigger| be a new [=event-level trigger configuration=] with
the items:
: [=event-level trigger configuration/trigger data=]
:: |triggerData|
: [=event-level trigger configuration/dedup key=]
:: |dedupKey|
: [=event-level trigger configuration/priority=]
:: |priority|
: [=event-level trigger configuration/filters=]
:: |filters|
: [=event-level trigger configuration/negated filters=]
:: |negatedFilters|
1. [=set/Append=] |eventTrigger| to |eventTriggers|.
1. Return |eventTriggers|.
Issue: Allow the user agent to return null if |values|'s [=list/size=] is
greater than some constant.
To <dfn noexport>parse trigger-registration JSON</dfn> given a [=string=]
|json|, a [=site=] |destination|, and an [=origin=] |reportingOrigin|:
1. [=Assert=]: |reportingOrigin| is a [=potentially trustworthy origin=].
1. Let |value| be the result of running
[=parse a JSON string to an Infra value=] with |json|.
1. If |value| is not an [=ordered map=], return null.
1. Let |eventTriggers| be the result of running [=parse event triggers=]
with |value|.
1. If |eventTriggers| is null, return null.
1. Let |debugKey| be null.
1. If |value|["`debug_key`"] [=map/exists=] and is a [=string=]:
1. Set |debugKey| to the result of applying the
<a spec="html">rules for parsing non-negative integers</a> to
|value|["`debug_key`"].
1. If |debugKey| is an error, set |debugKey| to null.
1. If the result of running [=check if a debug key is allowed=] with
|reportingOrigin| is <strong>blocked</strong>, set |debugKey| to null.
1. Let |filters| be a new [=filter map=].
1. If |value|["`filters`"] exists:
1. Set |filters| to the result of running [=parse filter data=] with
|value|["`filters`"] and [=parse filter data/registrationType=] set to
"`trigger`".
1. If |filters| is null, return null.
1. Let |negatedFilters| be a new [=filter map=].
1. If |value|["`not_filters`"] exists:
1. Set |negatedFilters| to the result of running [=parse filter data=] with
|value|["`not_filters`"] and [=parse filter data/registrationType=] set
to "`trigger`".
1. If |negatedFilters| is null, return null.
1. Let |trigger| be a new [=attribution trigger=] with the items:
: [=attribution trigger/attribution destination=]
:: |destination|
: [=attribution trigger/trigger time=]
:: The current time.
: [=attribution trigger/reporting endpoint=]
:: |reportingOrigin|
: [=attribution trigger/filters=]
:: |filters|
: [=attribution trigger/negated filters=]
:: |negatedFilters|
: [=attribution trigger/debug key=]
:: |debugKey|
: [=attribution trigger/event-level trigger configurations=]
:: |eventTriggers|
: [=attribution trigger/aggregatable trigger data=]
:: «»
: [=attribution trigger/aggregatable values=]
:: «[]»
1. Return |trigger|.
Issue: Parse aggregatable trigger fields.
<h3 dfn id="does-filter-data-match">Does filter data match</h3>
To <dfn>match [=filter values=]</dfn> given a [=filter value=] |a| and a [=filter value=] |b|:
1. If |b| [=set/is empty=], then:
1. If |a| [=set/is empty=], then return true.