User Tools

Site Tools


privacy:requests

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
privacy:requests [2026/08/12 16:56] – Correct a substantive error: Duumviri does NOT train without labels. It uses EasyList and EasyPrivacy as ground truth (12,936 tracker / 14,785 non-tracker cases); what is independent is its differential features and its separately-trained breakage detecto karel.kubicek.claudeprivacy:requests [2026/08/29 13:36] (current) – Replace the last literal corpus figure inherited from the carve-out with a pointer to the section that maintains it. Authored by Claude karel.kubicek.claude
Line 6: Line 6:
  
 <WRAP important> <WRAP important>
-**The one thing to understand before you start: in this field the filter list is both the instrument and the ground truth, and almost nobody separates the two.** Of the 14 papers in this page's population that carry a learned request classifier, **8 take their labels from a filter list** — including every reference baseline the field compares against (AdGraph, WebGraph, Khaleesi, WTAGRAPH, AdFlush, Duumviri). So "our classifier reaches 98% accuracy" usually means "our classifier agrees with EasyList 98% of the time", and the residual is reported as error rather than as discovery.+**The one thing to understand before you start: in this field the filter list is both the instrument and the ground truth, and almost nobody separates the two.** Of the 14 papers in [[#Use in Publications|this page's population]] that carry a learned request classifier, **8 take their labels from a filter list** — including every reference baseline the field compares against (AdGraph, WebGraph, Khaleesi, WTAGRAPH, AdFlush, Duumviri). So "our classifier reaches 98% accuracy" usually means "our classifier agrees with EasyList 98% of the time", and the residual is reported as error rather than as discovery.
  
