| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| privacy:cookie_syncing [2026/08/26 18:40] – Correct two overstated claims (passive-traffic uniqueness, 'answer fewer than half') to measured statements. Authored by Claude karel.kubicek.claude | privacy:cookie_syncing [2026/08/26 19:10] (current) – Match the prose percentages to the table's own formatting so the shared number guard passes over the corpus section. Authored by Claude karel.kubicek.claude |
|---|
| **Cookie syncing** (also //cookie matching//, //ID syncing//, //user matching//) is the mechanism by which two parties that each hold their own identifier for the same browser learn that the two identifiers belong to the same person. The same-origin policy stops ''tracker.com'' from reading ''advertiser.com'''s cookie, so instead ''tracker.com'' sends the browser to ''advertiser.com'' with its own identifier in the URL — a redirect, an image, an iframe — and both sides write the pair into a match table. Everything afterwards happens server to server, invisibly. | **Cookie syncing** (also //cookie matching//, //ID syncing//, //user matching//) is the mechanism by which two parties that each hold their own identifier for the same browser learn that the two identifiers belong to the same person. The same-origin policy stops ''tracker.com'' from reading ''advertiser.com'''s cookie, so instead ''tracker.com'' sends the browser to ''advertiser.com'' with its own identifier in the URL — a redirect, an image, an iframe — and both sides write the pair into a match table. Everything afterwards happens server to server, invisibly. |
| |
| **This page is about detecting that exchange from a measurement, not about the ad-tech business it serves.** It is the mechanism that turns per-domain identifiers into a joinable graph, and it is the reason a per-party site-prevalence figure understates what that party can see. It is also, from the crawler's side, one of the few tracking behaviours that is **only** visible if you got the crawl configuration right: run stateless, or in a browser that blocks third-party cookies, and you will measure approximately zero and conclude that the phenomenon is gone. | **This page is about detecting that exchange from a measurement, not about the ad-tech business it serves.** It is the mechanism that turns per-domain identifiers into a joinable graph, and it is the reason a per-party site-prevalence figure understates what that party can see. It is also, from the crawler's side, the tracking behaviour most sensitive to how the crawl was set up. Run a Safari- or Firefox-default browser and you measure near-zero third-party syncing **by construction**, not because it stopped. Run stateless and you see only //first-contact// syncing and none of the accumulated graph — a real measurement, but of a different thing. |
| |
| <WRAP important> | <WRAP important> |
| **The load-bearing decision on this page is not "which detector" — it is "which string counts as an identifier".** Every family of method below, including the graph and machine-learning ones, ultimately asks whether a value that came out of client-side storage reappeared in a request to a different party. That question is answered by a heuristic with thresholds, those thresholds have changed materially since 2014, and **the error they introduce has now been measured**: Calzavara et al. {[calzavara2026_syntactic]} (PoPETs 2026) estimate that **16%–19% of the tracking requests exposed by classic syntactic matching are false positives**, rising to **27% for requests that only syntactic matching finds**, and that syntactic matching **misses about 17%** of the tracking requests that JavaScript taint tracking sees. A decade earlier Bashir et al. {[bashir2016tracing]} showed the false-negative side independently: the string heuristics of the day missed **31% of the ad-exchange pairs** that were demonstrably sharing data. So do not report a syncing prevalence without reporting the identifier heuristic and its thresholds — and see [[#The identifier heuristic is the measurement]] for what to use in 2026 rather than what 2016 used. | **The load-bearing decision on this page is not "which detector" — it is "which string counts as an identifier".** Every family of method below, including the graph and machine-learning ones, ultimately asks whether a value that came out of client-side storage reappeared in a request to a different party. That question is answered by a heuristic with thresholds, those thresholds have changed materially since 2014, and **the error they introduce has now been measured**: Calzavara et al. {[calzavara2026_syntactic]} (PoPETs 2026) estimate that **16%–19% of the tracking requests exposed by classic syntactic matching are false positives**, rising to **27%–30% for requests that only syntactic matching finds**, and that syntactic matching **misses 7,021 requests that JavaScript taint tracking finds** — 17% of the two methods' union, and about 30% of what taint tracking sees on its own. A decade earlier Bashir et al. {[bashir2016tracing]} showed the false-negative side independently: the string heuristics of the day missed **31% of the ad-exchange //partners//** that were demonstrably sharing data. (Partners, not pairs: the same paper finds that some pairs are detectable in one direction and not the other.) So do not report a syncing prevalence without reporting the identifier heuristic and its thresholds — and see [[#The identifier heuristic is the measurement]] for what to use in 2026 rather than what 2016 used. |
| </WRAP> | </WRAP> |
| |
| |
| * **Online Tracking: A 1-million-site Measurement and Analysis** {[englehardt2016online]}, CCS 2016 — the reference implementation. Section 4 states the ID-cookie criteria that most later work either copies or explicitly modifies, Section 5.6 measures syncing, and Section 3 explains why the crawl has to be stateful. Its tool, [[Programming:Crawler:OpenWPM|OpenWPM]], is still the default instrument. | * **Online Tracking: A 1-million-site Measurement and Analysis** {[englehardt2016online]}, CCS 2016 — the reference implementation. Section 4 states the ID-cookie criteria that most later work either copies or explicitly modifies, Section 5.6 measures syncing, and Section 3 explains why the crawl has to be stateful. Its tool, [[Programming:Crawler:OpenWPM|OpenWPM]], is still the default instrument. |
| * **Cookie Synchronization: Everything You Always Wanted to Know But Were Afraid to Ask** {[papadopoulos2019_csync]}, TheWebConf 2019 — the only paper in this corpus whose whole subject is the phenomenon, and one of only three that measure it on **real users' traffic** rather than on a crawl. Read it for the CONRAD algorithm and for what syncing does to a user over a year, not for a site-level prevalence figure (it does not produce one). | * **Cookie Synchronization: Everything You Always Wanted to Know But Were Afraid to Ask** {[papadopoulos2019_csync]}, TheWebConf 2019 — the only paper in this corpus whose whole subject is the phenomenon, and one of only three that measure it on **real users' traffic** rather than on a crawl. Read it for the CONRAD algorithm — its rule-based detector for identifier sharing in passive traffic, plus a machine-learning fallback for encrypted identifiers — and for what syncing does to a user over a year, not for a site-level prevalence figure (it does not produce one). |
| * **Tracing Information Flows Between Ad Exchanges Using Retargeted Ads** {[bashir2016tracing]}, USENIX Security 2016 — the one paper that does **not** look for identifiers in URLs at all, and therefore the only external check on everything that does. It infers sharing from the semantics of which retargeted ad gets served, which works even when the identifiers are encrypted. | * **Tracing Information Flows Between Ad Exchanges Using Retargeted Ads** {[bashir2016tracing]}, USENIX Security 2016 — the one paper that does **not** look for identifiers in URLs at all, and therefore the only external check on everything that does. It infers sharing from the semantics of which retargeted ad gets served, which works even when the identifiers are encrypted. |
| * **From Syntactic Matching to Taint Tracking and Back** {[calzavara2026_syntactic]}, PoPETs 2026 — the current methodological state of the art on the detection question itself. Read this before you implement anything; it is a systematisation of every identifier heuristic in the literature plus a measurement of what each gets wrong. | * **From Syntactic Matching to Taint Tracking and Back** {[calzavara2026_syntactic]}, PoPETs 2026 — the current methodological state of the art on the detection question itself. Read this before you implement anything; it is a systematisation of every identifier heuristic in the literature plus a measurement of what each gets wrong. |
| | **Syncs per identifier** | 3.51 (No Action) / 3.91 (Reject All) / 4.86 (Accept All) third parties learn a given third-party ID {[papadogiannakis2021_user]} | The same 27,180 sites | | | **Syncs per identifier** | 3.51 (No Action) / 3.91 (Reject All) / 4.86 (Accept All) third parties learn a given third-party ID {[papadogiannakis2021_user]} | The same 27,180 sites | |
| | **Users exposed** | 97% of regular web users, median user ID leaked to 3.5 domains, tracking domains up by a factor of **6.75** {[papadopoulos2019_csync]} | **850 real mobile users**, one year of passive traffic — not a crawl and not a site sample | | | **Users exposed** | 97% of regular web users, median user ID leaked to 3.5 domains, tracking domains up by a factor of **6.75** {[papadopoulos2019_csync]} | **850 real mobile users**, one year of passive traffic — not a crawl and not a site sample | |
| | **Request chains** | more than half of request chains participated in cookie syncing in most crawl configurations {[iqbal2022_khaleesi]} | Request chains, not sites, in the paper's own crawls | | | **Request chains** | more than half of request chains participated in cookie syncing in most crawl configurations {[iqbal2022_khaleesi]} | Request chains, not sites: chains observed in the paper's own crawls of a top list under several cookie-blocking configurations | |
| | **Sites in one vertical** | 2,867 porn sites, covering 58% of the top-100 most popular ones {[vallina2019_porn]} | A vertical-specific population, not a general top-list | | | **Sites in one vertical** | 2,867 porn sites, covering 58% of the top-100 most popular ones {[vallina2019_porn]} | A vertical-specific population, not a general top-list | |
| | **Cookies** | 76 of 2,545 unique "intractable" cookies (3%) were synchronised at least once {[rasaii2025_crumbs]} | Cookies that survived a reject-all interaction, not sites | | | **Cookies** | 76 of 2,545 unique "intractable" cookies (3%) were synchronised at least once {[rasaii2025_crumbs]} | //Intractable// cookies from one crawl run: set on a site where the banner was accepted, then sent by a **different** site to the tracker before that site's own banner was touched. Cookies, not sites, and a population defined by an interaction sequence | |
| | **Domain pairs / organisations** | 1,190 second-level domains involved, 44% of them advertising-or-tracking {[weerasekara2025_webviews]} | Mobile WebView traffic, not desktop web | | | **Domain pairs / organisations** | 1,190 second-level domains involved, 44% of them advertising-or-tracking {[weerasekara2025_webviews]} | Mobile WebView traffic, not desktop web | |
| |
| **Two consequences.** First, "X% of sites do cookie syncing" is meaningless without the crawl's statefulness, consent action, and vantage — the same population moves by six percentage points across the three consent actions in {[papadogiannakis2021_user]} alone. Second, the **directional** unit (A sent its ID to B) and the **pair** unit (A and B are synced) differ by roughly a factor of two, and papers are not consistent about which they report; {[englehardt2016online]} says explicitly that its count "includes both events where it is a referer and where it is a receiver". | **Two consequences.** First, "X% of sites do cookie syncing" is meaningless without the crawl's statefulness, consent action, and vantage — the same population moves by 5.6 percentage points across the three consent actions in {[papadogiannakis2021_user]} alone. Second, the **directional** unit (A sent its ID to B) and the **pair** unit (A and B are synced) differ by roughly a factor of two, and papers are not consistent about which they report; {[englehardt2016online]} says explicitly that its count "includes both events where it is a referer and where it is a receiver". |
| |
| ===== Methods, and Which Ones Are Current ===== | ===== Methods, and Which Ones Are Current ===== |
| |
| <WRAP important> | <WRAP important> |
| A ranking of what the literature //did// is a fact about the literature, not advice about what to do now. Statuses are as of **2026-08-26** and were checked against material outside the [[Literature:Corpus|publication corpus]] as well, because the corpus's 2025–2026 venue-years are provisional. | A ranking of what the literature //did// is a fact about the literature, not advice about what to do now. Statuses are as of **2026-08-26**. Each //superseded// judgement below rests on a named, dated source that supersedes the thing it retires, not on a corpus count, and the browser and vendor landscape was checked against vendor documentation — see [[provenance:privacy:cookie_syncing]]. The //current// labels also rest on judgement about the corpus's 2025–2026 venue-years, which are provisional, so read them as arguments rather than as measurements. |
| </WRAP> | </WRAP> |
| |
| Twenty-nine papers in the corpus measure identifier sharing between parties (see [[#Use in Publications]] for how that set was built). They fall into six families. | Thirty papers in the corpus measure identifier sharing between parties (see [[#Use in Publications]] for how that set was built). Twenty-nine of them field their own detector, in six families; the thirtieth reuses another paper's syncing labels rather than detecting anything, and is the last row. |
| |
| ^ Family ^ What it does ^ First / most recent in corpus ^ Papers ^ Status in 2026 ^ | ^ Family ^ What it does ^ First / most recent in corpus ^ Papers ^ Status in 2026 ^ |
| | **Syntactic matching** | Collect client-side storage, decide which values are identifiers, then look for those values (and their encodings) in URLs, paths, referrers and POST bodies going to another party | 2014 → 2025 | 14 — e.g. {[acar2014_never]}, {[englehardt2016online]}, {[fouad2020_missed]}, {[ditizio2021_calculus]}, {[randall2022_uidsmuggling]} | **Still the default, and now the best-characterised.** Cheap, works on any HTTP log, no browser modification. Its error is no longer unknown: 16%–19% false positives, ~17% false negatives {[calzavara2026_syntactic]}. Use it, but use the 2026 refinements below, not the 2016 thresholds | | | **Syntactic matching** | Collect client-side storage, decide which values are identifiers, then look for those values (and their encodings) in URLs, paths, referrers and POST bodies going to another party | 2014 → 2026 | 15 — e.g. {[acar2014_never]}, {[englehardt2016online]}, {[fouad2020_missed]}, {[ditizio2021_calculus]}, {[randall2022_uidsmuggling]} | **Still the default, and now the best-characterised.** Cheap, works on any HTTP log, no browser modification. Its error is no longer unknown: **16%–19% of its own detections are false positives**, and it misses about 7,000 requests that taint tracking finds — 17% of the union of the two {[calzavara2026_syntactic]}. The two rates have different denominators and are not two halves of one figure. Use it, but use the 2026 refinements below, not the 2016 thresholds | |
| | **Request-chain / redirect-chain analysis** | Reason about the //sequence// of requests rather than any single one: who redirected to whom, with what carried along | 2022 → 2023 | 4 — {[sanchezrola2021_journey]}, {[musa2022_atom]}, {[iqbal2022_khaleesi]}, {[iqbal2023_tracking]} | **Current, and the right frame for what syncing became.** Chains also capture bounce tracking and link decoration, which pure value-matching misses. {[iqbal2022_khaleesi]} is the reference; it also releases a classifier | | | **Request-chain / redirect-chain analysis** | Reason about the //sequence// of requests rather than any single one: who redirected to whom, with what carried along | 2022 → 2023 | 4 — {[sanchezrola2021_journey]}, {[musa2022_atom]}, {[iqbal2022_khaleesi]}, {[iqbal2023_tracking]} | **Current, and the right frame for what syncing became.** Chains also capture bounce tracking and link decoration, which pure value-matching misses. {[iqbal2022_khaleesi]} is the reference; it also releases a classifier | |
| | **Graph + machine learning** | Build a graph of the page load (requests, scripts, storage, DOM) and learn which nodes are advertising-or-tracking | 2022 → 2024 | 3 — {[siby2022_webgraph]}, {[shaoor2023cookiegraph]}, {[shaoor2024purl]} | **Current for //blocking//, indirect for //measuring syncing//.** {[siby2022_webgraph]}, {[shaoor2023cookiegraph]} and {[shaoor2024purl]} detect the tracking behaviour that syncing is part of, and PURL's decoration graph is the closest thing to a purpose-built successor detector. But they are trained on filter-list labels, so they inherit those labels' blind spots — see [[Privacy:Requests#Ground truth, and the circularity]] | | | **Graph + machine learning** | Build a graph of the page load (requests, scripts, storage, DOM) and learn which nodes are advertising-or-tracking | 2022 → 2024 | 3 — {[siby2022_webgraph]}, {[shaoor2023cookiegraph]}, {[shaoor2024purl]} | **Current for //blocking//, indirect for //measuring syncing//.** {[siby2022_webgraph]}, {[shaoor2023cookiegraph]} and {[shaoor2024purl]} detect the tracking behaviour that syncing is part of, and PURL's decoration graph is the closest thing to a purpose-built successor detector. But they are trained on filter-list labels, so they inherit those labels' blind spots — see [[Privacy:Requests#Ground truth, and the circularity]] | |
| | **Ad-semantics inference** | Ignore the wire format; infer that two exchanges shared data because a retargeted ad, or a bid, could not otherwise have been served | 2016 → 2022 | 3 — {[bashir2016tracing]}, {[cook2020_headerbidding]}, {[oh2022_cartology]} | **Underused and still the only independent check.** It is the only family that sees server-to-server sharing and encrypted identifiers. Expensive: {[bashir2016tracing]} trained 90 personas and collected 35,448 inclusion chains; {[cook2020_headerbidding]} needs header-bidding bid streams. Nobody has repeated it since 2022 — see [[#Open Questions]] | | | **Ad-semantics inference** | Ignore the wire format; infer that two exchanges shared data because a retargeted ad, or a bid, could not otherwise have been served | 2016 → 2022 | 3 — {[bashir2016tracing]}, {[cook2020_headerbidding]}, {[oh2022_cartology]} | **Underused and still the only independent check.** It is the only family that sees server-to-server sharing and encrypted identifiers. Expensive: {[bashir2016tracing]} trained 90 personas and collected 35,448 inclusion chains; {[cook2020_headerbidding]} needs header-bidding bid streams. No paper in these venues has repeated it since 2022 — see [[#Open Questions]] | |
| | **Passive traffic analysis** | Apply the same identifier logic to real users' HTTP logs instead of a crawl | 2017 → 2019 | 3 — incl. {[papadopoulos2018_cost]}, {[papadopoulos2019_csync]} | **Historical in these venues, for access reasons, not methodological ones.** It answers questions a crawl cannot ("how many users are affected, how fast"), and no paper in this corpus has done it since 2019 | | | **Passive traffic analysis** | Apply the same identifier logic to real users' HTTP logs instead of a crawl | 2017 → 2019 | 3 — incl. {[papadopoulos2018_cost]}, {[papadopoulos2019_csync]} | **Historical in these venues, for access reasons, not methodological ones.** It answers questions a crawl cannot ("how many users are affected, how fast"), and no paper in this corpus has done it since 2019 | |
| | **JavaScript taint tracking** | Instrument the engine so a value read from ''document.cookie'' or ''localStorage'' carries a taint into every derived string, and report when a tainted string reaches the network | 2026 → 2026 | 1 — {[calzavara2026_syntactic]} | **Newly evaluated, and explicitly //not// a drop-in replacement.** {[calzavara2026_syntactic]} finds Foxhound-based taint tracking has far fewer false positives (4%–7%) but misses **43%** of what syntactic matching finds, because taint propagation is limited to string operations and does not model the full JavaScript semantics. The paper's conclusion is to run both | | | **JavaScript taint tracking** | Instrument the engine so a value read from ''document.cookie'' or ''localStorage'' carries a taint into every derived string, and report when a tainted string reaches the network | 2026 → 2026 | 1 — {[calzavara2026_syntactic]} | **Newly evaluated, and explicitly //not// a drop-in replacement.** {[calzavara2026_syntactic]} finds Foxhound-based taint tracking has far fewer false positives (4%–7%) but misses a great deal: **17,496 requests, 43% of the 40,605-request union and 52% of the 33,584 that syntactic matching finds**, are exposed by syntactic matching alone. Taint propagation is limited to string operations and does not model the full JavaScript semantics. The paper's conclusion is to run both | |
| | | **(Reuses another paper's labels)** | Takes an existing published list of syncing domains and asks a question of it, rather than detecting syncing | 2021 → 2021 | 1 — {[iqbal2021_fingerprinting]} | Not a detection method, and listed only so the seven rows sum to 30. It is nonetheless the cheapest way to get a syncing variable into a study about something else: {[iqbal2021_fingerprinting]} uses {[fouad2020_missed]}'s list to find that **17.28% of fingerprinting vendors also participate in cookie syncing** | |
| |
| ==== What is genuinely superseded ==== | ==== What is genuinely superseded ==== |
| * **Two synchronised profiles as the way to tell an identifier from a constant.** The classic design runs two machines and keeps values that differ between them {[englehardt2016online]}. {[randall2022_uidsmuggling]} shows this discards a large number of genuine identifiers — those that appear on only one crawler, and those that cannot be distinguished from session IDs — and uses **four** crawlers instead: three different user profiles plus one that repeats the first profile's visit, so a value can be tested for "varies across users" and "stable for the same user" separately. If you can afford four browsers, run four. | * **Two synchronised profiles as the way to tell an identifier from a constant.** The classic design runs two machines and keeps values that differ between them {[englehardt2016online]}. {[randall2022_uidsmuggling]} shows this discards a large number of genuine identifiers — those that appear on only one crawler, and those that cannot be distinguished from session IDs — and uses **four** crawlers instead: three different user profiles plus one that repeats the first profile's visit, so a value can be tested for "varies across users" and "stable for the same user" separately. If you can afford four browsers, run four. |
| * **Assuming the identifier travels in plaintext.** DoubleClick was already encrypting synced identifiers by 2016 {[bashir2016tracing]}, and {[papadopoulos2019_csync]} added a machine-learning "cookie-less" detector for exactly this reason. Plaintext-only matching is a lower bound and should be labelled as one. | * **Assuming the identifier travels in plaintext.** DoubleClick was already encrypting synced identifiers by 2016 {[bashir2016tracing]}, and {[papadopoulos2019_csync]} added a machine-learning "cookie-less" detector for exactly this reason. Plaintext-only matching is a lower bound and should be labelled as one. |
| * **"Third-party cookies are about to disappear, so this is about to stop mattering."** They are not. Google announced on **2025-04-22** that it would keep third-party-cookie choice in Chrome and not ship the planned prompt,((Anthony Chavez, "Next steps for Privacy Sandbox and tracking protections in Chrome", ''privacysandbox.google.com/blog/privacy-sandbox-next-steps'', 2025-04-22: "we've made the decision to maintain our current approach to offering users third-party cookie choice in Chrome, and will not be rolling out a new standalone prompt for third-party cookies." Fetched 2026-08-26.)) and on **2025-10-17** it announced the retirement of ten Privacy Sandbox technologies — Attribution Reporting, Topics, Protected Audience, Private Aggregation including Shared Storage, Related Website Sets, SelectURL, IP Protection, On-Device Personalization, Protected App Signals and SDK Runtime — while stating that "Chrome will maintain our current approach to offering users third-party cookie choice in Chrome".((''privacysandbox.google.com/blog/update-on-plans-for-privacy-sandbox-technologies'', 2025-10-17. Fetched 2026-08-26.)) The framing to avoid is "post-cookie"; the framing that holds is "Chrome keeps them, Safari and Firefox do not" — which makes syncing a **browser-conditional** phenomenon, not a disappearing one. | * **"Third-party cookies are about to disappear, so this is about to stop mattering."** They are not. Google announced on **2025-04-22** that it would keep third-party-cookie choice in Chrome and not ship the planned prompt,((Anthony Chavez, "Next steps for Privacy Sandbox and tracking protections in Chrome", ''privacysandbox.google.com/blog/privacy-sandbox-next-steps'', 2025-04-22: "we've made the decision to maintain our current approach to offering users third-party cookie choice in Chrome, and will not be rolling out a new standalone prompt for third-party cookies." Fetched 2026-08-26.)) and on **2025-10-17** it announced the retirement of ten Privacy Sandbox technologies, among them Attribution Reporting, Topics and Protected Audience, while stating that "Chrome will maintain our current approach to offering users third-party cookie choice in Chrome".((''privacysandbox.google.com/blog/update-on-plans-for-privacy-sandbox-technologies'', 2025-10-17, fetched 2026-08-26. The full list, verbatim: "Attribution Reporting API (Chrome and Android), IP Protection, On-Device Personalization, Private Aggregation (including Shared Storage), Protected Audience (Chrome and Android), Protected App Signals, Related Website Sets (including requestStorageAccessFor and Related Website Partition), SelectURL, SDK Runtime and Topics (Chrome and Android).")) The framing to avoid is "post-cookie"; the framing that holds is "Chrome keeps them, Safari and Firefox do not" — which makes syncing a **browser-conditional** phenomenon, not a disappearing one. Note that the retirement is a live process rather than a completed one, and that Google's blog posts give no Chrome milestone for it while Chrome's own engineering channel does: as of 2026-08-26 the Privacy Sandbox feature-status page lists Protected Audience, Topics, Attribution Reporting, Private Aggregation, Shared Storage and Related Website Sets as "Intent to deprecate and remove filed", and the Chrome Platform Status entry for Protected Audience gives a removal milestone of **Chrome 153** with status "Proposed".((''privacysandbox.google.com/overview/status'' and ''chromestatus.com/api/v0/features/6552486106234880'', both fetched 2026-08-26. If you need a date rather than a milestone, read Chrome Platform Status, not the blog.)) |
| |
| ==== What the corpus cannot tell you ==== | ==== What the corpus cannot tell you ==== |
| | Roesner et al. {[roesner2012_detecting]} | 2012 | > session | no | — | — | unique across unrelated visits | | | Roesner et al. {[roesner2012_detecting]} | 2012 | > session | no | — | — | unique across unrelated visits | |
| | Acar et al. {[acar2014_never]} | 2014 | > 30 days | yes | — | RO < 33% | same across related visits; same length across unrelated visits | | | Acar et al. {[acar2014_never]} | 2014 | > 30 days | yes | — | RO < 33% | same across related visits; same length across unrelated visits | |
| | Englehardt et al. {[englehardt2015_cookies]} | 2015 | > 90 days | no | — | RO < 55% | same across related visits; same length across unrelated visits | | | Englehardt et al. {[englehardt2015_cookies]} | 2015 | > 90 days | no | — | RO < 55% | same across related visits; same length across unrelated visits; unique across unrelated visits | |
| | Englehardt & Narayanan {[englehardt2016online]} | 2016 | > 90 days | yes | 8–100 | RO < 66% | same across related visits; unique across unrelated visits | | | Englehardt & Narayanan {[englehardt2016online]} | 2016 | > 90 days | yes | 8–100 | RO < 66% | same across related visits; unique across unrelated visits | |
| | Papadopoulos et al. {[papadopoulos2019_csync]} | 2019 | > session | yes | ≥ 10 | — | — | | | Papadopoulos et al. {[papadopoulos2019_csync]} | 2019 | > session | yes | ≥ 10((The source table says ≥ 10; the original paper says strictly greater — "strings with specific length (> 10 characters)". The difference is one character and is the source table's, not this page's.)) | — | — | |
| | Sánchez-Rola et al. {[sanchezrola2019can]} | 2019 | — | no | — | guesses ≥ 10^9 | — | | | Sánchez-Rola et al. {[sanchezrola2019can]} | 2019 | — | no | — | guesses ≥ 10^9 | — | |
| | Fouad et al. {[fouad2020_missed]} | 2020 | — | yes | — | — | — | | | Fouad et al. {[fouad2020_missed]} | 2020 | — | yes | — | — | — | |
| | Chen et al. {[chen2021_cookieswap]} | 2021 | > session | no | ≥ 8 | RO < 66% | length after URL-decoding; RO after removing timestamps and common subsequences > 2 | | | Chen et al. {[chen2021_cookieswap]} | 2021 | > session | no | ≥ 8 | RO < 66% | length after URL-decoding; RO after removing timestamps and common subsequences > 2 | |
| | Sánchez-Rola et al. {[sanchezrola2021_journey]} | 2022 | — | no | — | guesses ≥ 10^9 | — | | | Sánchez-Rola et al. {[sanchezrola2021_journey]} | 2022((Dated by conference: it appeared at the 43rd IEEE S&P, May 2022, and the corpus files it under 2022. The PDF's own running header and copyright line read 2021, and this site's bibliography entry follows the IEEE Xplore record in saying 2021, so the reference list below will show a different year from this cell.)) | — | no | — | guesses ≥ 10^9 | — | |
| | Nikkhah Bahrami et al. {[bahrami2025_cookieguard]} | 2025 | — | yes | ≥ 8 | — | — | | | Nikkhah Bahrami et al. {[bahrami2025_cookieguard]} | 2025 | — | yes | ≥ 8 | — | — | |
| | Calzavara et al. {[calzavara2026_syntactic]} | 2026 | > session | yes | ≥ 8 | RO < 66% **and** guesses ≥ 10^9 | length after URL-decoding; RO after removing timestamps and common subsequences > 2 | | | Calzavara et al. {[calzavara2026_syntactic]} | 2026 | > session | no((The //Parse// column of the source table is blank for its own row, which is what this cell reports. The paper's §3.3 nonetheless describes slicing on non-alphanumeric characters as one of its supported transformations, so the blank looks like an omission in the printed table rather than a design choice. Checked against the PDF's word coordinates, not the text layer, because the column is marked only by a tick glyph.)) | ≥ 8 | RO < 66% **and** guesses ≥ 10^9 | length after URL-decoding; RO after removing timestamps and common subsequences > 2 | |
| |
| The paper's own summary of that table is the sentence to quote in your related-work section: **"there is no consensus on the most effective heuristic due to the absence of a solid ground truth."** | The paper's own summary of that table is the sentence to quote in your related-work section: **"there is no consensus on the most effective heuristic due to the absence of a solid ground truth."** |
| - **Match after decoding, not only after encoding.** Most prior work generated encoded forms of the identifier (Base64, MD5, SHA-1, SHA-256) and looked for those. That misses the case where the identifier is inside a structure that is then encoded — ''base64('{"uid": 1234}')'' contains no encoding of ''1234''. Parse and decode the //request// too, up to a bounded depth (three layers is the convention). | - **Match after decoding, not only after encoding.** Most prior work generated encoded forms of the identifier (Base64, MD5, SHA-1, SHA-256) and looked for those. That misses the case where the identifier is inside a structure that is then encoded — ''base64('{"uid": 1234}')'' contains no encoding of ''1234''. Parse and decode the //request// too, up to a bounded depth (three layers is the convention). |
| - **Confirm each match with a canary.** Their validation technique is cheap and reusable: overwrite the storage value with a distinctive canary, revisit the page, and check whether the matching request now carries the canary. If it does, the flow is real; if the request still carries the original value, the match was spurious. Applying this filter removed **24% of tracking requests and 36% of distinct trackers** from their own results, and manual inspection confirmed the removed ones were not tracking. | - **Confirm each match with a canary.** Their validation technique is cheap and reusable: overwrite the storage value with a distinctive canary, revisit the page, and check whether the matching request now carries the canary. If it does, the flow is real; if the request still carries the original value, the match was spurious. Applying this filter removed **24% of tracking requests and 36% of distinct trackers** from their own results, and manual inspection confirmed the removed ones were not tracking. |
| - **If you can run both matching and taint tracking, do.** The two disagree on 60% of the union: 17,496 requests (43% of 40,605) found by syntactic matching alone, 7,021 (17%) by taint tracking alone. Neither is a superset. | - **If you can run both matching and taint tracking, do.** The two disagree on 60% of the union of 40,605 requests: 17,496 (43% of the union, 52% of syntactic matching's own 33,584) found by syntactic matching alone, 7,021 (17% of the union) by taint tracking alone. Neither is a superset. |
| |
| ===== Crawl Configuration That Decides Whether You See It At All ===== | ===== Crawl Configuration That Decides Whether You See It At All ===== |
| Syncing is the tracking behaviour most sensitive to crawler setup. Get any of these wrong and the measurement floor, not the phenomenon, is what you report. | Syncing is the tracking behaviour most sensitive to crawler setup. Get any of these wrong and the measurement floor, not the phenomenon, is what you report. |
| |
| * **Stateful, and with a seed profile.** {[englehardt2016online]} is explicit: for cookie syncing, statefulness "is essential", because the sync graph of an accumulated identity is what you are trying to reconstruct. They also solve the parallelism problem in a way worth copying — build one seed profile by visiting the top 10,000 sites serially, then load that profile into every parallel browser instance. Their measured justification: such a profile "will have communicated with 76% of all third-party domains present on more than 5 of the top 100,000 sites". The residual bias is stated too: third parties absent from the seed hand out a different identifier in each parallel instance and so appear to sync with themselves — and **nobody has measured how large that inflation is**, which is the open question on [[Programming:Stateful stateless#Statefulness does not scale, and the standard workaround has a known artefact|the statefulness page]]. | * **Stateful, and with a seed profile.** {[englehardt2016online]} is explicit: for cookie syncing, statefulness "is essential", because the sync graph of an accumulated identity is what you are trying to reconstruct. They also solve the parallelism problem in a way worth copying — build one seed profile by visiting the top 10,000 sites serially, then load that profile into every parallel browser instance. Their measured justification: such a profile "will have communicated with 76% of all third-party domains present on more than 5 of the top 100,000 sites". The residual bias is stated too: third parties absent from the seed hand out a different identifier in each parallel instance and so appear to sync with themselves — and **no paper in these venues has measured how large that inflation is**, which is the open question on [[Programming:Stateful stateless#Statefulness does not scale, and the standard workaround has a known artefact|the statefulness page]]. |
| * **But "stateful sees more" is not a law.** Zeber et al. {[zeber2020representativeness]} give the mechanism for the opposite: "cookie syncing is not necessary for users who have already had their cookies synced, whereas a stateless crawler browser instance with a fresh profile would be a clear target for cookie syncing". A fresh profile over-triggers //first-contact// syncing; an aged profile is what you need for the //graph//. Decide which of the two you are measuring and say so — the full comparison is on [[Programming:Stateful stateless#What each design can and cannot measure|the statefulness page]]. That six of the corpus's 24 crawling papers ran **both** conditions is the right instinct. | * **But "stateful sees more" is not a law.** Zeber et al. {[zeber2020representativeness]} give the mechanism for the opposite: "cookie syncing is not necessary for users who have already had their cookies synced, whereas a stateless crawler browser instance with a fresh profile would be a clear target for cookie syncing". A fresh profile over-triggers //first-contact// syncing; an aged profile is what you need for the //graph//. Decide which of the two you are measuring and say so — the full comparison is on [[Programming:Stateful stateless#What each design can and cannot measure|the statefulness page]]. That six of the corpus's 25 crawling papers ran **both** conditions is the right instinct. |
| * **The browser decides the answer.** Safari's ITP "by default blocks all third-party cookies. There are no exceptions to this blocking",((''webkit.org/tracking-prevention/'', fetched 2026-08-26.)) and Firefox has partitioned cookies by top-level site for all users since **Firefox 103**.((''developer.mozilla.org/en-US/docs/Web/Privacy/Guides/State_Partitioning'', fetched 2026-08-26: "Dynamic Partitioning: Enabled by default for all users since Firefox 103.")) A default-configured Firefox or Safari crawl measures near-zero third-party syncing **by construction**. If your instrument is OpenWPM on Firefox, check what protections are on before you interpret a low number; {[shaoor2023cookiegraph]} turns Firefox's additional protections off deliberately and says so. Conversely, running with third-party cookies blocked is a legitimate //experimental condition// — {[acar2014_never]} used it and found synced IDs and parties fell "by nearly a factor of two". | * **The browser decides the answer.** Safari's ITP "by default blocks all third-party cookies. There are no exceptions to this blocking",((''webkit.org/tracking-prevention/'', fetched 2026-08-26.)) and Firefox has partitioned cookies by top-level site for all users since **Firefox 103**.((''developer.mozilla.org/en-US/docs/Web/Privacy/Guides/State_Partitioning'', fetched 2026-08-26: "Dynamic Partitioning: Enabled by default for all users since Firefox 103.")) A default-configured Firefox or Safari crawl measures near-zero third-party syncing **by construction**. If your instrument is OpenWPM on Firefox, check what protections are on before you interpret a low number; {[shaoor2023cookiegraph]} turns Firefox's additional protections off deliberately and says so. Conversely, running with third-party cookies blocked is a legitimate //experimental condition// — {[acar2014_never]} used it and found synced IDs and parties fell "by nearly a factor of two". |
| * **Consent action changes the number, and not in the direction you expect.** {[papadogiannakis2021_user]}: sites carrying third-party ID synchronisation went **24.03% → 26.20% → 29.61%** for No Action → Reject All → Accept All, and syncs per third-party ID **3.51 → 3.91 → 4.86**. Rejecting produced //more// syncing than not interacting at all. Record the consent action, and prefer measuring more than one. See [[Privacy:Consent]] and [[Programming:Interaction]]. | * **Consent action changes the number, and not in the direction you expect.** {[papadogiannakis2021_user]}: sites carrying third-party ID synchronisation went **24.03% → 26.20% → 29.61%** for No Action → Reject All → Accept All, and syncs per third-party ID **3.51 → 3.91 → 4.86**. Rejecting produced //more// syncing than not interacting at all. Record the consent action, and prefer measuring more than one. See [[Privacy:Consent]] and [[Programming:Interaction]]. |
| * **Interaction depth and timing.** Syncing is triggered by the ad stack, which runs after the auction. Prebid.js — the dominant open-source header-bidding wrapper — documents its user-sync defaults as **''syncDelay'' 3000 ms after the auction ends**, **''syncsPerBidder'' 5**, image syncs enabled and **iframe syncs disabled by default**.((''docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html'', fetched 2026-08-26.)) A crawler that closes the page 3 seconds after ''load'' can miss the syncs entirely, and any per-adapter count is capped at 5 by the publisher's own configuration rather than by the adapter's appetite. In the corpus's measuring set, **10 of the 24 that crawled visited the landing page only**. | * **Interaction depth and timing.** Syncing is triggered by the ad stack, which runs after the auction. Prebid.js — the dominant open-source header-bidding wrapper — documents its user-sync defaults as **''syncDelay'' 3000 ms after the auction ends**, **''syncsPerBidder'' 5**, image syncs enabled and **iframe syncs disabled by default**.((''docs.prebid.org/dev-docs/publisher-api-reference/setConfig.html'', fetched 2026-08-26.)) A crawler that closes the page 3 seconds after ''load'' can miss the syncs entirely, and any per-adapter count is capped at 5 by the publisher's own configuration rather than by the adapter's appetite. In the corpus's measuring set, **11 of the 25 that crawled visited the landing page only**. |
| * **Vantage.** Which exchanges bid, and therefore which sync, depends on where the browser appears to be, and EU vantage points additionally bring a consent banner into the path. Of the 29 measuring papers, **18 state any vantage location at all**; the United States accounts for 12 of those. | * **Vantage.** Which exchanges bid, and therefore which sync, depends on where the browser appears to be, and EU vantage points additionally bring a consent banner into the path. Of the 30 measuring papers, **19 state any vantage location at all**; the United States accounts for 13 of those. |
| * **Logging.** You need request URLs //and// referrers //and// POST bodies, plus ''Set-Cookie'' and the resulting cookie jar, plus redirect chains with their initiators. HAR alone is usually not enough — see [[Programming:Traffic files]]. | * **Logging.** You need request URLs //and// referrers //and// POST bodies, plus ''Set-Cookie'' and the resulting cookie jar, plus redirect chains with their initiators. HAR alone is usually not enough — see [[Programming:Traffic files]]. |
| |
| Third-party-cookie syncing is a Chrome-and-blocklist-permitting behaviour. Everywhere it is blocked, the same function is served by mechanisms that a syncing detector will not see, and these are where the measurable action is now. | Third-party-cookie syncing is a Chrome-and-blocklist-permitting behaviour. Everywhere it is blocked, the same function is served by mechanisms that a syncing detector will not see, and these are where the measurable action is now. |
| |
| * **Link decoration and UID smuggling.** The identifier moves into the URL of a top-level navigation, so no third-party cookie is needed. {[randall2022_uidsmuggling]} measures it directly: **8.11% of 10,814 unique URL paths** carried a smuggled UID, versus **2.7%** of navigation paths that were pure bounce tracking, and it identifies **27 "dedicated smugglers"**. {[shaoor2024purl]} finds tracking link decorations on **73.02%** of tested sites, averaging **10.75** per site. Detection, tooling and the parameter-list landscape are on [[Privacy:Requests#Link Decoration and Tracking Parameters]] — do not re-derive them here. | * **Link decoration and UID smuggling.** The identifier moves into the URL of a top-level navigation, so no third-party cookie is needed. {[randall2022_uidsmuggling]} measures it directly: UID smuggling on **8.11% of the unique URL paths** its crawler took (Table 2 puts that population at 10,814), against **2.7% of the navigation paths** that were bounce tracking without a UID transfer, and it names **27 "dedicated smugglers"** — redirectors with no purpose in the path except carrying an identifier.((The paper's Table 2 also reports 850 unique URL paths with UID smuggling, which is 7.86% of 10,814 rather than 8.11%. The two figures are not reconciled in the paper; the page quotes the stated percentage and gives the table count so a reader can see the gap.)) {[shaoor2024purl]} finds tracking link decorations on **73.02%** of tested sites, averaging **10.75** per site. The 2026 entry in this line is {[dao2026_gclid]}, which follows one specific click identifier: **all 568 YouTube ad interactions it observed carried a ''gclid'' in a URL path**, **64 of 76 advertisers stored it as a first-party cookie** (41 of 74 even after the banner was rejected), and **133 distinct third-party domains received ''gclid'' values**. That last figure is the syncing question in link-decoration clothing: an identifier the advertiser did not set, reaching parties that did not set it either. Detection, tooling and the parameter-list landscape are on [[Privacy:Requests#Link Decoration and Tracking Parameters]] — do not re-derive them here. |
| * **Bounce tracking.** A redirect through the tracker's own domain so that its cookie becomes first-party for one hop. WebKit classifies it explicitly: ITP "counts the number of unique such redirects" and "will count it as a bounce even if the redirect is delayed by landing on a webpage and triggering a navigation a couple of seconds later", and it "caps the expiry of cookies created in JavaScript on the landing webpage to 24 hours" when it detects link decoration.((''webkit.org/tracking-prevention/'', fetched 2026-08-26.)) {[iqbal2022_khaleesi]} detects it with a chain heuristic requiring a top-level navigation, third-party cookies and a return navigation. | * **Bounce tracking.** A redirect through the tracker's own domain so that its cookie becomes first-party for one hop. WebKit classifies it explicitly: ITP "counts the number of unique such redirects" and "will count it as a bounce even if the redirect is delayed by landing on a webpage and triggering a navigation a couple of seconds later", and it "caps the expiry of cookies created in JavaScript on the landing webpage to 24 hours" when it detects link decoration.((''webkit.org/tracking-prevention/'', fetched 2026-08-26.)) {[iqbal2022_khaleesi]} detects it with a chain heuristic requiring a top-level navigation, third-party cookies and a return navigation. Chrome ships mitigations for it too, and — importantly for anyone reading the Privacy Sandbox retirement as "Chrome gave up" — they are on the //keep// list: a site that a navigation redirected through, and that the user has not interacted with in 45 days, has its storage deleted, for users who block third-party cookies.((''privacysandbox.google.com/protections/bounce-tracking-mitigations'', fetched 2026-08-26. This is conditional on the user blocking third-party cookies, so it does not fire in a default Chrome crawl.)) |
| * **First-party identifier sharing.** The identifier is set as a first-party cookie — often by a third-party script — and then sent onward. {[fouad2020_missed]} calls this first-to-third-party syncing and finds it on **67.96%** of the domains it visited; {[sanchezrola2021_journey]} names the practice **cookie ghostwriting**, where an entity creates a cookie in another party's name, and measures the resulting graph over 138M cookie-creation events from 6.2M pages on 1M sites. {[shaoor2023cookiegraph]} and {[bahrami2025_cookieguard]} are the detection follow-ups. This is the family most likely to be what you actually need to measure in 2026. | * **First-party identifier sharing.** The identifier is set as a first-party cookie — often by a third-party script — and then sent onward. {[fouad2020_missed]} calls this first-to-third-party syncing and finds it on **67.96%** of the domains it visited; {[sanchezrola2021_journey]} names the practice **cookie ghostwriting**, where an entity creates a cookie in another party's name, and measures the resulting graph over 138M cookie-creation events from 6.2M pages on 1M sites. {[shaoor2023cookiegraph]} and {[bahrami2025_cookieguard]} are the detection follow-ups. This is the family most likely to be what you actually need to measure in 2026. |
| * **Server-side.** If the exchange happens between two servers, no client-side method sees it at all. That is the subject of [[Privacy:Server side tracking]], and it is the reason the ad-semantics family {[bashir2016tracing]} remains the only complete check. | * **Server-side.** If the exchange happens between two servers, no client-side method sees it at all. That is the subject of [[Privacy:Server side tracking]], and it is the reason the ad-semantics family {[bashir2016tracing]} remains the only complete check. |
| | IEEE S&P | 779 | 6 (0.8%) | 2 (0.3%) | | | IEEE S&P | 779 | 6 (0.8%) | 2 (0.3%) | |
| |
| **PoPETs is where this literature lives**, by a factor of two over the next venue and five over CCS. If you are choosing a venue, that is the signal. NDSS has never published a paper in these seven venues that mentions syncing five times. | **PoPETs is where this literature lives.** Its ≥1-mention rate (5.5%) is about twice IMC's, the next venue, and about seven times CCS's; at the ≥5 threshold it holds 9 of the 31 papers. If you are choosing a venue, that is the signal. No NDSS paper in the corpus mentions syncing five times or more, despite NDSS having the fourth-highest ≥1-mention rate in the table. |
| |
| ==== By year ==== | ==== By year ==== |
| |
| Papers mentioning any syncing wording, per year, against that year's corpus size. **2025 is thin at the edges and 2026 is provisional** — CCS 2026 and IMC 2026 have not been held, and IEEE S&P 2026 and TheWebConf 2026 are incompletely selected — so the last two rows are not evidence of decline. | Papers mentioning any syncing wording, per year, against that year's corpus size. **This measures attention in the literature, not how common syncing was in any year** — no row here is a prevalence figure. **2025 is thin at the edges and 2026 is provisional** — CCS 2026 and IMC 2026 have not been held, and IEEE S&P 2026 and TheWebConf 2026 are incompletely selected — so the last two rows are not evidence of decline. |
| |
| ^ Year ^ Corpus papers ^ ≥1 mention ^ ≥5 mentions ^ | ^ Year ^ Corpus papers ^ ≥1 mention ^ ≥5 mentions ^ |
| | 2026 //(provisional)// | 415 | 3 | 0 | | | 2026 //(provisional)// | 415 | 3 | 0 | |
| |
| 2010–2013 produced two mentions in 510 papers and no paper engaging with it. **2022 is the peak year** on both columns, which matches the arrival of the request-chain and graph families. | 2010–2013 produced two mentions in 510 papers and no paper engaging with it. **2022 is the peak year of attention** on both columns, which is also when the request-chain and graph families arrive. That is a coincidence worth noticing, not a cause. |
| |
| ==== The 29 measuring papers ==== | ==== The 30 measuring papers ==== |
| |
| Built by hand from the 43 candidates the automated sweep produced: 29 measure identifier sharing between distinct parties, 5 cite it without measuring it, and 9 use the phrase for something else entirely (a rendering side-channel that "synchronises cookies" across browsers, a ''cookie-match'' predicate in a formal browser model, opt-out cookie name matching, and a redefinition of "cookie syncing" to mean cross-site syncing enabled by a browser bug). **Unlabelled residue: zero** — every candidate carries a hand label. | Built by hand from the 44 candidates the automated sweep produced: 30 measure identifier sharing between distinct parties, 5 cite it without measuring it, and 9 use the phrase for something else entirely (a rendering side-channel that "synchronises cookies" across browsers, a ''cookie-match'' predicate in a formal browser model, opt-out cookie name matching, and a redefinition of "cookie syncing" to mean cross-site syncing enabled by a browser bug). **Unlabelled residue: zero** — every candidate carries a hand label. |
| |
| ^ Detection family ^ Papers ^ Share of 29 ^ | ^ Detection family ^ Papers ^ Share of 30 ^ |
| | Syntactic matching | 14 | 48.3% | | | Syntactic matching | 15 | 50.0% | |
| | Request-chain analysis | 4 | 13.8% | | | Request-chain analysis | 4 | 13.3% | |
| | Ad-semantics inference | 3 | 10.3% | | | Ad-semantics inference | 3 | 10.0% | |
| | Graph + machine learning | 3 | 10.3% | | | Graph + machine learning | 3 | 10.0% | |
| | Passive traffic analysis | 3 | 10.3% | | | Passive traffic analysis | 3 | 10.0% | |
| | JavaScript taint tracking | 1 | 3.4% | | | JavaScript taint tracking | 1 | 3.3% | |
| | Reuses another paper's labels | 1 | 3.4% | | | Reuses another paper's labels | 1 | 3.3% | |
| |
| ==== Crawl configuration of these papers ==== | ==== Crawl configuration of these papers ==== |
| |
| Of the 29, **24 ran an automated crawl** (''crawlConfig'' fired). Sentinels are shown but are never counted as answers. | Of the 30, **25 ran an automated crawl** (''crawlConfig'' fired). Sentinels are shown but are never counted as answers. |
| |
| ^ Field ^ Value ^ Papers ^ Share of 24 ^ | ^ Field ^ Value ^ Papers ^ Share of 25 ^ |
| | ''statefulness'' | stateful | 10 | 41.7% | | | ''statefulness'' | stateful | 10 | 40.0% | |
| | | both stateful and stateless | 6 | 25.0% | | | | both stateful and stateless | 6 | 24.0% | |
| | | stateless | 2 | 8.3% | | | | stateless | 3 | 12.0% | |
| | | //not stated// | 6 | 25.0% | | | | //not stated// | 6 | 24.0% | |
| | ''consentAction'' | no interaction | 9 | 37.5% | | | ''consentAction'' | no interaction | 9 | 36.0% | |
| | | accept **and** reject | 3 | 12.5% | | | | accept **and** reject | 4 | 16.0% | |
| | | //not stated// | 12 | 50.0% | | | | //not stated// | 12 | 48.0% | |
| | ''interactionDepth'' | landing page only | 10 | 41.7% | | | ''interactionDepth'' | landing page only | 11 | 44.0% | |
| | | landing plus subpages | 7 | 29.2% | | | | landing plus subpages | 7 | 28.0% | |
| | | single target page | 4 | 16.7% | | | | single target page | 4 | 16.0% | |
| | | deep crawl | 1 | 4.2% | | | | deep crawl | 1 | 4.0% | |
| | | //not stated// | 2 | 8.3% | | | | //not stated// | 2 | 8.0% | |
| | ''headless'' | headless | 2 | 8.3% | | | ''headless'' | headless | 3 | 12.0% | |
| | | headful | 2 | 8.3% | | | | headful | 2 | 8.0% | |
| | | //not stated// | 20 | 83.3% | | | | //not stated// | 20 | 80.0% | |
| |
| **A quarter of the papers measuring the one behaviour that requires a stateful crawl do not say whether their crawl was stateful**, and half do not say what they did about consent banners. Those are the two fields this page asks you to report. See [[Programming:Stateful stateless]]. | **Just under a quarter of the papers measuring the one behaviour that most needs a stateful crawl do not say whether their crawl was stateful**, and just under half do not say what they did about consent banners. Those are the two fields this page asks you to report. See [[Programming:Stateful stateless]]. |
| | |
| | <WRAP important> |
| | **Read the ''headless'' row as the weakest one in this table, and not only because 80.0% of the papers do not state a value.** The extraction stores **one** evidence quote for the whole ''crawlConfig'' object, so a spot-check can confirm at most one of its fields per paper; of five quotes read by hand for this page, none supported the ''headless'' value and only one supported ''statefulness''. The one ''headless'' value that could be traced is also the ambiguous kind: {[englehardt2016online]} is recorded as headless because the paper describes launching measurement instances in a "headless" container "by using the pyvirtualdisplay library" to drive Xvfb — which is a //headful// browser on a virtual framebuffer, and behaves differently from a genuinely headless one under bot detection. The extraction is faithful to the paper's own word; the paper's own word is loose. If headless-ness matters to your argument, read the papers rather than this row. |
| | </WRAP> |
| |
| ==== Artifacts ==== | ==== Artifacts ==== |
| |
| Of the 29, **12 (41.4%)** state a public artifact and **10 (34.5%)** mention none. What is actually released and reusable: | Of the 30, **13 (43.3%)** state a public artifact and **10 (33.3%)** mention none. What is actually released and reusable: |
| |
| ^ Artifact ^ Paper ^ What you get ^ | ^ Artifact ^ Paper ^ What you get ^ |
| | [[https://github.com/citp/OpenWPM|OpenWPM]] | {[englehardt2016online]} | The crawler, still maintained; the ID-cookie logic has to be re-implemented from the paper | | | [[https://github.com/openwpm/OpenWPM|OpenWPM]] | {[englehardt2016online]} | The crawler, actively maintained (last push 2026-08-25). The ID-cookie logic is //not// in it and has to be re-implemented from the paper. The ''citp/OpenWPM'' URL printed in the paper now redirects here | |
| | [[https://github.com/ucsdsysnet/crumbcruncher|CrumbCruncher]] | {[randall2022_uidsmuggling]} | The four-crawler synchronised design, Puppeteer-based | | | [[https://github.com/ucsdsysnet/crumbcruncher|CrumbCruncher]] | {[randall2022_uidsmuggling]} | The four-crawler synchronised design, Puppeteer-based | |
| | [[https://uiowa-irl.github.io/Khaleesi/|Khaleesi]] | {[iqbal2022_khaleesi]} | Request-chain classifier | | | [[https://uiowa-irl.github.io/Khaleesi/|Khaleesi]] | {[iqbal2022_khaleesi]} | Request-chain classifier | |
| | [[https://github.com/cookiegraph/CookieGraph|CookieGraph]] | {[shaoor2023cookiegraph]} | First-party tracking-cookie classifier | | | [[https://github.com/cookiegraph/CookieGraph|CookieGraph]] | {[shaoor2023cookiegraph]} | First-party tracking-cookie classifier | |
| | [[https://github.com/purl-sanitizer/purl|PURL]] | {[shaoor2024purl]} | Link-decoration classifier and sanitiser | | | [[https://github.com/shaoormunir/purl|PURL]] | {[shaoor2024purl]} | Link-decoration classifier and sanitiser. The ''purl-sanitizer'' organisation in the paper no longer exists; the URL redirects here, last push 2024-08-22 | |
| | [[https://github.com/pooneh-nb/cookieGuard|CookieGuard]] | {[bahrami2025_cookieguard]} | First-party cookie-jar isolation | | | [[https://github.com/pooneh-nb/cookieGuard|CookieGuard]] | {[bahrami2025_cookieguard]} | First-party cookie-jar isolation | |
| | ''purl.org/tracking-detection-paper'' | {[calzavara2026_syntactic]} | Syntactic-matching and taint-tracking pipelines, and the comparison data | | | [[https://github.com/eleumasc/Web-Tracking-Detection|Web-Tracking-Detection]] | {[calzavara2026_syntactic]} | Syntactic-matching and taint-tracking pipelines and the comparison data. The paper cites ''purl.org/tracking-detection-paper'', which redirects here; last push 2026-08-03 | |
| | [[http://personalization.ccs.neu.edu/|Retargeting dataset]] | {[bashir2016tracing]} | 7K labelled targeted and retargeted ads, inclusion chains, full HTTP traces — **the only published external ground truth for syncing detection**, and it is from 2016 | | | [[http://personalization.ccs.neu.edu/|Retargeting dataset]] | {[bashir2016tracing]} | 7K labelled targeted and retargeted ads, inclusion chains, full HTTP traces — **the only external ground truth released by any of the 30 papers in this corpus**, and it is from 2016 | |
| | | ''doi.org/10.17617/3.H5T0W4'' | {[dao2026_gclid]} | The ''gclid'' crawl data, in a repository with a DOI rather than on GitHub | |
| | |
| | Nine of the thirteen public artifacts are listed; the other four are conference-artifact or project pages whose reuse value is narrower than a tool or a dataset. The full list of links the extraction found is in the report output on [[provenance:privacy:cookie_syncing]]. |
| |
| ==== How syncing papers classify requests ==== | ==== How syncing papers classify requests ==== |
| |
| Crossing the measuring set with the extraction's ''classification'' family: **20 of the 29** carry a tuple whose target is ''web-request'' (corpus-wide, 262 of the 4,439 papers that classified anything target ''web-request''). Of those 20, **15** use a **blocklist** to decide which of the parties involved counts as a tracker: **12** name EasyList and/or EasyPrivacy and **4** name Disconnect. That is a second, independent dependency on filter lists layered on top of the identifier heuristic, and it inherits [[Privacy:Requests#What a Filter List Misses, Measured|everything those lists miss]]. Only **9 of the 20** report any validation of that classification stronger than a sentinel. | Crossing the measuring set with the extraction's ''classification'' family: **20 of the 30** carry a tuple whose target is ''web-request'' (corpus-wide, 262 of the 4,439 papers that classified anything target ''web-request''). Of those 20, **15** use a **blocklist** to decide which of the parties involved counts as a tracker: **12** name EasyList and/or EasyPrivacy and **4** name Disconnect. That is a second, independent dependency on filter lists layered on top of the identifier heuristic, and it inherits [[Privacy:Requests#What a Filter List Misses, Measured|everything those lists miss]]. Only **9 of the 20** report any validation of that classification stronger than a sentinel. |
| |
| ===== What to Report ===== | ===== What to Report ===== |
| |
| If a reviewer is to accept a syncing figure, the paper has to answer all of these. The corpus can only speak to three of them, and on those three the record is poor: a quarter of the papers do not state statefulness, half do not state a consent action, and 83% do not state whether the browser was headless. | If a reviewer is to accept a syncing figure, the paper has to answer all of these. The corpus can only speak to three of them, and on those three the record is poor: 24.0% of the papers do not state statefulness, 48.0% do not state a consent action, and 80.0% do not state whether the browser was headless. |
| |
| - **The unit and its denominator.** Sites? Directional flows? Unordered domain pairs? Users? Requests? Chains? And of what population — see the table in [[#Pick the Unit Before You Pick the Method]]. | - **The unit and its denominator.** Sites? Directional flows? Unordered domain pairs? Users? Requests? Chains? And of what population — see the table in [[#Pick the Unit Before You Pick the Method]]. |
| |
| <WRAP todo> | <WRAP todo> |
| * **Nobody has repeated the ad-semantics check since 2022.** {[bashir2016tracing]} is the only independent measurement of what identifier heuristics miss, it is from 2016, and its 31%-missed figure is cited as if it were current. Header bidding {[cook2020_headerbidding]} and the retargeting design are both still runnable. This is the highest-value replication on this page. | * **No paper in these seven venues has repeated the ad-semantics check since 2022.** {[bashir2016tracing]} is the only independent measurement of what identifier heuristics miss, it is from 2016, and its 31%-missed figure is cited as if it were current. Header bidding {[cook2020_headerbidding]} and the retargeting design are both still runnable. This is the highest-value replication on this page. |
| * **There is no time series.** Every prevalence figure here comes from a different population, crawler and year, so nobody can say whether syncing grew, shrank, or moved. A single stateful crawl of a fixed population, repeated quarterly with a fixed heuristic, would be the first. | * **There is no time series.** Every prevalence figure here comes from a different population, crawler and year, so nothing in this corpus can say whether syncing grew, shrank, or moved. A single stateful crawl of a fixed population, repeated quarterly with a fixed heuristic, would be the first. |
| * **The identifier heuristics have never been compared head-to-head on one dataset.** {[calzavara2026_syntactic]} tabulates eleven of them and then implements one "representative" union, explicitly declining to evaluate them individually. Running all eleven over one crawl and reporting the spread would tell the field how much of its published variance is heuristic choice. | * **The identifier heuristics have never been compared head-to-head on one dataset.** {[calzavara2026_syntactic]} tabulates ten prior heuristics and then implements an eleventh — a "representative" union of them — explicitly declining to evaluate the ten individually. Running all ten over one crawl and reporting the spread would tell the field how much of its published variance is heuristic choice rather than measurement. |
| * **No paper in these venues measures the deterministic-ID frameworks** (UID2, EUID, and their competitors) in the wild, even though they are the industry's stated replacement for syncing. | * **No paper in these venues measures the deterministic-ID frameworks** (UID2, EUID, and their competitors) in the wild, even though they are the industry's stated replacement for syncing. |
| * **Machine-learning detectors have not been evaluated against taint tracking.** {[calzavara2026_syntactic]} names this as future work: its comparison covers syntactic matching and taint tracking but not {[siby2022_webgraph]}, {[shaoor2023cookiegraph]} or the behaviour-based detectors. | * **Machine-learning detectors have not been evaluated against taint tracking.** {[calzavara2026_syntactic]} names this as future work: its comparison covers syntactic matching and taint tracking but not {[siby2022_webgraph]}, {[shaoor2023cookiegraph]} or the behaviour-based detectors. |
| The limitations specific to this page: | The limitations specific to this page: |
| |
| * **The population is defined by a regex over full text, then corrected by hand.** The regex is a filter for reading effort, not a definition. It under-recalls badly at the low end: {[calzavara2026_syntactic]}, the most methodologically central paper here, uses the phrase **twice** and would have been excluded by any threshold. Three papers were added to the set by hand for exactly this reason. There is no way to know how many others were missed, and the honest reading of "106 papers mention it" is "at least 106". | * **The population is defined by a regex over full text, then corrected by hand.** The regex is a filter for reading effort, not a definition. It under-recalls badly at the low end: {[calzavara2026_syntactic]}, the most methodologically central paper here, uses the phrase **twice** and would have been excluded by any threshold. Three papers were added to the set by hand for exactly this reason, and a fourth to correct a boundary inconsistency rather than to expand the set. There is no way to know how many others were missed, and the honest reading of "106 papers mention it" is "at least 106". |
| * **The 29-paper "measures it" set is one person's judgement**, recorded as an explicit label per paper in the report script so that a disagreement can be located. Nine candidates were excluded because the phrase means something else in them; that call is defensible but not unique. | * **The 30-paper "measures it" set is one person's judgement**, recorded as an explicit label per paper in the report script so that a disagreement can be located. Nine candidates were excluded because the phrase means something else in them; that call is defensible but not unique. |
| | * **The boundary of that set is genuinely fuzzy, and it moved during writing.** It is "measures an identifier being conveyed to a party that did not set it", which includes both a two-way sync and a one-way hand-off. Two corpus papers meet that description and are **not** in the 30, because they were found after the set was fixed and adding papers as one stumbles on them is how a hand-curated set stops being reproducible: {[bekos2023_hitchhiker]} measures a median website passing identifiers to **6.2 third parties**, and {[dimova2021cname]} finds **1,899 cookie leaks in request URLs on 1,295 distinct sites**. Both are named here rather than quietly omitted; a reader who counts them gets 32, and the shape of every table above is unchanged by two papers. One paper //was// added late — the gclid study — but to correct a boundary that had been applied two different ways, not to expand the set; the difference is argued on [[provenance:privacy:cookie_syncing]]. Drawn strictly — only papers measuring a genuine //two-way// match between two parties' identifiers — the set would be closer to twenty. |
| * **The detection-family assignment is coarse.** Papers combine families — {[shaoor2024purl]} builds a graph //and// does syntactic value matching — and each was assigned the family that does the identifier-sharing work. Read the family table as a ranking, not as a partition. | * **The detection-family assignment is coarse.** Papers combine families — {[shaoor2024purl]} builds a graph //and// does syntactic value matching — and each was assigned the family that does the identifier-sharing work. Read the family table as a ranking, not as a partition. |
| * **Every prevalence figure quoted from a paper carries that paper's denominator, and they are not comparable.** This is stated once in [[#Pick the Unit Before You Pick the Method]] and is worth repeating: none of the percentages on this page can be averaged, ordered, or plotted against each other. | * **Every prevalence figure quoted from a paper carries that paper's denominator, and they are not comparable.** This is stated once in [[#Pick the Unit Before You Pick the Method]] and is worth repeating: none of the percentages on this page can be averaged, ordered, or plotted against each other. |
| | * **''crawlConfig'' is an object with one shared evidence quote**, so the crawl-configuration table cannot be quote-checked field by field. Of five quotes read by hand, four do not touch the field the row reports. See the box beside that table, and the detail in the provenance page. |
| * **Corpus-level counts come from the ''.cols'' rendering of the PDFs.** Column reading order was repaired but not perfectly; a phrase split across a column break can still be missed even after whitespace collapsing and de-hyphenation. | * **Corpus-level counts come from the ''.cols'' rendering of the PDFs.** Column reading order was repaired but not perfectly; a phrase split across a column break can still be missed even after whitespace collapsing and de-hyphenation. |
| * **The extraction fields used here** (''crawlConfig.statefulness'', ''.consentAction'', ''.interactionDepth'') are among the most stable in the schema — 98%, 93% and 97% paper-level agreement between two independent extraction runs — but that stability was measured on the previous corpus and has not been re-measured. | * **The extraction fields used here** (''crawlConfig.statefulness'', ''.consentAction'', ''.interactionDepth'') are among the most stable in the schema — 98%, 93% and 97% paper-level agreement between two independent extraction runs — but that stability was measured on the previous corpus and has not been re-measured. |