-We now know roughly what that costs. Calzavara et al. {[calzavara2026_syntactic]} (PoPETs 2026) ran syntactic filter-list matching and dynamic taint tracking over the same crawl and compared them request by request: of the 40,605 tracking requests found, syntactic matching found 33,584 and taint tracking 23,109, but **only 16,088 were found by both**. They then re-tested the requests automatically, by removing the identifier and checking whether the tracking behaviour disappeared. The estimate that comes out is **16%–19% likely false positives among the syntactic matches**, rising to **27%–30%** among the requests only syntactic matching flagged, against **4%–7%** for the requests taint tracking found — and **7,021 requests, around 17% of the dataset, were found by taint tracking alone**. Treat a filter-list hit as a noisy label with error bars in the high teens, not as a definition — and say in your paper that you did.+We now know roughly what that costs. Calzavara et al. {[calzavara2026_syntactic]} (PoPETs 2026) ran syntactic filter-list matching and dynamic taint tracking over the same crawl and compared them request by request: of the 40,605 tracking requests found, syntactic matching found 33,584 and taint tracking 23,109, but **only 16,088 were found by both**. They then re-tested every one of those matches automatically, with a **canary**: replace the identifier in client-side storage with a fresh value, revisit the page, and see whether the new value shows up in a request matching the same template. If it does the match is confirmed; if the old value is still there instead, it is refuted. The estimate that comes out is **16%–19% likely false positives among the syntactic matches**, rising to **27%–30%** among the requests only syntactic matching flagged, against **4%–7%** for the requests taint tracking found — and **7,021 requests, around 17% of the dataset, were found by taint tracking alone**. Treat a filter-list hit as a noisy label with error bars in the high teens, not as a definition — and say in your paper that you did. **That said, this is one study, one taint-tracking browser, 7,614 sites**; nobody has repeated it, and [[#Open Questions]] says so.
 </WRAP> </WRAP>
  
 ===== What to Read First ===== ===== What to Read First =====
  
-  * **[[https://arxiv.org/abs/2506.14057|SoK: Advances and Open Problems in Web Tracking]]** {[vekaria2025_soktracking]} — a systematisation by **fourteen** of the field's authors, and the fastest orientation to where request classification sits in the wider tracking literature. Its §V-C1 gives the same three-limitation account of filter lists this page gives (small maintainer community, accumulated dead rules, static so evadable) and then names the ML lineage: AutoFR, AdGraph, WebGraph, WTAGraph, and PageGraph as the shipped implementation. **It is still a preprint**: only v1 exists (16 June 2025), and the version exhibited as a poster at IEEE S&P 2026 labels itself "Preprint".((Checked 2026-08-12: ''arxiv.org/abs/2506.14057'' lists only ''[v1] Mon, 16 Jun 2025''; v2 and v3 return HTTP 404. The extended version is at [[https://github.com/privacysandstorm/sok-advances-open-problems-web-tracking|github.com/privacysandstorm/sok-advances-open-problems-web-tracking]]. The listing page'author block reads as 37 comma-separated fieldsbut that is the affiliation list running on: splitting on the affiliation marker gives Vekaria, Beugin, Munir, Acar, Bielova, Englehardt, Iqbal, Kapravelos, Laperdrix, Nikiforakis, Polakis, Roesner, Shafiq and Zimmeck — fourteen.)) Check for a venue version before you cite it as published.+  * **[[https://arxiv.org/abs/2506.14057|SoK: Advances and Open Problems in Web Tracking]]** {[vekaria2025_soktracking]} — a systematisation by **fourteen** of the field's authors, and the fastest orientation to where request classification sits in the wider tracking literature. Its §V-C1 gives the same three-limitation account of filter lists this page gives (small maintainer community, accumulated dead rules, static so evadable) and then names the ML lineage: AutoFR, AdGraph, WebGraph, WTAGraph, and PageGraph as the shipped implementation. **It is still a preprint**: only v1 exists (16 June 2025), and the version exhibited as a poster at IEEE S&P 2026 labels itself "Preprint".((Checked 2026-08-12: ''arxiv.org/abs/2506.14057'' lists only ''[v1] Mon, 16 Jun 2025''; v2 and v3 return HTTP 404. The extended version is at [[https://github.com/privacysandstorm/sok-advances-open-problems-web-tracking|github.com/privacysandstorm/sok-advances-open-problems-web-tracking]]. Do not trust the listing page'own count: its PDF link reads "by Yash Vekaria (1) and 36 other authors"because arXiv's author metadata for this paper runs the affiliation list into the author field. The paper itself names Vekaria, Beugin, Munir, Acar, Bielova, Englehardt, Iqbal, Kapravelos, Laperdrix, Nikiforakis, Polakis, Roesner, Shafiq and Zimmeck — fourteen.)) Check for a venue version before you cite it as published.
   * **SoK: After Decades of Web Tracker Detection, What's Next?** {[rieder2026_sok]}, IEEE S&P 2026 — a meta-study specifically of tracker //detectors//, which is the classifier lineage this page is about.   * **SoK: After Decades of Web Tracker Detection, What's Next?** {[rieder2026_sok]}, IEEE S&P 2026 — a meta-study specifically of tracker //detectors//, which is the classifier lineage this page is about.
-  * Then read in this order, because each one answers the previous one's complaint: filter lists as measured dead weight {[snyder2020_who]} → what they miss {[fouad2020_missed]} → the graph lineage {[iqbal2020_adgraph]}, {[siby2022_webgraph]} → mixed resources {[amjad2021_trackersift]} → the deployable classifier {[lee2024_adflush]} → labels without list {[shuang2025_duumviri]} → how wrong the list was all along {[calzavara2026_syntactic]}.+  * Then read in this order, because each one answers the previous one's complaint: filter lists as measured dead weight {[snyder2020_who]} → what they miss {[fouad2020_missed]} → the graph lineage {[iqbal2020_adgraph]}, {[siby2022_webgraph]} → mixed resources {[amjad2021_trackersift]} → the deployable classifier {[lee2024_adflush]} → labels that at least come with breakage check {[shuang2025_duumviri]} → how wrong the list was all along {[calzavara2026_syntactic]}.
  
 ===== Pick the Unit Before You Pick the Method ===== ===== Pick the Unit Before You Pick the Method =====
Line 23: Line 23:
 ^ Unit ^ What you get ^ What it costs ^ ^ Unit ^ What you get ^ What it costs ^
 | **eTLD+1 / domain** | The cheapest unit, and the only one a hosts-file or DNS blocklist can give you. Comparable across papers | Cannot distinguish ''cdn.example.com/jquery.js'' from ''cdn.example.com/track.gif''; CNAME cloaking and first-party proxying defeat it {[dimova2021cname]} | | **eTLD+1 / domain** | The cheapest unit, and the only one a hosts-file or DNS blocklist can give you. Comparable across papers | Cannot distinguish ''cdn.example.com/jquery.js'' from ''cdn.example.com/track.gif''; CNAME cloaking and first-party proxying defeat it {[dimova2021cname]} |
 +| **entity / company** | The unit the //question// usually wants: ''google.com'', ''googleapis.com'' and ''doubleclick.net'' are one organisation, so an eTLD+1 "third party" label is wrong for same-org domains | Needs an entity map. Disconnect's ''entities.json'' and DuckDuckGo Tracker Radar's entity-to-domain map are the two the field uses, and they disagree; whichever you pick, name it |
 | **request URL** | What Adblock-syntax lists actually match on, with resource type and party as modifiers | A tracker that rotates paths or moves to a first-party subdomain escapes; blocked replica ad domains survived a mean 410.5 days before a rule appeared — see below | | **request URL** | What Adblock-syntax lists actually match on, with resource type and party as modifiers | A tracker that rotates paths or moves to a first-party subdomain escapes; blocked replica ad domains survived a mean 410.5 days before a rule appeared — see below |
 | **script / resource** | Attributes the request to the code that made it | ~13.4% of scripts are //mixed// — they do tracking and functionality in the same file {[amjad2024_notjs]} | | **script / resource** | Attributes the request to the code that made it | ~13.4% of scripts are //mixed// — they do tracking and functionality in the same file {[amjad2024_notjs]} |
Line 38: Line 39:
  
 ^ Era ^ Method ^ Representative work ^ Status in 2026 ^ ^ Era ^ Method ^ Representative work ^ Status in 2026 ^
-| 2010– | **Adblock-syntax filter lists**, applied live or in post-processing | EasyList, EasyPrivacy, Disconnect | **Current, and still the default.** It is the most common method in the corpus section below by a factor of nearly two over anything else. Not because it is best but because it is comparable, free and reviewable |+| 2010– | **Adblock-syntax filter lists**, applied live or in post-processing | EasyList, EasyPrivacy, Disconnect | **Current, and still the default.** It is more than half again as common as anything else in the corpus section below. Not because it is best but because it is comparable, free and reviewable |
 | 2015–2019 | Supervised classifiers on **URL and content features** | One-class learning on tracker URLs {[ikram2017_seamless]} | **Superseded.** Content features are attacker-controlled; WebGraph's evasion experiment is the demonstration | | 2015–2019 | Supervised classifiers on **URL and content features** | One-class learning on tracker URLs {[ikram2017_seamless]} | **Superseded.** Content features are attacker-controlled; WebGraph's evasion experiment is the demonstration |
 | 2017–2021 | **Anti-adblock and circumvention detection** as its own task | The ad wars {[iqbal2017_wars]}, anti-adblock detection {[mughees2017_detecting]}, CV-Inspector {[le2021_inspector]} | **Alive but niche.** CV-Inspector reached 93% accuracy on sites that successfully circumvent adblockers, and found that over a third of sites with relevant rules in the Anti-Circumvention Filter List still circumvented | | 2017–2021 | **Anti-adblock and circumvention detection** as its own task | The ad wars {[iqbal2017_wars]}, anti-adblock detection {[mughees2017_detecting]}, CV-Inspector {[le2021_inspector]} | **Alive but niche.** CV-Inspector reached 93% accuracy on sites that successfully circumvent adblockers, and found that over a third of sites with relevant rules in the Anti-Circumvention Filter List still circumvented |
Line 44: Line 45:
 | 2020–2022 | **Request chains** as the unit, sequential ML | Khaleesi {[iqbal2022_khaleesi]} (94.07% on a later crawl) | **Still a cited baseline.** It is not a page-execution graph; do not lump it with AdGraph | | 2020–2022 | **Request chains** as the unit, sequential ML | Khaleesi {[iqbal2022_khaleesi]} (94.07% on a later crawl) | **Still a cited baseline.** It is not a page-execution graph; do not lump it with AdGraph |
 | 2021–2023 | **Rule generation** rather than rule matching: learn the filter rules themselves | AutoFR {[le2023_autofr]}, regional list generation {[sjosten2020_filter]} | **Current, and under-used in measurement.** AutoFR's generated rules blocked 86% of ads against EasyList's 87%, within its breakage threshold | | 2021–2023 | **Rule generation** rather than rule matching: learn the filter rules themselves | AutoFR {[le2023_autofr]}, regional list generation {[sjosten2020_filter]} | **Current, and under-used in measurement.** AutoFR's generated rules blocked 86% of ads against EasyList's 87%, within its breakage threshold |
-| 2021 | **Surrogate replacement** instead of blocking, to avoid breakage | SugarCoat {[smith2021_sugarcoat]} | **Current** and shipped in Brave. Mean breakage rating 1.03 (normal) versus 2.86 when the same scripts were blocked outright |+| 2021 | **Surrogate replacement** instead of blocking, to avoid breakage | SugarCoat {[smith2021_sugarcoat]} | **Current**and Brave collaboration rather than a research prototype.((Brave's own privacy-updates index carries it as post #12, 18 November 2021: "Brave and UC San Diego announce SugarCoat, a new solution to strengthen the protection of Web users' privacy while not breaking websites… the result of a year-long research collaboration". Checked 2026-08-12 at [[https://brave.com/privacy-updates/|brave.com/privacy-updates]]. The per-post URL that used to hold it now 404s, so this is the announcement, not a claim about which Brave version ships it today.)) Mean breakage rating 1.03 (normal) versus 2.86 when the same scripts were blocked outright |
 | 2023–2024 | **Deployability as the objective**: small feature sets, no content features | AdFlush {[lee2024_adflush]} | **Current.** F1 0.98 against AdGraph 0.93, WebGraph 0.90, WTAGraph 0.84; F1 stayed above 0.9789 for five and a half months without retraining | | 2023–2024 | **Deployability as the objective**: small feature sets, no content features | AdFlush {[lee2024_adflush]} | **Current.** F1 0.98 against AdGraph 0.93, WebGraph 0.90, WTAGraph 0.84; F1 stayed above 0.9789 for five and a half months without retraining |
 | 2024 | **Function granularity** with dynamic calling context | NoT.js {[amjad2024_notjs]} | **Current**, and mostly a [[Privacy:JavaScript|JavaScript]] method | | 2024 | **Function granularity** with dynamic calling context | NoT.js {[amjad2024_notjs]} | **Current**, and mostly a [[Privacy:JavaScript|JavaScript]] method |
Line 62: Line 63:
 ==== What the corpus cannot tell you ==== ==== What the corpus cannot tell you ====
  
-**LLM classification of web requests is, as of 2026-08-12, essentially absent from the peer-reviewed literature.** One paper in these seven venues, TGNN {[xiong2026_tgnn]} (TheWebConf 2026), carries an ''llm'' method on a ''web-request'' classification tuple, and it uses the model to //annotate training data// rather than to classify at inference. A targeted search outside the corpus — arXiv, EuroS&P, ACSAC, RAID, AsiaCCS and WPES, 2025–2026 — found no peer-reviewed paper that prompts or fine-tunes a language model to decide whether an HTTP request is tracking. Industry is ahead of the literature here and says so: AdGuard demonstrated a prototype at the Ad-Filtering Dev Summit in October 2025 that asks a model per resource instead of consulting a list, and reported latency and cost as the blockers.((AdGuard, [[https://adguard.com/en/blog/beyond-filter-lists-rethinking-ad-blocking-with-llms.html|"Beyond Filter Lists: Rethinking Ad Blocking with LLMs"]], October 2025, checked 2026-08-12. A vendor blog post about a Chrome-extension prototype, not a peer-reviewed evaluation — cited here as evidence that the idea is being tried, not as a result.)) If you are planning an LLM-based request classifier you are not late — but you have no baseline to cite, so budget for building one, and for the reviewer question about cost, reproducibility and prompt drift that this page cannot answer for you.+**LLM classification of web requests is, as of 2026-08-12, essentially absent from the peer-reviewed literature.** One paper in these seven venues, TGNN {[xiong2026_tgnn]} (TheWebConf 2026), carries an ''llm'' method on a ''web-request'' classification tuple, and it uses the model to //annotate training data// rather than to classify at inference. A targeted search outside the corpus — arXiv, EuroS&P, ACSAC, RAID, AsiaCCS and WPES, 2025–2026 — found no peer-reviewed paper that prompts or fine-tunes a language model to decide whether an HTTP request is tracking. Industry is ahead of the literature here and says so: AdGuard demonstrated a prototype at the Ad-Filtering Dev Summit in October 2025 that asks a model per resource instead of consulting a list, and reported latency and cost as the blockers.((AdGuard, [[https://adguard.com/en/blog/beyond-filter-lists-rethinking-ad-blocking-with-llms.html|"Beyond Filter Lists: Rethinking Ad Blocking with LLMs"]], published 2025-11-18describing a talk given at the summit that October; checked 2026-08-12. A vendor blog post about a Chrome-extension prototype, not a peer-reviewed evaluation — cited here as evidence that the idea is being tried, not as a result.)) If you are planning an LLM-based request classifier you are not late — but you have no baseline to cite, so budget for building one, and for the reviewer question about cost, reproducibility and prompt drift that this page cannot answer for you.
  
-**And one 2026 paper is missing from the tables below by construction.** AdVersa {[lim2026_adversa]} (TheWebConf 2026) reports F1 **98.23%**, generalisation to unseen domains at 91.47% F1, and robustness where prior systems were evaded 57–92% of the time. TheWebConf 2026 is one of the incompletely-selected venue-years, so it is absent from every corpus figure on this page even though it is squarely in scope. Its own abstract frames it as embedding-based rather than LLM-based; treat it as the current successor to the AdGraph/WebGraph line and **not** as the missing LLM baseline.+**And one 2026 paper is missing from the tables below by construction.** AdVersa {[lim2026_adversa]} (TheWebConf 2026) reports F1 **98.23%**, generalisation to unseen domains at 91.47% F1, and robustness where prior systems were evaded 57–92% of the time. TheWebConf 2026 is one of the incompletely-selected venue-years, so it is absent from every corpus figure on this page even though it is squarely in scope. Its own abstract frames it as embedding-based rather than LLM-based; treat it as the likeliest successor to the AdGraph/WebGraph line and **not** as the missing LLM baseline. Its figures here are the paper's own, taken from its abstract and Crossref record; nobody on this page has read it critically.
  
 ===== Block Lists ===== ===== Block Lists =====
  
-==== Crowd-Sourced and Outdated ====+Matching a request against an Adblock-syntax filter list is what **57.0%** of the papers below do, and it is still the default. What it means to do that well — which lists exist and which are dead, how to record the exact version and commit you matched against, which engine to use, what a rule needs from your crawl in order to be evaluated at all, what the list misses and where, and why "on the list" is a definition rather than a finding — is one topic and it now has its own page:
  
-The main principle of block lists is their crowd-sourced nature. For instance, the [[https://github.com/easylist/easylist|EasyList repository]] has **324 contributors, 286,987 commits and 8,901 closed issues** as of 2026-08-12.((Measured against the GitHub REST API on 2026-08-12: ''api.github.com/repos/easylist/easylist'' plus ''Link''-header pagination on ''/contributors?per_page=1'' and ''/commits?per_page=1'', and ''search/issues?q=repo:easylist/easylist+type:issue+state:closed''. The count is 386 if anonymous and deleted accounts are included. These numbers were "almost 300 / over 200k / more than 7k" in an earlier version of this page; they grow, so re-measure rather than cite this sentence.)) This has several implications:+  * **[[Programming:Filter Lists|Filter lists]]** — the list as instrument and as ground truth.
  
-  * Widespread advertisers and trackers have well-defined and up-to-date rules, while the long tail of tracking companies might not be covered well. +The three things from it you cannot skip while reading this page:
-  * Adding rules is much more common than deleting them. Snyder et al. {[snyder2020_who]} applied EasyList to a sample of 10,000 websites and found that **90.16% of its resource-blocking rules provide no benefit to users in common browsing scenarios**; they measured EasyList growing from a few hundred rules to over 60,000 across its first nine years. Böttger et al. {[bottger2025_regional]} reproduced the shape of that result on regional lists five years lateracross their crawl profiles **93.3% of distinct rules identified no tracking request at all**, and only 8,163 of 143,654 rules ever fired. +
-  * There is a cat-and-mouse game between list maintainers and the advertising industry. Some rules (e.g., [[https://www.engadget.com/inside-the-arms-race-between-youtube-and-ad-blockers-140031824.html|YouTube's war on ad blocking]]) are short-lived, making it necessary to use up-to-date lists.+
  
-<WRAP important> +  * **A rule is evaluated against a request //in context//.** ''$third-party'', ''$domain='', the resource-type options and ''@@'' exception rules all need the initiator URL, the resource type and the redirect chainA crawl that logged only request URLs cannot be post-processed with a list, and it fails silently rather than erroring
-**"We used EasyList" is not a reproducible method, and the list itself tells you why.** Running the provenance script below three times within half an hour on 2026-08-12 returned three different lists: ''Version: 202608121614'' with 52,556 network rules, ''202608121621'' with 52,557, then ''202608121642'' with 52,560. Each carries a ''! Commit:'' field naming the exact git commit that produced it. There is no excuse for not recording it, and no way to reproduce result that does not. +  * **The list is a moving target.** EasyList publishes a ''Version:'' and a ''Commit:'' in its own header and changes several times an hour; of the corpus papers naming list as tool, **four** record something that identifies the rules they matched against ([[Programming:Filter Lists#Which version|the count and its denominator]]). 
-</WRAP> +  * **filter-list hit is a noisy label**, estimated at **16%–19% false positives** {[calzavara2026_syntactic]}, with the false negatives measured repeatedly and separately — 25.22{[fouad2020_missed]}, 34.5% {[lee2023_track]}, and much worse off the desktop web.
- +
-==== Blocking Specific Resources ==== +
- +
-Rules can prevent actions from happening (useful for protecting user privacy), either by blocking entire domains or specific requests based on their paths. Alternatively, rules can be applied after loading a resource (described by a CSS selector) to prevent its rendering, which is more useful for blocking advertisements or annoying elements. +
- +
-**The split matters for your measurement, and it is bigger than people expect.** Measured on the live lists on 2026-08-12: EasyList is **52,557 network rules and 24,422 cosmetic rules**, so nearly a third of it cannot answer "would this request have been blocked". EasyPrivacy is **54,850 network rules and 34 cosmetic ones** — effectively all network. EasyList Cookie List inverts this completely at **1,668 network and 22,979 cosmetic** rules, because hiding a banner is a rendering problem. If your pipeline reports "rules matched", say which kind. +
- +
-==== Existing Lists ==== +
- +
-Status column checked **2026-08-12** against the primary source in each row. Filter lists die quietly, and a dead list in a 2026 crawl is a silent measurement error. +
- +
-^ List ^ What it is for ^ Status, 2026-08-12 ^ +
-| [[https://easylist.to/index.html|EasyList]] | Advertisements, except first-party self-promotion. Full [[https://easylist.to/pages/policy.html|policy]] | **Active**, pushed the day this was checked; ''Version:'' and ''Commit:'' in the header | +
-| **EasyPrivacy** | Tracking and privacy. Four documented categories: generic URL/tracking patterns used by first or third parties; self-hosted and CNAME first-party trackers; third-party-hosted tracking scripts; and tracking servers blocked at URL level((Quoted from [[https://easylist.to/pages/policy.html|easylist.to/pages/policy.html]], checked 2026-08-12. The page carries no revision date, so how long that text has stood cannot be established from it.)) | **Active** | +
-| [[https://github.com/disconnectme/disconnect-tracking-protection|Disconnect tracking protection]] | Tracker domains grouped by company and category | **Active** (last push 2026-08-07). CC BY-NC-SA 4.0 — **not** a permissive licence, check it before redistributing. Firefox does not consume this repo directly; it ships the Safe-Browsing-format build from [[https://github.com/mozilla-services/shavar-prod-lists|shavar-prod-lists]] | +
-| [[https://spreadprivacy.com/duckduckgo-tracker-radar/|DuckDuckGo Tracker Radar]] | Automatically constructed tracker domains with company attribution, prevalence, fingerprinting and cookie signals. [[https://github.com/duckduckgo/tracker-radar/blob/main/docs/DATA_MODEL.md|Data model]] | **Active** (pushed 2026-08-12). The blocklist derived from it is at ''duckduckgo/tracker-blocklists'' — note the **plural**; the singular repository name 404s | +
-| [[https://www.ghostery.com/whotracksme/|Ghostery WhoTracks.me]] | Tracker prevalence dataset over the top 10,000 sites, with company attribution | **Active** (repo pushed 2026-08-04). Both URLs moved: ''whotracks.me'' now redirects to ''ghostery.com/whotracksme/'', and the repository to [[https://github.com/whotracksme/whotracks.me|whotracksme/whotracks.me]] | +
-| [[https://github.com/AdguardTeam/AdguardFilters|AdGuard filters]] | Ads, tracking, annoyances, and a separate URL-tracking filter | **Active.** GitHub Releases is empty — the canonical download is ''filters.adtidy.org/<platform>/filters/<N>.txt'', whose header carries ''Version'', ''TimeUpdated'' and ''Expires''. The registry mapping IDs to lists is [[https://github.com/AdguardTeam/FiltersRegistry|FiltersRegistry]] | +
-| [[https://pgl.yoyo.org/adservers/|Peter Lowe's list]] | Ad and tracking servers, domain-level, deliberately small | **Active**: 3,525 entries, last updated the day this was checked. A useful high-precision, low-recall comparison point | +
-| **hpHosts / MalwareBytes ATS** | Historic hosts-file ad/tracking list | **Dead.** ''hosts-file.net'' did not resolve on 2026-08-12; Malwarebytes stopped updating it around 2020. It appears in older papers — do not reuse it | +
-| [[https://justdomains.github.io/blocklists/|justdomains]] | Not a list: a domain-only re-encoding of EasyListEasyPrivacy, AdGuard DNS and others | **Active as a conversion layer.** Cite the upstream list, not this | +
-| [[https://easylist.to/pages/other-supplementary-filter-lists-and-easylist-variants.html|Country-specific lists]] | Mostly advertising, region-specific | **Active.** Böttger et al. {[bottger2025_regional]} is the only systematic study of what they add | +
-| **EasyList Cookie List** | CSS selectors for cookie notices. Now inside the main easylist repo at ''easylist_cookie/'' | **Active** (last modified 2026-08-11). No ''Version:'' field, only ''Last modified:''+
-| [[https://github.com/OhMyGuus/I-Still-Dont-Care-About-Cookies|I Still Don't Care About Cookies]] | Removes notices //and// clicks through them. Useful when the specific consent action does not matter | **Active** (pushed 2026-08-12), GPL-3.0, but 14,232 open issues. Click rules are still at ''src/data/js/5_clickHandler.js'' — the numeric prefixes have gapsso do not assume contiguous ordering | +
-| [[https://github.com/duckduckgo/autoconsent|DuckDuckGo autoconsent]] | CMP-specific rules that can express //which// purposes to accept or reject | **Active and the most maintained of the three** (pushed 2026-08-12). This is the one to build on | +
-| [[https://github.com/cavi-au/Consent-O-Matic|Consent-O-Matic]] | The original CMP rule set, with per-purpose consent | **Alive but slower** (last push 2026-02-07, 154 open issues) | +
-| **Mozilla ''cookie-banner-rules-list''** | Firefox's cookie-banner handling rules | **Archived** on GitHub, last push 2025-01-07. Do not start here | +
-| DNS-blocking lists | Domain-level blocking, no path granularity | See [[design:website_classification|Website classification]] | +
- +
-==== What a Filter List Misses, Measured ==== +
- +
-You will be asked this in review, so have the numbers. +
- +
-^ Study ^ Method used as the reference ^ What the lists missed ^ +
-| Fouad et al. {[fouad2020_missed]}, PETS 2020 | Behavioural detection seeded by invisible pixels (35.66% of all collected images were invisible) | EasyList+EasyPrivacy missed **25.22%** and Disconnect **30.34%** of the trackers they detected; every browser extension tested missed at least **24.38%** | +
-| Chen et al. {[chen2021_detecting]}, IEEE S&P 2021 | Event-loop-turn JavaScript behaviour signatures built from blocked scripts | **3,589 scripts** hosting behaviour known to be harmful, on **12.48%** of sites measured, missed by the lists that had already blocked the same behaviour elsewhere | +
-| Lee et al. {[lee2023_track]}, TheWebConf 2023 | Packet-metadata classifier, then manual inspection of its "errors" | **34.5%** of the classifier's apparent false positives were real trackers the lists had not yet discovered | +
-| Lee et al. {[lee2024_adflush]}, TheWebConf 2024 | A deployable ML classifier, reported upstream | **642 ads and trackers across 108 domains** confirmed and reported to EasyList, EasyPrivacy and uBlock | +
-| Shuang et al. {[shuang2025_duumviri]}, NDSS 2025 | Differential breakage testing, no labels | **22 previously unreported trackers** (175 occurrences) in one evaluation set | +
-| Calzavara et al. {[calzavara2026_syntactic]}, PoPETs 2026 | Dynamic taint tracking, head to head | **7,021 requests (≈17% of the dataset)** found only by taint tracking; and 16%–19% of the list's own hits were likely false positives | +
- +
-The reverse direction has a number too. AdFlush {[lee2024_adflush]} and the filter lists it was compared against flagged almost exactly the same //volume// of traffic — **39.27% versus 39.92% of all requests** — while disagreeing on which requests. Two methods agreeing on a headline percentage is not evidence they agree. +
- +
-==== Programming: Using Lists ==== +
- +
-Block lists use regular expressions with custom syntax to decide which resources to block. The advantage of applying them in post-processing is that you can run a crawl allowing all resources and classify afterwards — and re-classify with a different list laterwhich you cannot do if you blocked at crawl time+
- +
-Maintenance status checked **2026-08-12**; this is the section of the page that rots fastest. +
- +
-^ Library ^ Language ^ Status, 2026-08-12 ^ Use it? ^ +
-| [[https://github.com/brave/adblock-rust|brave/adblock-rust]] | Rust | **Active** (pushed 2026-08-12). The crate is named ''adblock'', **not** ''adblock-rust'' — v0.13.2, published 2026-07-19 | **Yes.** Brave ships it, so it tracks uBlock-era syntax including ''$removeparam''+
-| ''adblock-rs'' | Node | **Active**, v0.13.2 published 2026-07-19, tracks the Rust crate 1:1 | **Yes**, if you are in Node | +
-| [[https://github.com/ghostery/adblocker|@ghostery/adblocker]] | TypeScript/Node | **Active**, v2.18.2 published 2026-08-05. Renamed: ''@cliqz/adblocker'' is **deprecated** on npm and last published 2024-10-16 | **Yes.** Ghostery's own engine | +
-| ''adblock'' (PyPI, ''ArniDagur/python-adblock'') | Python | **Stale**: v0.6.0, uploaded 2022-07-17. Wraps an old ''adblock-rust'' | Only with pinned, stated version | +
-''braveblock'' (PyPI) | Python | **Stale**v0.5.1, uploaded 2024-02-14 | Only with a pinned, stated version | +
-| [[https://github.com/englehardt/abp-blocklist-parser|abp-blocklist-parser]] | Python | **Abandoned**: last push 2020-11-02, 10 commits total, open issues include "Python 3 support" | **No.** It predates ''$removeparam'' and most modern rule options | +
-| [[https://github.com/scrapinghub/adblockparser|adblockparser]] | Python | **Archived** on GitHub 2019PyPI v0.7 from 2016-10-17 | **No** | +
- +
-<WRAP important> +
-**There is no actively maintained Python binding to a modern filter-list engine as of 2026-08-12.** Both PyPI wrappers around Brave's engine are years behind the Rust crate, and the two pure-Python parsers are abandoned. If your pipeline is Python and your claim depends on rule semantics, either shell out to the Rust or Node engine, or state the parser version and accept that unsupported rule options are silently not matched. This is a real threat to validity that papers do not usually mention. +
-</WRAP> +
- +
-If you only need CSS selector filters during crawl, your crawling library likely supports them natively. For example, in Selenium, you can use ''driver.find_element(By.CSS_SELECTOR, "img#tracker")''+
- +
-==== Manifest V3 Caps How Many Rules an Extension Can Load ==== +
- +
-If your measurement design is "install blocker extension and see what it blocks"this is now a hard constraint rather than an engineering detail. Chrome's ''declarativeNetRequest'' limits, from the API documentation on **2026-08-12**:(([[https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest|developer.chrome.com — chrome.declarativeNetRequest]], "Rule limits", fetched and read 2026-08-12. The constant names are the documentation's own.)) +
- +
-^ Limit ^ Value ^ +
-| static rulesets declared in the manifest | 100, of which **50 enabled at once** (''MAX_NUMBER_OF_ENABLED_STATIC_RULESETS'') | +
-| static rules guaranteed across them | **30,000** (''GUARANTEED_MINIMUM_STATIC_RULES'') | +
-| dynamic rules | ≥5,000 "unsafe" (''MAX_NUMBER_OF_UNSAFE_DYNAMIC_RULES''), 30,000 "safe" since Chrome 121 (''MAX_NUMBER_OF_DYNAMIC_RULES'') | +
-| session rules | 5,000 (''MAX_NUMBER_OF_SESSION_RULES'') | +
-| **regular-expression rules** | **1,000 of each type** (''MAX_NUMBER_OF_REGEX_RULES''), each under 2 KB compiled | +
- +
-Compare those against the lists: **EasyList alone carries 52,557 network rules and EasyPrivacy 54,850** (measured 2026-08-12). Neither fits in the 30,000-rule static guarantee, let alone both, and the 1,000-rule regex cap bites well before that. An MV3 extension therefore ships a //subset// of the list, chosen by its authors — which is what uBlock Origin Lite is and why it is not feature-equivalent to uBlock Origin.((''gorhill/uBlock'' remains actively maintained (pushed 2026-08-11) and works fully on Firefox, which still supports MV2. Chrome disabled MV2 extensions in Chrome 138 and its published date for removing them from the Chrome Web Store is 2026-08-31. The MV3 replacement is [[https://github.com/uBlockOrigin/uBOL-home|uBlock Origin Lite]] (pushed 2026-08-12). Repository dates measured against the GitHub API on 2026-08-12; the Chrome Web Store listing itself could not be fetched — it redirects to a Google consent wall — so the store-side dates here come from Google's published deprecation timeline and press coverage, not from the listing.)) +
- +
-Lukić and Papadopoulos {[lukic2026_mv3]} measured whether this actually degrades blocking and found **no statistically significant reduction** in ads or trackers blocked between MV2 and MV3 builds of four popular blockers — but they did find MV3 leaving cosmetic placeholders in 21% of cases where MV2 left none. **The blocking survived; whether an MV3 extension is a sound //measurement instrument// is a different question, and it is not settled.** If your method depends on the extension seeing every request, prefer post-processing a full crawl with the Rust or Node engine above, where no rule cap applies. +
- +
-==== Recording Which List You Used ==== +
- +
-Run this at the start of a crawl and archive the JSON with your data. It reads the metadata the lists publish about themselves, counts rules by kind, and hashes the bytes. +
- +
-<file python filterlist_provenance.py> +
-#!/usr/bin/env python3 +
-"""Record exactly which filter list you used, so your crawl is reproducible. +
- +
-Filter lists change several times a day. "We used EasyList" is not a method; +
-"EasyList, Version 202608121614, commit cff91d2b, 52,556 network rules" is. Every +
-Adblock-Plus-syntax list carries that metadata in its own header comments -- +
-this script extracts it, counts the rules by kind, and writes a JSON record you +
-can archive next to your crawl data and paste into your methodology section. +
- +
-Run it at the START of a crawl, not when you write the paper. +
- +
-    python3 filterlist_provenance.py > filterlists.json +
-    python3 filterlist_provenance.py --save lists/   # also archive the raw .txt +
-""" +
- +
-import argparse +
-import hashlib +
-import json +
-import pathlib +
-import re +
-import sys +
-import urllib.request +
-from datetime import datetime, timezone +
- +
-# The lists a tracking measurement usually wants. Add your regional list here. +
-LISTS = { +
-    "easylist": "https://easylist.to/easylist/easylist.txt", +
-    "easyprivacy": "https://easylist.to/easylist/easyprivacy.txt", +
-    "easylist-cookie": "https://secure.fanboy.co.nz/fanboy-cookiemonster.txt", +
-    "adguard-url-tracking": "https://filters.adtidy.org/windows/filters/17.txt", +
-    "peter-lowe": "https://pgl.yoyo.org/adservers/serverlist.php" +
-    "?hostformat=adblockplus&showintro=0&mimetype=plaintext", +
-+
- +
-# Header fields Adblock-syntax lists publish about themselves. Not every list +
-# sets every field; a missing field is reported as None rather than guessed. +
-HEADER_FIELDS = ("Version", "Last modified", "TimeUpdated", "Expires", "Commit", "Title"+
- +
-# A cosmetic rule hides an element that has already loaded; a network rule stops +
-# the request. Only network rules answer "would this request have been blocked"+
-# Note the order in classify(): cosmetic *exception(`site.com#@#.ad`) is +
-# counted as cosmeticnot as an exception, because the question this count +
-# answers is "how much of this list is about requests at all"+
-COSMETIC = re.compile(r"#[@?$]?#|#\$#"+
- +
- +
-def classify(line): +
-    if not line.strip() or line.startswith("!") or line.startswith("["): +
-        return "comment" +
-    if COSMETIC.search(line): +
-        return "cosmetic" +
-    if line.startswith("@@"): +
-        return "exception" +
-    return "network" +
- +
- +
-def describe(name, url): +
-    req = urllib.request.Request(url, headers={"User-Agent": "filterlist-provenance/1.0"}) +
-    with urllib.request.urlopen(req, timeout=60) as resp: +
-        raw = resp.read() +
-    text = raw.decode("utf-8", errors="replace"+
-    lines = text.split("\n"+
- +
-    header = {} +
-    for field in HEADER_FIELDS: +
-        m = re.search(rf"^!\s*{re.escape(field)}:\s*(.+)$", text[:8000], re.M) +
-        header[field] = m.group(1).strip() if m else None +
- +
-    counts = {"comment": 0, "cosmetic": 0, "exception": 0, "network": 0} +
-    for line in lines: +
-        counts[classify(line)+= 1 +
- +
-    return { +
-        "name": name, +
-        "url": url, +
-        "fetched_at": datetime.now(timezone.utc).isoformat(timespec="seconds"), +
-        "sha256": hashlib.sha256(raw).hexdigest(), +
-        "bytes": len(raw), +
-        "header": header, +
-        "rules": counts, +
-    }, raw +
- +
- +
-def main(): +
-    ap = argparse.ArgumentParser() +
-    ap.add_argument("--save", metavar="DIR", help="also write the raw list files here"+
-    args = ap.parse_args() +
- +
-    out = [] +
-    for name, url in LISTS.items(): +
-        try: +
-            record, raw = describe(name, url) +
-        except Exception as exc: +
-            # Fail loud: a list you could not fetch is a hole in your method, +
-            # not something to paper over with a stale local copy. +
-            print(f"FAILED {name} <{url}>: {exc}", file=sys.stderr) +
-            raise +
-        out.append(record) +
-        if args.save: +
-            d = pathlib.Path(args.save) +
-            d.mkdir(parents=True, exist_ok=True) +
-            (d / f"{name}.txt").write_bytes(raw) +
-        # Not every list sets `Version:`; EasyList Cookie List and Peter Lowe'+
-        # list only set `Last modified:`Report whichever exists, and say so. +
-        stamp = ( +
-            record["header"]["Version"+
-            or record["header"]["TimeUpdated"+
-            or record["header"]["Last modified"+
-            or "(no version or date in header)" +
-        ) +
-        print( +
-            f"{name:22{stamp:24}" +
-            f" network={record['rules']['network']:7cosmetic={record['rules']['cosmetic']:7}+
-            f" exception={record['rules']['exception']:6} sha256={record['sha256'][:12]}", +
-            file=sys.stderr, +
-        ) +
-    json.dump(out, sys.stdout, indent=2) +
-    print(file=sys.stdout) +
- +
- +
-if __name__ == "__main__": +
-    main() +
-</file> +
- +
-Real output, 2026-08-12:+
  
-<code> 
-easylist               202608121621             network=  52557 cosmetic=  24422 exception=   758 sha256=652ca564670f 
-easyprivacy            202608121630             network=  54850 cosmetic=     34 exception=   836 sha256=809f80964d06 
-easylist-cookie        2026-08-11 23:25 UTC     network=   1668 cosmetic=  22979 exception=   427 sha256=4de43038a16a 
-adguard-url-tracking   2.0.13.86                network=   2492 cosmetic=      2 exception=    91 sha256=c468efefcdfe 
-peter-lowe             Wed, 12 Aug 2026 15:15:56 GMT network=   3525 cosmetic=      0 exception=     0 sha256=25093c8b037f 
-</code> 
  
 ===== ML Classification ===== ===== ML Classification =====
  
-While ad-blocking lists are used by up to a billion users, machine-learning-based blocking has not been widely adopted.((A notable ML-based browser extension was Privacy Badgerwhich used "local learning" to detect tracking. [[https://www.eff.org/deeplinks/2020/10/privacy-badger-changing-protect-you-better|This feature was later disabled to prevent fingerprinting]].)) There are several reasons for this:+Filter lists ship to users; learned classifierswith one partial exception, do not. Three reasonsand all three matter for how you read the results below:
  
-  * Using ML to dynamically decide whether to block resource might make the browser fingerprintable. +  * **A model that decides at runtime is fingerprinting surface.** Privacy Badger's "local learning" was removed for exactly this reason.((EFF[[https://www.eff.org/deeplinks/2020/10/privacy-badger-changing-protect-you-better|"Privacy Badger Is Changing to Protect You Better"]], October 2020.)) 
-  Adversarial machine-learning methods suggest that if ML blocking becomes popularautomated methods to evade detection will emergeThis is not speculative: Tramèr et al. {[tramer2019_adversarial]} broke perceptual ad blocking outright, and both AdGraph and WebGraph report their own evasion rates. +  * **Evasion is not hypothetical.** Tramèr et al. {[tramer2019_adversarial]} broke perceptual ad blocking outright, and AdGraphWebGraph, Khaleesi and WTAGRAPH all report their own evasion rates — one of them, AdGraph, at 96.62%
-  * Blocking content based on ML increases the chances of breaking websites, especially in non-reproducible ways.+  * **Breaking a site in a way nobody can reproduce is worse than missing a tracker**, and a model gives you no rule to point at when a user complains.
  
-Howeverthese challenges do not limit the application of ML-based detection in research. Several excellent publications have developed robust ML pipelines to detect advertising and privacy-intrusive resourcesmaking them worth considering.+None of that stops you using a learned classifier as a //measurement// instrument, which is what this section is for. **But read the three subsections below as the field's historical baselines, not as recommendations**: the systems this page calls current are in [[#What Came Afterand Why It Matters]].
  
 <WRAP important> <WRAP important>
Line 332: Line 115:
 **Khaleesi: Breaker of Advertising and Tracking Request Chains** {[iqbal2022_khaleesi]} also extends AdGraph, but changes the unit: it classifies **request chains**, which accounted for about one third of all requests in its crawls, reaching 94.07% accuracy on a later dataset than it was trained on. Here is a [[https://github.com/uiowa-irl/Khaleesi|repository with trained model and pipeline]]. **Khaleesi: Breaker of Advertising and Tracking Request Chains** {[iqbal2022_khaleesi]} also extends AdGraph, but changes the unit: it classifies **request chains**, which accounted for about one third of all requests in its crawls, reaching 94.07% accuracy on a later dataset than it was trained on. Here is a [[https://github.com/uiowa-irl/Khaleesi|repository with trained model and pipeline]].
  
-Additionally, it offers a [[https://github.com/uiowa-irl/Khaleesi?tab=readme-ov-file#browser-extension|Firefox extension]] that blocks advertising chains. While not directly suitable for crawls (the current implementation blocks requests), you can disable the functionality [[https://github.com/uiowa-irl/Khaleesi/blob/main/browser_extension/background/background.js#L52|here]] and collect logs to classify ads.+Additionally, it offers a [[https://github.com/uiowa-irl/Khaleesi?tab=readme-ov-file#browser-extension|Firefox extension]] that blocks advertising chains. While not directly suitable for crawls (the current implementation blocks requests), you can disable the functionality by removing the ''return { cancel: true }'' at [[https://github.com/uiowa-irl/Khaleesi/blob/main/browser_extension/background/background.js#L51-L54|background.js lines 51–54]] (checked 2026-08-12: line 52 is the log, 53 is the cancel) and collect logs to classify ads instead.
  
 ==== What Came After, and Why It Matters ==== ==== What Came After, and Why It Matters ====
Line 362: Line 145:
 | **uBlock Origin ''$removeparam''** | Not a separate list: an option used inside its subscribed lists, incl. AdGuard's above. Which lists ship is in [[https://github.com/uBlockOrigin/uAssets|uAssets]] | Cite the underlying list, not "uBlock" | | **uBlock Origin ''$removeparam''** | Not a separate list: an option used inside its subscribed lists, incl. AdGuard's above. Which lists ship is in [[https://github.com/uBlockOrigin/uAssets|uAssets]] | Cite the underlying list, not "uBlock" |
 | **Brave debouncing** | ''brave-lists/debounce.json'' in [[https://github.com/brave/adblock-lists|brave/adblock-lists]] | JSON, typed rules (''redirect'', ''base64,redirect'', ''regex-path''). Solves a related problem — bounce-through redirectors — not parameter stripping | | **Brave debouncing** | ''brave-lists/debounce.json'' in [[https://github.com/brave/adblock-lists|brave/adblock-lists]] | JSON, typed rules (''redirect'', ''base64,redirect'', ''regex-path''). Solves a related problem — bounce-through redirectors — not parameter stripping |
-| **Firefox query stripping** | **No downloadable file.** Delivered by Remote Settings (''query-stripping'' collection), read at runtime by ''nsIUrlQueryStrippingListService''; local override prefs ''privacy.query_stripping.strip_list'' / ''.allow_list''To reproduce Firefox's behaviour you must dump the Remote Settings collection, not grep a repo. Budget for this |+| **Firefox query stripping** | Not in a repository — it is a **Remote Settings** collection, read at runtime by ''nsIUrlQueryStrippingListService''. Fetch it directly: ''https://firefox.settings.services.mozilla.com/v1/buckets/main/collections/query-stripping/records'' returns the ''stripList'' and ''allowList'' as JSON, no auth. Local override prefs are ''privacy.query_stripping.strip_list'' / ''.allow_list''**Much shorter than the others**: 3 records, 23 stripped parameters and 1 allow-listed host on 2026-08-12 (''gclid'', ''fbclid'', ''msclkid'', ''mc_eid'', ''mkt_tok'' …). If you are comparing coverageFirefox is not trying to do the same job as AdGuard's 2,492-rule filter |
 | **ClearURLs rules** | [[https://github.com/ClearURLs/Rules|ClearURLs/Rules]] | Rules data still updated (last push 2026-03-25); the extension itself has not been pushed since 2025-07-27 and a fork, Linkumori, positions itself as the maintained MV3 successor. **Verify the extension's status yourself before treating it as live** | | **ClearURLs rules** | [[https://github.com/ClearURLs/Rules|ClearURLs/Rules]] | Rules data still updated (last push 2026-03-25); the extension itself has not been pushed since 2025-07-27 and a fork, Linkumori, positions itself as the maintained MV3 successor. **Verify the extension's status yourself before treating it as live** |
  
-<wrap todo>Nobody has published a coverage-and-accuracy comparison of these parameter lists against each other, in the way Vallina et al. did for website categorisation services. PURL's own labels came from a union of them plus manual curation, which means the union has never been independently audited. This is a well-scoped, publishable measurement.</wrap>+<WRAP todo>Nobody has published a coverage-and-accuracy comparison of these parameter lists against each other, in the way Vallina et al. did for website categorisation services. PURL's own labels came from a union of them plus manual curation, which means the union has never been independently audited. This is a well-scoped, publishable measurement.</WRAP>
  
 ===== Cookie Notices and Their Interactive Elements ===== ===== Cookie Notices and Their Interactive Elements =====
Line 373: Line 156:
 **The pipeline everyone converges on has three stages, and each has a measured cost.** **The pipeline everyone converges on has three stages, and each has a measured cost.**
  
-  - **Find the notice.** Start with the **EasyList Cookie List** CSS selectors (1,668 network and 22,979 cosmetic rules on 2026-08-12) and add DOM/text heuristics: high ''z-index'', ''position: fixed'', a privacy-related keyword pool, a container that overlaps the viewport bottom or centre.+  - **Find the notice.** Start with the **EasyList Cookie List** CSS selectors ([[Programming:Filter Lists#The lists|current rule counts here]] — it is overwhelmingly cosmeticwhich is what you want for finding a banner) and add DOM/text heuristics: high ''z-index'', ''position: fixed'', a privacy-related keyword pool, a container that overlaps the viewport bottom or centre.
   - **Label the interactive elements.** Accept / reject / close / save / settings / other. Button text is short, multilingual and adversarially designed, which is why this is the stage that moved from keyword lists to learned models.   - **Label the interactive elements.** Accept / reject / close / save / settings / other. Button text is short, multilingual and adversarially designed, which is why this is the stage that moved from keyword lists to learned models.
-  - **Decide what to click, and verify it happened.** A click that silently fails is worse than no click, because the crawl continues and reports pre-consent behaviour as post-consent.+  - **Decide what to click, and verify it happened.** A click that silently fails is worse than no click, because the crawl continues and reports pre-consent behaviour as post-consent. The consent-interaction crawlers the field shares for this — BannerClick, Priv-Accept and the ''autoconsent'' integration built into [[Programming:Crawler:Tracker Radar Collector|Tracker Radar Collector]] — are compared on [[Programming:Crawler#Specialised Measurement Crawlers|the crawler page]].
  
 ^ Study ^ Stage 1 method ^ Stage 2 method ^ Reported performance ^ ^ Study ^ Stage 1 method ^ Stage 2 method ^ Reported performance ^
Line 382: Line 165:
 | Khandelwal et al. {[khandelwal2023automated]}, USENIX Sec 2023 (CookieEnforcer) | Candidate-element extraction, then **BERT** | **T5-Large** predicting the click sequence | 986 of 2,000 domains, 2 false positives and 16 false negatives; **93.7% end-to-end** on 1,000 sites. At scale: notices on **52.7%** of 85,473 sites, 35.4% of them multi-view, and only **21.5%** offering a one-click opt-out | | Khandelwal et al. {[khandelwal2023automated]}, USENIX Sec 2023 (CookieEnforcer) | Candidate-element extraction, then **BERT** | **T5-Large** predicting the click sequence | 986 of 2,000 domains, 2 false positives and 16 false negatives; **93.7% end-to-end** on 1,000 sites. At scale: notices on **52.7%** of 85,473 sites, 35.4% of them multi-view, and only **21.5%** offering a one-click opt-out |
 | Ogut et al. {[ogut2024_dissecting]}, USENIX Sec 2024 | XPath plus privacy-word pools, validated by hand | — | Notices on 37% of loaded sites; the paper to read on **language**, since button text is the classifier's input | | Ogut et al. {[ogut2024_dissecting]}, USENIX Sec 2024 | XPath plus privacy-word pools, validated by hand | — | Notices on 37% of loaded sites; the paper to read on **language**, since button text is the classifier's input |
-| Bouhoula et al. {[bouhoula2024automated]}, USENIX Sec 2024 | EasyList Cookie List plus custom heuristics | **BERT** on 2353 hand-annotated interactive-element texts, six labels | **100.0% precision and 86.9% recall** on notice detection; the element classifier reached **97.6%** accuracy in 5-fold cross-validation, with double annotation agreeing at **Cohen's κ = 91%** |+| Bouhoula et al. {[bouhoula2024automated]}, USENIX Sec 2024 | EasyList Cookie List plus custom heuristics | **BERT** on 2353 hand-annotated interactive-element texts, six labels | **100.0% precision and 86.9% recall** on notice detection; the six-label element classifier reached **95.1% accuracy and F1 90.9%** in 5-fold cross-validation, with double annotation agreeing at **Cohen's κ = 91%** |
 | Demir et al. {[demir2024_bannertools]}, PETS 2024 | Compared existing banner-interaction extensions | — | Each extension interacts with **12 banners on average, 65%** of those shown (SD 21%, min 48%, max 95%) — the number to cite when you justify not using an off-the-shelf extension | | Demir et al. {[demir2024_bannertools]}, PETS 2024 | Compared existing banner-interaction extensions | — | Each extension interacts with **12 banners on average, 65%** of those shown (SD 21%, min 48%, max 95%) — the number to cite when you justify not using an off-the-shelf extension |
-| Tang et al. {[tang2025_navigating]}, USENIX Sec 2025 | Random forest on home pages, 1,000 hand-annotated | — | Global comparison; **96.18% (EU) to 97.72% (US)** of sites had at least one consent violation, and only 3.82% enforced preferences correctly |+| Tang et al. {[tang2025_navigating]}, USENIX Sec 2025 //(a compliance result, listed for its detector)// | Random forest on home pages, 1,000 hand-annotated | — | Global comparison; **96.18% (EU) to 97.72% (US)** of sites had at least one consent violation, and only 3.82% enforced preferences correctly |
  
 <WRAP important> <WRAP important>
Line 398: Line 181:
 Everything in this section comes from a structured extraction over **5,859 full-text papers** from CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf and IEEE S&P, 2010–2026, one record per paper with a verbatim evidence quote per claim. The 2025 and 2026 venue-years are provisional — CCS and IMC 2026 have not been held, and IEEE S&P and WWW 2026 are incompletely selected — so any per-year row reaching them is under-represented by construction. Methodology and limitations are at the end of this section. Everything in this section comes from a structured extraction over **5,859 full-text papers** from CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf and IEEE S&P, 2010–2026, one record per paper with a verbatim evidence quote per claim. The 2025 and 2026 venue-years are provisional — CCS and IMC 2026 have not been held, and IEEE S&P and WWW 2026 are incompletely selected — so any per-year row reaching them is under-represented by construction. Methodology and limitations are at the end of this section.
  
-==== Two search handles, and they barely overlap ====+==== Two search handles, and they only partly overlap ====
  
 There is no single field called "request classification", and if you search for one you will find half of it. The population for this section is built from two independent signals: There is no single field called "request classification", and if you search for one you will find half of it. The population for this section is built from two independent signals:
Line 412: Line 195:
 **Only 42% of the population fires both signals.** That is the practical finding: the filter list has become a general-purpose third-party labelling instrument, reached for by papers on consent, passkeys, WebViews and satellite connectivity that would never describe themselves as tracker-detection work — while a large minority of request classification is done with bespoke heuristics that name no public list at all. **Only 42% of the population fires both signals.** That is the practical finding: the filter list has become a general-purpose third-party labelling instrument, reached for by papers on consent, passkeys, WebViews and satellite connectivity that would never describe themselves as tracker-detection work — while a large minority of request classification is done with bespoke heuristics that name no public list at all.
  
-The second signal needs narrowing, and the narrowing is itself informative. The raw enum value ''classification.target == "web-request"'' fires on **258** papers, but most are not about advertising or tracking+The second signal needs narrowing, and the narrowing is itself informative. The raw enum value ''classification.target == "web-request"'' fires on **258** papers, and **94 of them are not about advertising or tracking at all** — infrastructure and CDN measurementweb-application security, spam and social-network abusebot detection, censorshipbrowser-extension security. The same over-catching happens on the list side: the regular expression that finds "a blocklist" also finds 35 papers using spam, malware, IP-reputation, content-category, censorship or certificate-revocation blocklists, which belong on [[design:website_classification|Website classification]] and [[design:ip_classification|IP classification]]. Every exclusion is named, counted and itemised on [[provenance:privacy:requests|the provenance page]] rather than dropped.
- +
-^ Excluded task family ^ Papers ^ +
-infrastructure, CDN and protocol measurement | 34 | +
-web-application security (XSSCSRF, WAF, HTTP parsing) | 28 | +
-spam, scam and social-network abuse | 18 | +
-bot, crawler and automation detection | 14 | +
-censorship and network interference | 11 | +
-browser extensions (security of the extension itself) | 3 | +
-| no task family matched — inspected by hand, all off-topic | 14 | +
- +
-A paper can match several excluded families, so these do not sum. The same over-catching happens on the list side: the regular expression that finds "a blocklist" also finds 10 malware/phishing,spam/emailIP-reputation, content-category, censorship and 2 certificate-revocation blocklists. Those are namedexcluded and counted rather than dropped — they belong on [[design:website_classification|Website classification]] and [[design:ip_classification|IP classification]].+
  
 ==== Where the papers are ==== ==== Where the papers are ====
Line 436: Line 208:
 | NDSS | 701 | 13 | 1.9% | | NDSS | 701 | 13 | 1.9% |
  
-**PETS is more than six times more likely than NDSS to publish this work** (12.7% of its papers against 1.9%), and PETS plus IMC together carry 43% of it on 20% of the corpus. If you are choosing where to submitor building a reading list, that is the ranking to follow.+**PETS is more than six times more likely than NDSS to publish this work** (12.7% of its papers against 1.9%), and PETS plus IMC together carry 43% of it on 20% of the corpus. **Read that as venue //scope//not as receptiveness**: PETS is a privacy-only venue, so of course this work is a larger share of it, and nothing here says anything about acceptance odds. As a reading-list rankingthough, it is the one to follow.
  
 ^ Period ^ Corpus papers ^ Population papers ^ Per 1,000 corpus papers ^ ^ Period ^ Corpus papers ^ Population papers ^ Per 1,000 corpus papers ^
Line 449: Line 221:
 ==== Which lists the field actually uses ==== ==== Which lists the field actually uses ====
  
-Of the **197** papers that used or produced an advertising-or-tracking filter list. A paper naming several lists is counted under each, so the shares do not sum to 100%. Names were folded into families, because they are free text: the //Spellings folded// column is how many distinct strings the corpus uses for each.+Of the **197** papers that used or produced an advertising-or-tracking filter list. A paper naming several lists is counted under each, so the shares do not sum to 100%. Names were folded into families, because they are free text: the //Spellings folded// column is how many distinct strings the corpus uses for each. [[Programming:Filter Lists#Which lists|The filter-lists page]] computes the same table over a slightly wider population (198 papers, because it does not intersect with this page's request-classification task fold) and is the canonical version; the two differ by one or two papers per row, which is itself a useful illustration of how much a population definition moves a count.
  
 ^ Filter list ^ Papers ^ Share of 197 ^ Spellings folded ^ ^ Filter list ^ Papers ^ Share of 197 ^ Spellings folded ^
Line 542: Line 314:
 ==== Methodology and limitations of these figures ==== ==== Methodology and limitations of these figures ====
  
-  * **How they were produced.** One structured record per paper was extracted from full text, each tuple carrying a verbatim evidence quote and its section. The script that produces every number in this section, with its denominators, is ''report_requests.mjs''; the folding rules are in ''req_fold.mjs''; ''verify_requests_figures.mjs'' re-checks every per-paper figure on this page against the paper's own text. Every query, the scripts' unedited output and the full residue are on [[provenance:privacy:requests]]; corpus-level caveats are on [[literature:corpus]].+  * **How they were produced.** One structured record per paper was extracted from full text, each tuple carrying a verbatim evidence quote and its section. The script that produces every number in this section, with its denominators, is ''report_requests.mjs''; the folding rules are in ''req_fold.mjs''; ''verify_requests_figures.mjs'' re-checks every per-paper figure on this page against the paper's own text. Every query, the scripts' unedited output and the full residue are on [[provenance:privacy:requests|the provenance page for this one]]; corpus-level caveats are on [[literature:corpus]].
   * **The population is a judgement, not an enum.** No field in the extraction means "classifies requests as tracking". S1 and S2 above are proxies, both are folded free text or a hand-written task rule, and both are stated in full on the provenance page so you can disagree with them.   * **The population is a judgement, not an enum.** No field in the extraction means "classifies requests as tracking". S1 and S2 above are proxies, both are folded free text or a hand-written task rule, and both are stated in full on the provenance page so you can disagree with them.
   * **A paper counts once**, never once per tuple, and shares do not sum to 100% because the fields are multi-valued.   * **A paper counts once**, never once per tuple, and shares do not sum to 100% because the fields are multi-valued.
   * **Sentinels are counted as what they are.** ''not-stated'', ''none-reported'' and ''not-applicable'' are never folded into a stated value; where they are the largest row, that is the finding.   * **Sentinels are counted as what they are.** ''not-stated'', ''none-reported'' and ''not-applicable'' are never folded into a stated value; where they are the largest row, that is the finding.
   * **Free-text names were folded before counting.** The residue is printed rather than dropped: 34 distinct strings across 35 tuples matched no list family, and almost all are generic off-topic phrases (''12 IP reputation blacklists'', ''combined public blacklists'', ''eCrimeX blacklist''). The full list is on the provenance page.   * **Free-text names were folded before counting.** The residue is printed rather than dropped: 34 distinct strings across 35 tuples matched no list family, and almost all are generic off-topic phrases (''12 IP reputation blacklists'', ''combined public blacklists'', ''eCrimeX blacklist''). The full list is on the provenance page.
-  * **Every per-paper figure on this page was checked against the paper's own full text**, not against the extraction's summary of it: of 140 literal figures, 138 were found verbatim in ''paper.cols.txt'' and 2 as a listed spelling variant (Matte et al. write ''1 426'' and ''22 949'' with a thin space). That pass caught a real error: the extraction's summary of Rasaii et al. {[rasaii2023_thou]} gives a denominator of "45,222 websites", and **that number is nowhere in the paper**, which says "we crawled 45k websites and found cookiewalls on 280 of them". The page says ~45k. Snyder et al. is a SIGMETRICS paper outside these seven venues, so its 90.16% was verified against the paper directly rather than through the corpus.+  * **Every per-paper figure on this page was checked against the paper's own full text**, not against the extraction's summary of it: of 143 literal figures, 141 were found verbatim in ''paper.cols.txt'' and 2 as a listed spelling variant (Matte et al. write ''1 426'' and ''22 949'' with a thin space). That pass caught a real error: the extraction's summary of Rasaii et al. {[rasaii2023_thou]} gives a denominator of "45,222 websites", and **that number is nowhere in the paper**, which says "we crawled 45k websites and found cookiewalls on 280 of them". The page says ~45k. Snyder et al. is a SIGMETRICS paper outside these seven venues, so its 90.16% was verified against the paper directly rather than through the corpus.
   * **Venue coverage.** Seven venues only. EuroS&P, ACSAC, RAID, AsiaCCS, WPES, CHI and SOUPS are absent, and several works this page relies on were published outside the seven — Snyder et al. at SIGMETRICS, Intumwayase et al. at WPES, and the Vekaria et al. SoK on arXiv. Any count here is a lower bound on a system's standing.   * **Venue coverage.** Seven venues only. EuroS&P, ACSAC, RAID, AsiaCCS, WPES, CHI and SOUPS are absent, and several works this page relies on were published outside the seven — Snyder et al. at SIGMETRICS, Intumwayase et al. at WPES, and the Vekaria et al. SoK on arXiv. Any count here is a lower bound on a system's standing.
   * **Stability.** ''classification.method'' agrees with an independent extraction run on 58% of papers and free-text names on about 20% of exact strings; enum fields such as ''classification.validation'' are considerably more stable. That is why methods are given as rankings and validation as percentages.   * **Stability.** ''classification.method'' agrees with an independent extraction run on 58% of papers and free-text names on about 20% of exact strings; enum fields such as ''classification.validation'' are considerably more stable. That is why methods are given as rankings and validation as percentages.
Line 553: Line 325:
 ===== What to Report ===== ===== What to Report =====
  
-  - **The list, its version and its commit.** ''EasyList Version 202608121614, commit cff91d2b'' — not "EasyList". Archive the ''.txt'' with your artefact. 70% of papers do not do this+  - **The list, its version and its commit**, and the archived ''.txt'' — not "EasyList". 70% of papers give no version at all and 98% give nothing that identifies the rules. [[Programming:Filter Lists#Recording Which List You Used|How, and a script that does it]]
-  - **The engine and its version**, separately from the list. ''adblock'' 0.13.2 and ''adblockparser'' 0.7 do not match the same rulesand the second one silently ignores options it does not know.+  - **The engine and its version**, separately from the list, because two parsers of the same list do not match the same rules and the older ones silently ignore options they do not know. [[Programming:Filter Lists#Post-processing beats blocking at crawl time|Which engines are maintained]].
   - **Which rule kinds you evaluated.** Network only, or cosmetic too? Nearly a third of EasyList is cosmetic and answers a different question.   - **Which rule kinds you evaluated.** Network only, or cosmetic too? Nearly a third of EasyList is cosmetic and answers a different question.
-  - **The unit.** Domain, eTLD+1, URL, chain or parameterand which public suffix list you used to decide party.+  - **The unit, and how you decided "party".** Domain, eTLD+1, URL, chain or parameter — and whether party is by public suffix list (name which one) or by **entity map** (name which one). The two give different third-party rates for the same crawl.
   - **What you did with mixed resources**, given that 48% of hostnames are mixed {[amjad2021_trackersift]}.   - **What you did with mixed resources**, given that 48% of hostnames are mixed {[amjad2021_trackersift]}.
   - **Validation on your own sample.** Hand-label a few hundred requests and report precision against the list. One paper in three reports nothing here.   - **Validation on your own sample.** Hand-label a few hundred requests and report precision against the list. One paper in three reports nothing here.
Line 565: Line 337:
 ===== Open Questions ===== ===== Open Questions =====
  
-<wrap todo>+<WRAP todo>
   * **No independent audit of the tracking-parameter lists exists** (see [[#Link Decoration and Tracking Parameters]]). PURL's ground truth is their union.   * **No independent audit of the tracking-parameter lists exists** (see [[#Link Decoration and Tracking Parameters]]). PURL's ground truth is their union.
   * **Nobody has repeated the filter-list-versus-behaviour comparison on a modern crawl at scale.** Calzavara et al. {[calzavara2026_syntactic]} did it for one taint-tracking browser on 7,614 sites; Fouad et al. {[fouad2020_missed]} did it behaviourally in 2020. The 16%–19% false-positive figure is currently a single data point that a lot of this page leans on.   * **Nobody has repeated the filter-list-versus-behaviour comparison on a modern crawl at scale.** Calzavara et al. {[calzavara2026_syntactic]} did it for one taint-tracking browser on 7,614 sites; Fouad et al. {[fouad2020_missed]} did it behaviourally in 2020. The 16%–19% false-positive figure is currently a single data point that a lot of this page leans on.
Line 571: Line 343:
   * **Python has no maintained filter-list engine.** Someone should either revive ''python-adblock'' against ''adblock'' 0.13.x or state loudly that Python pipelines must shell out.   * **Python has no maintained filter-list engine.** Someone should either revive ''python-adblock'' against ''adblock'' 0.13.x or state loudly that Python pipelines must shell out.
   * **Nothing in this corpus escapes the filter list.** All 8 learned request classifiers train on filter-list labels, Duumviri included. The two directions that come closest — Duumviri's differential features and breakage detector {[shuang2025_duumviri]}, and taint tracking as an independent detector {[calzavara2026_syntactic]} — have each been done once. **A request classifier whose labels come from something other than a list is an open problem, and it is the one this page would most like solved.**   * **Nothing in this corpus escapes the filter list.** All 8 learned request classifiers train on filter-list labels, Duumviri included. The two directions that come closest — Duumviri's differential features and breakage detector {[shuang2025_duumviri]}, and taint tracking as an independent detector {[calzavara2026_syntactic]} — have each been done once. **A request classifier whose labels come from something other than a list is an open problem, and it is the one this page would most like solved.**
-  * **What Manifest V3 did to extension-based measurement.** Lukić and Papadopoulos {[lukic2026_mv3]} found no significant loss of blocking effectiveness under ''declarativeNetRequest'', but the 30,000-rule static cap is well under EasyList'52,557 network rules and nobody has published which rules the shipped MV3 blockers drop, or what that omits from a measurement.+  * **What Manifest V3 did to extension-based measurement.** Lukić and Papadopoulos {[lukic2026_mv3]} found no significant loss of blocking effectiveness under ''declarativeNetRequest'', but the 30,000-rule static cap is well under EasyList's network-rule count ([[Programming:Filter Lists#If your instrument is a browser extension: Manifest V3 caps the rules|current figure here]]) and nobody has published which rules the shipped MV3 blockers drop, or what that omits from a measurement.
   * **Venue coverage is itself an open problem for this topic.** AdVersa {[lim2026_adversa]} at TheWebConf 2026 and Intumwayase et al. {[intumwayase2025_continents]} at WPES 2025 are both squarely in scope and both invisible to the figures above. A reading list built only from the seven venues in this corpus will be incomplete for exactly the most recent work.   * **Venue coverage is itself an open problem for this topic.** AdVersa {[lim2026_adversa]} at TheWebConf 2026 and Intumwayase et al. {[intumwayase2025_continents]} at WPES 2025 are both squarely in scope and both invisible to the figures above. A reading list built only from the seven venues in this corpus will be incomplete for exactly the most recent work.
-</wrap>+</WRAP>
  
 ===== Related Pages ===== ===== Related Pages =====
Line 580: Line 352:
   * [[Programming:Crawler:Tracker Radar Collector|Tracker Radar Collector]] — the lowest-effort crawler for this task, and where the Tracker Radar data comes from.   * [[Programming:Crawler:Tracker Radar Collector|Tracker Radar Collector]] — the lowest-effort crawler for this task, and where the Tracker Radar data comes from.
   * [[Programming:Crawler:PageGraph|Brave PageGraph]] — AdGraph's production successor, and the practical way to get a page-execution graph.   * [[Programming:Crawler:PageGraph|Brave PageGraph]] — AdGraph's production successor, and the practical way to get a page-execution graph.
 +  * [[Programming:Crawler:webXray|webXray and domain-to-company ownership]] — once a request is flagged, this is how to answer //whose// it is, and why webXray, Tracker Radar and Disconnect give three different answers.
   * [[Privacy:JavaScript|Analysing and classifying JavaScript]] — the script-level and function-level end of the granularity ladder.   * [[Privacy:JavaScript|Analysing and classifying JavaScript]] — the script-level and function-level end of the granularity ladder.
   * [[Privacy:Cookies|Cookies]] and [[Privacy:Fingerprinting|Fingerprinting]] — the other two things a "tracking" label is often about.   * [[Privacy:Cookies|Cookies]] and [[Privacy:Fingerprinting|Fingerprinting]] — the other two things a "tracking" label is often about.
 +  * [[Privacy:Cookie syncing|Measuring cookie and ID syncing]] — the exchange that makes those identifiers joinable across parties, and the reason the link-decoration section above exists.
   * [[Privacy:Consent|Granting consent to websites]] — what the cookie notice means, once you have found it.   * [[Privacy:Consent|Granting consent to websites]] — what the cookie notice means, once you have found it.
   * [[Design:Website Classification|Website classification]] — and the measured reason **not** to use a categorisation service to find trackers.   * [[Design:Website Classification|Website classification]] — and the measured reason **not** to use a categorisation service to find trackers.
privacy/requests.1786553760.txt.gz · Last modified: by karel.kubicek.claude

Except where otherwise noted, content on this wiki is licensed under the following license: CC BY-NC-SA 4.0
CC BY-NC-SA 4.0 Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki