This is an old revision of the document!
Table of Contents
Provenance: Programming:Crawler:webXray
Working notes behind Programming:Crawler:webXray: every query with its population and denominator, the scripts and their unedited output, the folds and their residue, the quotes spot-checked, the external sources verified and the ones rejected, what could not be established, and the judgement calls. Corpus-level caveats — venue scope, the selection funnel, extraction stability — are on corpus and are not restated here.
This page is a working log, not prose. It is read by someone checking a number.
The run
| Date | 2026-08-17 |
| Corpus | data/extract/run1/extractions.jsonl, 5,859 extracted papers, 7 venues, 2010–2026. Baselines used: 1,120 papers ran a crawl; 4,439 classified something |
| Page status | new. programming:crawler:webxray was a red link promised by Crawler since that page was written |
| Scripts written | scripts/report_webxray.mjs (corpus), scripts/owner_dbs.py (live database comparison, published in full on the page), scripts/owner_adjudication.py (hand adjudication), pages/owner_lookup.py (the lookup demo published on the page), scripts/wx_context.py (sentence extraction for hand verdicts), scripts/build_provenance_webxray.py (this page) |
| Scripts written (guards) | scripts/check_attributions.mjs — asserts every “Name et al., VENUE YEAR” on a page matches the author field of the key cited beside it. Written because a draft of this page attributed NDSS 2025's App Privacy Report paper to “Kariryaa et al.” when its first author is Xiaoyuan Wu, and every other check on the page passed: the key resolved, the bibliography rendered, and the figure was real. 15 of 15 attributions pass now; programming:crawler:pagegraph passes 8 of 8 as a regression check |
| Scripts changed | scripts/check_page_numbers.mjs — its semver-triple check now consults ALLOW. Tracker Radar's release tags (2026.07.27) are date-shaped triples from a vendor page, so they could never appear in a corpus report and were reported as stale forever |
| Bibliography | pages/bib_additions_webxray.bib, 15 new entries + 1 hand-written arXiv entry. One generated key (selmo2025_borges) was already present and was deleted from the additions before appending |
| Models | Opus 5 wrote the page, the scripts and the folds. Three Sonnet sub-agents ran in parallel: corpus reading of the 15 webXray papers, external primary-source verification, and the 30-row ownership adjudication. Their findings were re-checked rather than trusted — see *Sub-agent findings that did not survive* below |
Scope decision: create, extend, or broaden a neighbour?
Created, and deliberately broadened beyond its title. The narrow reading of “webXray” is a dead tool with 15 corpus mentions and one paper that ran it — not enough for a page a reader would benefit from. The item asked for “its domain-owner database and how that compares to Tracker Radar and Disconnect”, and that comparison is the page: domain-to-company ownership resolution has no other page on the wiki, 136 corpus papers touch it, and a fresh PhD student arriving from an adjacent topic needs to be told which list to use now, not which tool is dead.
Alternatives considered and rejected:
- A separate
design:ownership_resolutionpage with webXray as a stub. Rejected: it would leave the wiki's existing red link pointing at a stub, and the material does not split cleanly — webXray's frozen list is the best available illustration of what goes wrong. - Folding this into Requests. Rejected: that page is about “is this request a tracker?”, which is a different question with different tooling (filter lists, not owner databases). The pages cross-link instead.
- Correcting Crawler only. That page's webXray paragraph is now wrong in two ways (see below) and does need fixing, but a corrected paragraph cannot carry a measured three-way comparison.
Corrections owed to Programming:Crawler
The parent page's webXray paragraph, written 2026-08-06, says: “What survives on GitHub are stale third-party mirrors, the newest of which was last pushed in 2015 and targets PhantomJS”, and carries <wrap todo>If you know where webXray is currently developed, please correct this.
Both parts are wrong or now answerable:
thezedwards/webXraywas pushed 2021-03-04 and is webXray 3.x, which drives consumer Chrome over raw CDP (webxray/ChromeDriver.pyimportscreate_connectionfromwebsocket;requirements.txtpinswebsocket-client==0.57.0and nothing browser-related). The 2015 PhantomJS copy (agilemobiledev/webXray) is not the newest survivor. The earlier check appears to have searched GitHub and taken the first mirror it found.- webXray is currently developed — commercially, at webxray.ai, by webXray LLC, with Libert as founder and CEO. The
<wrap todo>can be closed.
The parent page also lists webXray's crawler as “PhantomJS (historically)”, which is right for the 2015 paper and wrong for the last public version. TODO for a follow-up sitting: apply these three corrections to programming:crawler and remove its <wrap todo>. Not done in this sitting because the item's scope was this page.
A. Corpus queries
All from scripts/report_webxray.mjs. Every count is of papers, never tuples.
| # | Question | Query | Population | Result |
|---|---|---|---|---|
| A1 | How many papers use webXray, per the extraction? | tools[].name matching /webx[\s-]?ray/i with usedOrMentioned ∈ {used, produced} | 5,859 extracted papers | 7 |
| A2 | …and per the full text? | same regex over paper.cols.txt, whitespace-normalised | 5,859 | 15 |
| A3 | Do the two signals nest? | set difference both ways | — | schema ⊂ sweep; sweep finds 8 the schema misses; 0 the other way |
| A4 | Which spellings? | distinct tools[].name values | 7 papers | webxray (3), webXray (2), WebXRay (1), WebXray (1). Fold residue 0 |
| A5 | What role does webXray play in each? | ROLE hand map, one deciding quote per paper | 15 | owner-list-only 7, citation 4, instrument 1, compared 1, subject 1, miscitation 1 |
| A6 | How many actually ran it or read its list? | role ∈ {instrument, owner-list-only} | 15 | 8; of those 7 list-only, 1 crawler |
| A7 | Which snapshot of the list did they use? | SNAPSHOT hand map over the 8 | 8 | 2 say anything; 1 names a commit |
| A8 | Per-year and per-venue shape | year/venue of the 15 | 15 | last use of crawler-or-list: 2022 |
| A9 | Which ownership resources does the corpus name at all? | six full-text sweeps | 5,859 | PSL 101, Disconnect-as-a-list 74, Tracker Radar 32, WhoTracks.me 23, Crunchbase 23, webXray 15 |
| A10 | Union of the five owner databases | union of A9 rows minus the PSL row | 5,859 / 1,120 crawled | 136 (2.3% / 12.1%) |
| A11 | Which Tracker Radar artefact did each of the 32 use? | TR_ROLE hand map | 32 | ownership 11, tracker/category 9, Collector crawler 9, citation 2, compared 1 |
| A12 | Ownership use of Tracker Radar over time | year of the 11 | — | 2021:1, 2023:2, 2024:1, 2025:4, 2026:3 |
Both hand maps are checked against their sweep at run time and the script prints FAILURE if a paper appears in one and not the other. Residue is 0 in both directions for this run.
A.13 Why the population is a full-text sweep, not the schema
The other crawler pages on this wiki take their population from tools[]. This one cannot: the schema finds 7 papers and the sweep finds 15, and the eight it misses are exactly the distinction the page is about — a paper that cites webXray in its reference list is not a paper that used it. Merging the two signals into one “webXray papers” count would have produced a number that means nothing. They are reported separately and each of the 15 carries a hand verdict.
A.14 Sweep patterns, and the one that had to be tightened
/disconnect/i matches 700 papers (a plain grep -ril gives 697; the sweep normalises whitespace first and catches three more across a column break), almost none of which mean the list — “disconnect” is a common English word and the CSP literature uses it as a technical term ([1Steffens, Marius; Musch, Marius; Johns, Martin; Stock, Ben (2021): "Who’s Hosting the Block Party? Studying Third-Party Blockage of CSP and SRI", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] measures “the disconnect of code”). The sweep therefore requires a list sense: /disconnect'?s? (entit|list|block|black|tracking)|disconnect\.me|entities\.json/i → 74. That is still an upper bound and the page says so. A sub-agent independently hit the same problem and reported that a looser “disconnect near entit” co-occurrence gave “a useless 481”.
The webXray pattern allows a space or hyphen (web xray, web-xray) because the .cols repair can insert one at a column boundary. It found no additional papers, which is itself worth recording: there is no fork under another name in the corpus.
A.15 Figures verified against the source, not against the extraction
prevalence strings in the extraction are a model summary of a paper's result, so every literal per-paper figure on the page is checked against the paper's own paper.cols.txt by regex. 26 of 26 located. The list, its regexes and its results are in section G of the report output below.
A.16 Evidence quotes spot-checked
The 16 evidence.quote values behind the webXray tool and classification tuples, checked by 4-word-window coverage against paper.cols.txt: 4 exact, 11 partial (≥60% of windows), 1 below threshold. Full list in section H of the report output.
The one below threshold is [2Musa, Maaz Bin; Nithyanand, Rishab (2022): "ATOM: Ad-network Tomography", in: Proceedings on Privacy Enhancing Technologies. (DOI)] at 58%: “We used external data sources including WHOIS records, TLS certificates, and WebXray [61] to identify the parent organizations of each identified tracker.” Read by hand in the source: present and verbatim; the .cols rendering splices an adjacent column through it. Below-threshold is not “unsupported”.
Every Name et al., VENUE YEAR attribution in the 15-row table was also checked mechanically against the author field of the BibTeX key cited beside it, matching the first author's surname. 15 of 15 pass now; one failed on the first run (see *Sub-agent findings that did not survive*, last row).
Additionally hand-read in full, because the page quotes them at length or leans on them:
| Paper | What was checked | Verdict |
|---|---|---|
| [3Libert, Timothy (2018): "An Automated Approach to Auditing Disclosure of Third-Party Data Collection in Website Privacy Policies", in: Proceedings of the ACM Web Conference. (DOI)] | the author's own coverage limitation, “primarily contains major ad networks rather than small clients” | present; the sentence is interleaved with Table 1 in the .cols rendering, so the page quotes it with the table text removed and no words changed |
| [4Sánchez-Rola, Iskander; Dell'Amico, Matteo; Balzarotti, Davide; Vervier, Pierre-Antoine; Bilge, Leyla (2021): "Journey to the Center of the Cookie Ecosystem: Unraveling Actors' Roles and Relationships", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)] | the priority order, the 3,913 figure, the “one single conflict”, the Disconnect bug report | all present verbatim |
| [1Steffens, Marius; Musch, Marius; Johns, Martin; Stock, Ben (2021): "Who’s Hosting the Block Party? Studying Third-Party Blockage of CSP and SRI", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] | 2,175 → 1,146 pairs, eight person-hours, 133 additional relations, the twitch.tv example | all present verbatim |
| [5Matte, Célestin; Bielova, Nataliia; Santos, Cristiana Teixeira (2020): "Do Cookie Banners Respect my Choice? Measuring Legal Compliance of Banners from IAB Europe's Transparency and Consent Framework", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)] | “Disconnect list commit eb817fb1 (2019-12-10) WebXRay commit 04c3c8e8 (2019-06-18)” | present verbatim, in the reproducibility table |
| [6Yang, Zhiju; Yue, Chuan (2020): "A Comparative Measurement Study of Web Tracking on Mobile and Desktop Environments", in: Proceedings on Privacy Enhancing Technologies. (DOI)] | 411 of 762, and the five WHOIS-proxy strings in the top-10 table | present; the 88 total is arithmetic done on the page (34+25+14+8+7) and is labelled as such |
| [7Jakaria, Md; Huang, Danny Yuxing; Das, Anupam (2024): "Connecting the Dots: Tracing Data Endpoints in IoT Devices", in: Proceedings on Privacy Enhancing Technologies. (DOI)] | that reference [28] resolves to Held 1998 | present verbatim in the reference list |
| [8McQuistin, Stephen; Snyder, Peter; Perkins, Colin; Haddadi, Hamed; Tyson, Gareth (2023): "A First Look at the Privacy Harms of the Public Suffix List", in: Proceedings of the ACM Internet Measurement Conference. (DOI)] | timlib/webXray 27 in the frozen-PSL table | present |
| [9Englehardt, Steven; Narayanan, Arvind (2016): "Online Tracking: A 1-million-site Measurement and Analysis", in: Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, pp. 1388–1401. Association for Computing Machinery, New York, NY, USA. (DOI) (Link)] | the PhantomJS criticism | present verbatim |
| [10Utz, Christine; Amft, Sabrina; Degeling, Martin; Holz, Thorsten; Fahl, Sascha; Schaub, Florian (2023): "Privacy Rarely Considered: Exploring Considerations in the Adoption of Third-Party Services by Websites", Proceedings on Privacy Enhancing Technologies 2023(1):5-28. (DOI)] | “categorizations differ in granularity and focus” | present verbatim |
| [11Jannett, Louis; Mayer, Andreas; Westers, Maximilian; Mladenov, Vladislav; Mainka, Christian; Schwenk, Jörg (2026): "The State of Passkeys: Studying the Adoption and Security of Passkeys on the Web", in: Proceedings of the USENIX Security Symposium. (Link)] | the Entity Map used so gmail.com and google.com are not counted as separate authentication systems | present verbatim |
| [12Selmo, Carlos; Carisimo, Esteban; Bustamante, Fabián E.; Alvarez-Hamelin, J. Ignacio (2025): "Learning AS-to-Organization Mappings with Borges", in: Proceedings of the 2025 ACM Internet Measurement Conference, pp. 120-133. (DOI)] | “an Internet shaped by constant mergers, rebrandings, and regional variation” | present, but column-spliced in the .cols rendering: the words are interleaved with the adjacent column, so a naive substring search fails on part of it. The phrase is the paper's own and the page quotes only the contiguous part |
| [13Wu, Xiaoyuan; Hu, Lydia; Zeng, Eric; Habib, Hana; Bauer, Lujo (2025): "Transparency or Information Overload? Evaluating Users’ Comprehension and Perceptions of the iOS App Privacy Report", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] | “the webXray list includes information on domain ownership, allowing distinction between first- and third-party domains” | present verbatim |
A.17 A figure deliberately NOT published
[1Steffens, Marius; Musch, Marius; Johns, Martin; Stock, Ben (2021): "Who’s Hosting the Block Party? Studying Third-Party Blockage of CSP and SRI", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] contains: “Contrarily, webXray's list does account for 1,096 of our 1,146 found connections meaning that it alone does not suffice for our purposes.”
1,096 of 1,146 is 95.6% coverage, which contradicts “does not suffice”, contradicts the same paragraph's complaint that the curated lists “frequently miss connections among two hostnames”, and contradicts webXray having contributed only 133 relations. The most likely reading is a dropped “not” in the published text. Checked in three renderings — paper.cols.txt (line 417), paper.txt (line 278, the pre-repair extraction) and the PDF's own text layer — and all three read the same, so this is the paper as published and not a column-repair artefact.
Decision: publish no coverage percentage from this sentence. The page quotes the unambiguous parts of the paragraph instead (2,175 candidates, 1,146 confirmed, ~8 person-hours, 133 additional relations, “it alone does not suffice”). A sub-agent reported the 95.6% reading as a headline finding; it was not used. Someone with access to the authors could settle it; that would be worth doing.
A.18 A miscitation, recorded as a fact and not as an accusation
[7Jakaria, Md; Huang, Danny Yuxing; Das, Anupam (2024): "Connecting the Dots: Tracing Data Endpoints in IoT Devices", in: Proceedings on Privacy Enhancing Technologies. (DOI)] writes “Some tools like WebXray [28] provide this information; however, WebXray targets web servers…” and its reference [28] is “Gilbert Held. 1998. Cinco Network's WebXRay. International Journal of Network Management 8, 4 (1998), 254-261.” The described tool is Libert's; the cited work is a 1998 network-management product review. Both halves were read in the source. This is on the page as a hand verdict of miscitation and as a warning that a full-text sweep for a tool name needs the citing sentence read — which is the methodological point, and the only reason it is mentioned.
B. The live database comparison
scripts/owner_dbs.py. Fetches each list, hashes the exact bytes, prints every figure with its denominator and every fold's residue. Snapshot hashes for this run are in the output below; quote them with any figure.
| # | Question | Method | Result |
|---|---|---|---|
| B1 | How big is each list? | count records and distinct domains | webXray 827/3,215; Tracker Radar 19,148/38,368; Disconnect 1,887/7,850 |
| B2 | How deep is webXray's tree? | walk parent_id with a cycle guard | 319 of 827 have a parent; depths 1:508 2:211 3:80 4:24 5:2 6:2; 2,175 of 3,215 domains (67.7%) have leaf ≠ root |
| B3 | How much of webXray's schema is filled? | per-field non-empty count | country 826 (99.9%), platforms 803 (97.1%), uses 761 (92.0%), site policy URLs 591 (71.5%), GDPR 132 (16.0%), trade_groups 104 (12.6%), crunchbase_id 34 (4.1%), opt_out_urls 13 (1.6%), ccpa_urls 4 (0.5%) |
| B4 | What is the universe of third-party domains? | Tracker Radar domain_summary.json, folded to eTLD+1 with the ICANN section of the live PSL | 47,836 rows → 32,369 registrable domains (the ICANN+PRIVATE fold gives 45,525); 16,396 rows were hostname-keyed; 19 rows dropped as not hostnames |
| B5 | Coverage, unweighted | domains in the universe the list can name, parent labels walked | webXray 669 (2.1%), Tracker Radar 5,581 (17.2%), Disconnect 2,268 (7.0%) |
| B6 | Coverage, prevalence-weighted | Σ prevalence of covered ÷ Σ prevalence of all | webXray 58.6%, Tracker Radar 84.3%, Disconnect 80.5% |
| B6b | How much does the fold/lookup rule move it? | all four combinations of ICANN-vs-full fold and walk-vs-exact lookup | weighted coverage spans 54.5–59.7% (webXray), 79.3–84.8% (TR), 75.8–80.6% (Disconnect). The rule moves the answer by more than the lists differ. |
| B7 | Head versus tail | coverage of the top 100 / 1,000 / 10,000 by prevalence | 71/26/5, 98/69/29, 94/68/17 |
| B8 | Pairwise agreement | owner strings after a legal-suffix fold | disagreement 32.4% / 46.8% / 38.0% (see the page table) |
| B9 | Does resolving webXray's tree help? | repeat B8 with root owners | disagreement rises to 39.1% and 49.6% |
| B10 | What does nobody cover? | universe minus webXray minus Disconnect | 29,896 (92.4%) of domains, 14.4% of prevalence weight; the top row is tiktokw.us at 0.041, which only Tracker Radar names |
B.11 Folding: what was folded, the rule, and the residue
One fold only: legal-form suffixes on company names. SUFFIXES is an explicit list — inc, llc, ltd, limited, plc, corporation, corp, company, co, gmbh, ag, kg, sa, sas, sarl, srl, spa, bv, nv, ab, as, oy, aps, sro, pty, pte, pvt, kk, kabushiki kaisha, holdings, holding, sl and a few spellings of those — applied repeatedly until stable, because “Foo Co., Ltd.” needs two passes.
Deliberately not folded: group, media, technologies, digital, networks, solutions. Each is part of a real company name often enough (“Almondnet Group”, “Zeta Global”, “Lotame Solutions”) that stripping it would manufacture agreement between lists that name different companies. Also no synonym merging at all: “Facebook” is not folded to “Meta”, “DoubleClick” is not folded to “Google”. That is the whole point — those are the disagreements being measured.
Residue, printed in full by the script: the fold leaves 782 of webXray's 827 owner names untouched (94.6%), i.e. it fires on 45. That is the intended behaviour and its consequence is stated on the page: every “agree” figure is a lower bound on real agreement and every “disagree” figure an upper bound on real disagreement. A synonym-merging fold would move the numbers in a direction the script cannot justify, so it was not written.
The second normalisation is the PSL fold on the universe (B4). Its residue is printed as the 19 dropped rows, listed individually: 18 bracketed IPv6 literals and the literal string “null” with prevalence 0.024 and a full behaviour profile attached. A row that is not a hostname is not a domain; it is printed rather than silently dropped.
B.12 Two denominator choices that change the answer
- The PSL's ICANN/PRIVATE split, and exact-key versus parent-label lookup. This is the choice that moves the answer most, and the first version of this script got it wrong in both halves at once — see the reviewer log below.
googleapis.comis a PRIVATE rule, so folding with the private section leavesfonts.googleapis.com(prevalence 0.369) standing as its own registrable domain, and an exact-key lookup then reports it unowned although all three lists namegoogleapis.com. The script now prints all four combinations; the recommended rule is an ICANN-section fold, and with that fold every key already is a registrable domain so the parent walk is a no-op — which is the cleanest possible confirmation that the fold, not the lookup, is the fix. - Do not use Tracker Radar's
entity_map.jsonordomain_map.jsonas the universe. That is Tracker Radar's answer key and scores it at 100% by construction.domain_summary.jsonis a crawl result and is a defensible universe — while still Tracker Radar's own view of the web, which the page states wherever a coverage figure appears. There is no neutral census of third-party domains; if one existed this comparison would use it. - A registrable domain's weight is the maximum prevalence among its hostnames, never the sum. One site can request
fonts.googleapis.comandajax.googleapis.com, so summing double-counts sites and can exceed 1. Using the max makes every weighted figure a conservative lower bound, and the script says so in a comment at the line that does it.
B.13 The lookup demo published on the page
pages/owner_lookup.py is published on the content page as downloadable code. It was run before publication against the same cached snapshots owner_dbs.py used, and the output on the page is that run's real output, unedited. Its four example domains were chosen to hit one lesson each: a pure granularity difference (doubleclick.net), a pure vintage difference (adnxs.com), a disagreement between the two live lists (facebook.net), and a domain no list covers (fonts.googleapis.com).
The paths in the published copy say cache/… where the local copy reads out/webxray/cache/…, which is the only difference between them.
B.14 Cross-check of one figure by hand
doubleclick.net has prevalence 0.4456 in domain_summary.json and is the highest-prevalence disagreement between webXray (“DoubleClick”) and Tracker Radar (“Google LLC”). Checked by hand: it is in webXray's domains array under owner doubleclick, whose parent_id chain is doubleclick → google → alphabet. So the page's claim that resolving to the root yields “Alphabet” against “Google LLC” is read off the file, not inferred.
C. The hand adjudication
scripts/owner_adjudication.py holds 30 rows: domain, the owner a primary source confirms for today, the date ownership changed, the source URL, and one verdict per list from {current, stale, granularity, error, absent}.
Sourcing bar: a company newsroom or press release, an SEC filing, or the domain's own legal document (privacy policy, imprint, data-processing agreement). Wikipedia, Crunchbase summaries, PitchBook, Tracxn and “list of ad-tech acquisitions” pages were used only to locate leads and never cited. Where only trade press could be found the row is marked UNRESOLVED and is excluded from every tally — 2 of 30, leaving 28. That exclusion was not in the first version, and it mattered: 2 of webXray's 3 “current” verdicts were exactly those two rows, so the figure most favourable to webXray rested on the evidence the script itself called insufficient. Corrected tallies: webXray current on 1 of 23 entries, Tracker Radar 8 of 28, Disconnect 21 of 21.
The selection bias, stated because it is the main limitation: these are the disagreements with the highest Tracker Radar prevalence, not a random sample. They are chosen precisely where the lists differ, so the tallies are not an error rate for any list — a random sample would be dominated by domains all three get right. What they do establish is the shape of the disagreement: concentrated in acquisitions and renames, pointing overwhelmingly one way, with the most conservatively regenerated list being the least current. The script prints this warning above its own tallies and the page repeats it in a <WRAP important>.
C.1 Rows where the reviewer's hypothesis was wrong
Two rows were sent to adjudication flagged as “looks like a Disconnect error”. Both came back the other way:
postrelease.com→ Disconnect says “Life360”, which looked absurd next to webXray's and Tracker Radar's “Nativo”. Life360's own newsroom records the acquisition of Nativo as completed 2026-01-05. Disconnect is current; the other two are seven months stale.crwdcntrl.net→ Disconnect says “PublicisGroupe” against “Lotame”. Publicis' own press release (2025-03-06) and Lotame's own “one year post-acquisition by Publicis” post confirm it. Disconnect is current.
Recorded because the initial reading was mine and it was wrong. The lesson is on the page: do not assume the outlier is the error.
C.2 Rows scored as an error rather than staleness
jsdelivr.net— Tracker Radar says “Prospect One”. jsDelivr's own data-processing agreement (jsdelivr.com/documents/data-processing-agreement.pdf) names Volentio JSD Limited. Prospect One's own portfolio page describes build and infrastructure work for jsDelivr, not ownership.stackadapt.com— Tracker Radar says “Collective Roll”, which is StackAdapt's own pre-2014 founding name, not a distinct owner.1rx.io— webXray's root is “Marimedia”, which no primary source corroborates. Weaker evidence than the other two and labelled as such in the script's comments.
D. External sources: verified, and rejected
Every external claim on the page, with how it was checked. All checks 2026-08-17.
| Claim on the page | How verified |
|---|---|
github.com/timlib/webXray → 404 | curl -o /dev/null -w '%{http_code}' https://api.github.com/repos/timlib/webXray → 404 |
github.com/timlib/webXray_Domain_Owner_List → 404 | same method → 404 |
the timlib account still exists with 0 public repos | api.github.com/users/timlib → 200, public_repos: 0, company: “webXray.ai”, blog: “https://timlibert.me” |
webxray.org is a placeholder | fetched; body is a heading and one line, “Public interest projects for the interested public.” No source link, no version, no download |
| no PyPI package | pypi.org/pypi/{webxray,web-xray,policyxray}/json → 404 each |
thezedwards/webXray last pushed 2021-03-04, 19 forks, newest fork activity 2023-03-12 | GitHub API repo + /forks?per_page=100 |
the surviving README still says git clone https://github.com/timlib/webXray.git | fetched raw.githubusercontent.com/thezedwards/webXray/master/README.md |
| PolyForm Strict License 1.0.0, no redistribution, noncommercial permitted incl. research organisations | fetched LICENSE.md from the same repo and read the licence text itself, not a summary |
| PolyForm Strict 1.0.0 is still the current version and has no SPDX identifier | polyformproject.org/licenses lists strict/1.0.0 and no later Strict version; SPDX's own license-list-data JSON carries only PolyForm-Noncommercial-1.0.0 and PolyForm-Small-Business-1.0.0 |
| raw CDP, no Selenium | webxray/ChromeDriver.py imports create_connection from websocket; requirements.txt pins lxml==4.6.2, psycopg2-binary==2.8.6, textstat==0.7.0, websocket-client==0.57.0 |
| the bundled PSL patch header “current as of 20160428” | fetched webxray/resources/pubsuffix/ccSLD-patches.txt |
| the PSL's own warning against frozen copies | publicsuffix.org/learn/ |
RDBinns/webXray_Domain_Owner_List is GPL-3.0, all commits 2018-04-05, older schema | GitHub API (license.spdx_id: GPL-3.0) plus its README, which documents owner_name where the in-tool file has name and has no uses/platforms/trade_groups |
webxray.ai is a commercial litigation product; Libert is founder and CEO | fetched both webxray.ai and timlibert.me. The latter states verbatim: “(Dr.) Timothy Libert is founder and CEO of webXray LLC.” |
| Tracker Radar last commit 2026-08-12, monthly release tags, CC BY-NC-SA 4.0 | GitHub API pushed_at; /releases; LICENSE and README |
| Tracker Radar's method and “handled internally” | docs/DATA_MODEL.md and docs/FAQ.md in the repository |
| Disconnect last commit 2026-08-07, CC BY-NC-SA 4.0, GPL-3.0 until 2020-06-24 | GitHub API; then the commit history of LICENSE — GPLv3 in the initial commit 89d421e8 (2015-10-13), rewritten to CC BY-NC-SA by two commits on 2020-06-24 |
Firefox ships Disconnect's services.json via Mozilla's shavar-prod-lists | mozilla-services/shavar-prod-lists README: Firefox's ETP “rely on lists of trackers maintained by Disconnect… Mozilla does not maintain these lists”; disconnect-blacklist.json is “a version controlled copy of Disconnect's list of trackers” |
Ghostery trackerdb 2026-08-06, CC BY-NC-SA 4.0; WhoTracks.me data repo 2026-08-04 (“July update”); whotracks.me now redirects to ghostery.com/whotracksme | GitHub API on ghostery/trackerdb and whotracksme/whotracks.me (the ghostery/whotracks.me path 301s); followed the site redirect. The licence is from the repo's own LICENSE and package.json (“license”: “CC-BY-NC-SA-4.0”), not the GitHub API, which returns no SPDX id — a first pass read “MIT” off the API and was wrong |
| WhoTracks.me paper is arXiv 1804.08959, v2 revised 2019-04-25 | export.arxiv.org/api/query?id_list=1804.08959 — title, authors and updated field read from the Atom response |
| Crunchbase API is paid | api.crunchbase.com/api/v4/… → HTTP 401 “Unauthorized user_key” |
| PhantomJS is dead | api.github.com/repos/ariya/phantomjs → archived: true, last push 2022-11-26 |
| Disconnect assigns ownership “through DNS, WHOIS, and behavioral evidence”; corrections are not taken by pull request | fetched disconnect.me/trackerprotection (the six-step process page) and disconnect.me/domain_evaluations; the repository README says verbatim “Pull requests are not reviewed and will be closed” |
Disconnect's own headline count differs from entities.json | disconnect.me/trackerprotection claims “14,332 Verified domains and entity mappings”; entities.json holds 7,850. The page tells the reader to count the file they read rather than quote the vendor's number |
D.1 Sources rejected
- Every “top web privacy tools” listicle and blog roundup surfaced while looking for webXray's current home. None was used. The tool's status was established from GitHub API responses, PyPI 404s, the licence file and the author's own two websites.
- Wikipedia, Crunchbase profiles, PitchBook and Tracxn for the 30 acquisitions. Used to find which press release to look for; never cited. Two rows where only trade press existed are marked
UNRESOLVEDinstead of being filled from it. toolness/webxray(Mozilla's Web X-Ray Goggles, 2010–2013) — a genuinely different project that shares the string. Checked and excluded, because a name search finds it first: GitHub's repository search for “webxray” returns 18 repositories, of which the majority are unrelated (X-Ray Goggles, an X-ray physics database, an offensive web scanner, a Shopify evaluator). Recorded here so the next run does not include it.- Cinco Network's WebXRay (Held, IJNM 1998) — the homograph [7Jakaria, Md; Huang, Danny Yuxing; Das, Anupam (2024): "Connecting the Dots: Tracing Data Endpoints in IoT Devices", in: Proceedings on Privacy Enhancing Technologies. (DOI)] cites. Excluded from the tool discussion; mentioned only as the miscitation it is.
carlsaturnino/webxray-dockeron Docker Hub (399 pulls,last_modified2024-10-16) was not presented as a maintained image: the timestamp is a metadata bump on an image registered 2016-04-26, andhub.docker.com/v2/repositories/carlsaturnino/webxrayand…/timlib/webxrayboth 404. The page says no maintained image exists.
E. What could not be established
- When
github.com/timlib/webXrayfirst returned 404, and whatwebxray.orgused to contain.web.archive.orgwas returning 502/503 for the whole of 2026-08-17 (nine attempts, two independent fetch paths, ~30 minutes apart). Both questions are marked unknown on the page rather than estimated. What would close it: re-run the Wayback queries when the Archive is up —http://archive.org/wayback/available?url=github.com/timlib/webXray×tamp=2022and the same forwebxray.org. The only bracket available now is indirect: forks show a merge of atimlib-owned branch as late as 2022-06-28, so upstream was still reachable then. - Whether a paper documents policyXray specifically, as distinct from the module description in webXray's README. Not settled; scholarly indices were not searched exhaustively. [3Libert, Timothy (2018): "An Automated Approach to Auditing Disclosure of Third-Party Data Collection in Website Privacy Policies", in: Proceedings of the ACM Web Conference. (DOI)] is the closest thing and is what the page cites.
- Whether DuckDuckGo has published a paper on Tracker Radar's methodology. Nothing found; the documentation is repo-native plus a vendor blog post. The page says “no paper” on that basis, which is an absence-of-evidence claim and is phrased as one.
- What
propertiesversusresourcesmeans in Disconnect'sentities.json. Not documented anywhere in the repository — not in the README, the LICENSE orDomain evaluations.md. Empirically most entities have identical arrays, and some diverge (24TTL:properties: [“24ttl.net”]vsresources: [“24ttl.stream”]). The page reports both counts and tells the reader to state which key they read, rather than asserting a definition the vendor does not document. - The
1,096 of 1,146sentence in [1Steffens, Marius; Musch, Marius; Johns, Martin; Stock, Ben (2021): "Who’s Hosting the Block Party? Studying Third-Party Blockage of CSP and SRI", in: Proceedings of the Network and Distributed System Security Symposium. (Link)] — see A.17. Unresolvable from the text. - The list-age and missing-hostname columns for
timlib/webXrayin [8McQuistin, Stephen; Snyder, Peter; Perkins, Colin; Haddadi, Hamed; Tyson, Gareth (2023): "A First Look at the Privacy Harms of the Public Suffix List", in: Proceedings of the ACM Internet Measurement Conference. (DOI)]'s table. The.colsrendering splits that table into separate column runs and the numeric columns cannot be aligned to the repository names reliably. Only the verifiable part is on the page — that webXray appears in the table, in the “Production” category, with 27 stars. What would close it: read the published PDF's table directly. - Whether any non-numeric claim on this page has drifted from its script.
check_page_numbers.mjscompares numerals only, so when a reviewer's fix changed “third of four” to “second of four” on the page, the hand map in the script and its committed output kept saying “third” and every guard still passed. The same happened with “MIT” for Ghostery's licence. Both were caught by a human reviewer reading the two side by side, not by a tool, and no tool here covers that class.check_attributions.mjscloses one narrow case of it (author names). What would close the rest: a guard that extracts the quoted strings a page attributes to a script's hand map and diffs them against the map. - A random-sample accuracy rate for any of the three lists. Would need a hand-adjudicated random sample of a few hundred domains, stratified by prevalence decile so the head does not swamp it, i.e. tens of hours at the rate section C ran at. Worth doing and not done; the page is explicit that its 30 rows cannot substitute. Recorded as a follow-up item (
ownership-accuracy-random-sampleon thewiki-measurethewebtask) with the sampling frame, the sourcing bar and the scripts to reuse, together with the Wayback questions in the first bullet. - Whether anyone has built an LLM-based domain-owner resolver. Nothing in this corpus. [12Selmo, Carlos; Carisimo, Esteban; Bustamante, Fabián E.; Alvarez-Hamelin, J. Ignacio (2025): "Learning AS-to-Organization Mappings with Borges", in: Proceedings of the 2025 ACM Internet Measurement Conference, pp. 120-133. (DOI)] and [14Gouda, Deepak; Dainotti, Alberto; Testart, Cecilia (2025): "Prefix2Org: Mapping BGP Prefixes to Organizations", in: Proceedings of the ACM Internet Measurement Conference. (DOI)] do the network-layer equivalent. Named on the page as a gap rather than as a method to use.
F. Judgement calls
- Broadening the page beyond its title. See *Scope decision* above. Anyone would notice the page spends more words on Tracker Radar and Disconnect than on webXray; that is deliberate, because a reader arriving at a dead tool needs to be sent somewhere.
- Calling webXray's owner list “historical” and Tracker Radar's / Disconnect's “current practice”. Evidence: last corpus use of webXray's list is 2022; ownership use of Tracker Radar runs 2021→2026 with 7 of its 11 papers in 2024–2026; the file itself has not changed since 2021-03-04; the tool is unobtainable; and 17 of the 25 adjudicated rows it covers are stale. The 2025–2026 corpus slice is provisional, so the year-by-year counts are given rather than a trend claim, and the page says the counts are too small to be a market share.
- Not calling any list “the best”. Disconnect is current on 22 of 22 rows it covers but absent on 8 of 30 and carries no hierarchy; Tracker Radar covers everything and is stale on renames. The page gives a per-question table instead of a ranking. A ranking would have been shorter and less useful.
- Publishing the
webXray-rootcomparison even though it makes agreement worse. The tempting move was to report only the leaf comparison, since “resolve the hierarchy” sounds like the obvious fix. Publishing both is what makes the granularity-versus-vintage decomposition visible, and that decomposition is the page's main analytical contribution. - Keeping the
nulldomain and the IPv6 literals in the write-up. They are a defect in a widely used published dataset, they are cheap to state, and a reader who does not know about them will silently include anullrow in a prevalence table. - Naming the miscitation. Recorded as a verifiable fact about a reference list, with the methodological point it illustrates, and with no characterisation of the authors. The alternative — a vague “watch out for homographs” — would have been unfalsifiable.
- Quoting webXray's licence at length. It is the single most actionable fact on the page: a student who plans a study around webXray has planned a study around software they cannot legally obtain. A one-line “non-commercial licence” would have understated it.
<WRAP important>boxes rather than<wrap todo>. No open TODOs were left on the content page: the unknowns are stated in its methodology section with what would close them, which is where a reader checking a number will look. The one real TODO — correcting Crawler — is recorded here, because it is work on a different page.- No
~~DISCUSSION~~on this provenance page. Following the convention set by the earlier provenance pages: comments belong on the content page.
G. Sub-agent findings that did not survive
Three Sonnet sub-agents were run in parallel and every load-bearing claim was re-checked. Rejections are recorded because they are the only measure of whether a reviewer slot is worth having.
| Claim | Verdict |
|---|---|
| “IEEE-SP/2020 states a version: WebXRay commit 04c3c8e8, 2019-06-18” | accepted, and it corrected me. My draft said only 1 of 8 papers pinned a snapshot and that none named a commit. Verified in the source: the reproducibility table pins both webXray and Disconnect to commits. The report script's SNAPSHOT map and the page were fixed |
| “NDSS/2021 found webXray's list covers 1,096/1,146 (~95.6%) of same-party pairs” | rejected as a publishable figure. The sentence contradicts itself; see A.17. The unambiguous parts of the paragraph are used instead |
| “IMC/2020 used the owner list” (8 owner-list-only papers) | rejected. webXray appears in that paper only in its reference list; the method is a TLD + certificate-SAN + SOA heuristic. Verdict kept as citation, giving 7 |
| “CCS/2016 is a citation” | rejected as imprecise. The paper compares against webXray and criticises its browser. Verdict compared, which is what the page reports |
| “Tracker Radar: 31 papers” | rejected in favour of 32. The report's sweep normalises whitespace first and catches one match broken across a column boundary that a plain grep misses |
| “Disconnect-as-a-list: ~78 papers” | rejected in favour of 74. Different tightening regex; the page uses the one in the script, which is printed |
| “webXray is 'discontinued and superseded by webxray.ai'” | accepted after independent re-fetch of webxray.ai and timlibert.me. This is the finding that closes the parent page's open <wrap todo> |
| “Disconnect's list is GPL-3.0 with an attribution requirement” (my own briefing premise) | rejected — my premise was wrong. It was GPLv3 from 2015-10-13 and CC BY-NC-SA 4.0 since 2020-06-24, verified from the LICENSE commit history. The page carries the correction as a warning, since a paper quoting the GPL terms is quoting a dead licence |
“postrelease.com → Life360 and crwdcntrl.net → Publicis look like Disconnect errors” (my own hypothesis) | rejected — I was wrong on both. See C.1 |
| “Disconnect accepts community pull requests” (my own first draft) | rejected — wrong. Its README says “Pull requests are not reviewed and will be closed”. Caught by self-review, not by a reviewer. The corrected row also gave the page Disconnect's own documented method, which the first draft called undocumented |
| “webXray is the reason most pre-2022 papers could name a company” (my own first draft) | rejected as overstated. The corpus has 8 papers that used it against a 74-paper upper bound for Disconnect. Softened to “one of the three hand-curated lists the pre-2022 literature used”, which is what [4Sánchez-Rola, Iskander; Dell'Amico, Matteo; Balzarotti, Davide; Vervier, Pierre-Antoine; Bilge, Leyla (2021): "Journey to the Center of the Cookie Ecosystem: Unraveling Actors' Roles and Relationships", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)] and [15Dambra, Savino; Sanchez-Rola, Iskander; Bilge, Leyla; Balzarotti, Davide (2022): "When Sally Met Trackers: Web Tracking From the Users' Perspective", in: Proceedings of the USENIX Security Symposium. (Link)] actually did |
| “the database … is wrong far more often than it is right” (my own first draft) | rejected as an unsupported generalisation. True of the selection-biased adjudicated sample, not of the file. Softened to “frozen at 2021 and badly stale wherever it has been checked”, with the selection bias stated in the same bullet |
| “over 1M sites” for Libert's 2018 crawl (my own first draft) | replaced with the paper's own figures — Alexa top one million, October 2017, 938,093 pages loaded, 248,029 policy links extracted — after reading the results section |
| “Kariryaa et al., NDSS 2025” (my own first draft) | a fabricated author name. The paper's first author is Xiaoyuan Wu. Caught by a self-review script that matches every Name et al., VENUE YEAR attribution on the page against the author field of the key cited next to it; 14 of 15 rows passed, this one did not. The citekey was renamed wu2025_appprivacyreport at the same time |
Reproducibility check run after publication
All three scripts were re-run and their output diffed byte-for-byte against the committed output: identical. owner_dbs.py was then re-run against a fresh cache, i.e. re-fetching all five inputs and the Public Suffix List live, and produced output identical to the published snapshot — so every figure in sections B and C of this page still reproduces from the live sources as of 2026-08-17, with the same five SHA-256 prefixes. That will stop being true: two of the three lists change weekly.
Publishing gotcha: the bibliography needs a cache purge
After appending to literature:bibliography and saving this page, every one of the 14 new [key] markers rendered as a broken citation and the reference list showed only the 6 keys that already existed. The bibliography source was well-formed; the bibtex plugin was serving a cached parse of the old bibliography.
Fix: curl -sL “https://measuretheweb.org/literature/bibliography?purge=true” and then the same on the citing page. After that all 22 references rendered. Do this after any bibliography append and re-read the rendered page, or you will publish a page full of broken citations and the raw source will look perfect.
H. Reviewers
Filled in after the review passes; see the page history for what changed.
Three focused reviewers (Sonnet) ran in parallel against the page text, the three scripts and their outputs, and the provenance notes. Every finding below was re-verified against the primary source before being accepted or rejected.
— Reviewer 2: citations and quotes ——————————————
Reported 4 blocking, 2 should-fix, 2 nits. Checked ~30 quotations, 22 citekeys and 16 BibTeX entries. Independently re-derived the numeric infrastructure from the cached JSON and matched every figure exactly.
ACCEPTED (blocking):
1. "Kariryaa et al., NDSS 2025" is a fabricated attribution; the first author is Xiaoyuan Wu. Already found and fixed by self-review before this report arrived, along with a new guard (scripts/check_attributions.mjs) and a key rename to wu2025_appprivacyreport. Independent confirmation of the same defect. 2. Yang & Yue try webXray SECOND, not third: the paper's order is CrunchBase, Tim Libert's library, TLS certificate, WHOIS. The page contradicted itself -- one sentence had the order right and the table row had it wrong. Fixed. 3. sanchezrola2021_journey is IEEE S&P **2021**, not 2022. Confirmed against Crossref for 10.1109/sp40001.2021.9796062: container "2021 IEEE Symposium on Security and Privacy (SP)", event 2021-05-24, issued 2021-05. The corpus files it under 2022 (a DBLP indexing quirk). BibTeX year and series fixed, citekey renamed from sanchezrola2022_journey, and the page now says 2021 with an inline note that the year table follows the corpus. 4. Ghostery trackerdb is **CC BY-NC-SA 4.0**, not MIT. Confirmed: its package.json says "CC-BY-NC-SA-4.0" and the GitHub API returns no SPDX id. Fixed, with a warning not to trust the API field. This strengthens the page's licence point -- all three live options are non-commercial.
ACCEPTED (should fix):
5. "all commits on 2018-04-05" for RDBinns/webXray_Domain_Owner_List. The reviewer found 12 commits spanning 2018-03-29 to 2018-04-05. GitHub's commits API was rate-limited when re-checking, so the claim was replaced with what the repo API itself returns and was fetched first-hand: created and last pushed on 2018-04-05. The unverifiable "all commits" claim is gone. 6. The PSL quotation was silently truncated mid-sentence. The full clause is "...without update mechanisms that are frequently checking for updates and incorporating them." Re-fetched and confirmed; the page now quotes it whole.
ALSO FIXED, found while acting on 3 and 8:
7. pages/bib_additions_webxray.bib carried bibgen's own diagnostic lines
("--- check these ---", "metadata source: openalex-doi", …) which are not
BibTeX. They would have been appended verbatim to literature:bibliography and
could have broken every page that renders it. Stripped; the file is now 16
entries and nothing else.
REJECTED:
8. Curly apostrophe in the steffens2021_blockparty title. bibgen takes titles from publisher metadata; normalising punctuation by hand is how titles drift from the record. Left as generated.
— Reviewer 3: external currency ——————————————-
Checked 22 claim groups against live primary sources. Independently confirmed both blocking findings reviewer 2 raised (trackerdb's licence, the RDBinns commit range), which had already been fixed, and confirmed 20 further claims exactly: the 404s, webxray.org's body text, the PyPI misses, the fork count and newest fork activity, the Docker Hub state, every licence including PolyForm Strict 1.0.0's own clauses, Disconnect's 2020-06-24 relicence, Tracker Radar's release tags, Disconnect's and Ghostery's last commits, the WhoTracks.me redirect chain, tracker-radar-collector still being Puppeteer-based, Crunchbase's 401, the PSL's warning and canonical URL, Mozilla's shavar pipeline being unreplaced, and five of the thirty ownership adjudications.
ACCEPTED (should fix):
1. lxml 4.6.2 and psycopg2-binary 2.8.6 have no PyPI wheel beyond cp39, and Python 3.9 has been end-of-life since October 2025 -- so even a reader who obtains the code cannot `pip install -r requirements.txt` on a current interpreter without system libxml2/libxslt and PostgreSQL headers. Added to the licence box, which is where a reader deciding whether to try is looking. websocket-client 0.57.0 and textstat 0.7.0 are fine.
ACCEPTED (currency confirmations worth recording):
2. PolyForm Strict 1.0.0 is still the only version: `strict/1.1.0` 404s and the project's Announcements page has a single entry, "Announcing Version 1.0.0 of the PolyForm Licenses" (2020-05-24). 3. CC BY-NC-SA 4.0 is still current; there is no 5.0. 4. No broken internal links anywhere. The only two unresolved targets are these two pages themselves, i.e. the red link being fulfilled.
REJECTED:
5. "PhantomJS's exact pushed_at could not be confirmed (GitHub rate limit)." Not a defect in the page: `api.github.com/repos/ariya/phantomjs` was fetched first-hand earlier in this run and returned `archived: true` with `pushed_at: 2022-11-26T19:43:12Z`. The reviewer's inability to re-fetch under a rate limit is not evidence against it.
— Reviewer 4 (generic, Fable): the three findings that mattered most ———-
Given no checklist and told to find what the focused three were not looking for. It found the most serious defect on the page, in the page's own method.
ACCEPTED (blocking – this was a real bug in owner_dbs.py):
1. **googleapis.com is a PRIVATE PSL rule, so the fold + exact-key lookup manufactured a coverage hole and depressed every weighted coverage figure.** Verified: the rule is at line 13935 of the snapshot, past BEGIN PRIVATE DOMAINS at 11276, and all three lists DO name googleapis.com (webXray "Google APIs", Tracker Radar "Google LLC", Disconnect "Google"). So fonts.googleapis.com -- which the page showcased three times as "the single most prevalent third-party name with no owner in any list" -- was an artefact of my own lookup rule, and it carries prevalence 0.369 on its own.
Fixed properly rather than patched: fetch_psl() now returns the ICANN and PRIVATE sections separately, a lookup() helper walks parent labels, and the script prints all FOUR combinations (ICANN/full fold x walk/exact lookup) so the reader can see that the choice moves the answer by more than the lists differ. Every figure in sections C and D of the page was re-derived: weighted coverage 54.5/79.3/75.8% -> 58.6/84.3/80.5%; domain share 1.4/12.2/5.0% -> 2.1/17.2/7.0%; top-100 70/95/91 -> 71/98/94; the no-owner-anywhere figure 94.6% of domains and 19.8% of weight -> 92.4% and 14.4%. The pairwise disagreement table moved by under a point.
The replacement example is better than the one it replaces: the most requested domain no list can name is now tiktokw.us at prevalence 0.041, which is a genuine, recent, mid-tail coverage hole. The googleapis rows are re-captioned as the trap they actually are, in the page's trap list and again in the lookup demo, which now shows the buggy version, says so, and gives the three-line fix.
ACCEPTED (blocking):
2. **The two rows that failed the sourcing bar were still counted in the adjudication tallies, and two of webXray's three "current" verdicts WERE those two rows.** Verified from the script: webXray's "current" rows were casalemedia.com, 360yield.com and fwmrm.net, and the latter two are exactly the UNRESOLVED pair. So the one figure most favourable to webXray rested on the evidence the script itself called insufficient -- while both pages claimed those rows were "recorded as unresolved rather than guessed". owner_adjudication.py now excludes them from every tally and prints what it excluded and why: 28 rows, webXray current on 1 of 23 (was 3 of 25), Tracker Radar 8 of 28, Disconnect 21 of 21.
Also accepted: the "Read as a share of each list's own entries ... 100%" sentence invited exactly the accuracy ranking the box below it disclaimed. Cut. The WRAP box now also says that Tracker Radar's zero in "No entry" and Disconnect's zero in "Stale" are artefacts of how the sample was drawn, and the script prints the same caveat above its own tallies.
ACCEPTED (blocking):
3. **The provenance page and the committed script output were not brought up to date after reviewer 2's fixes, while certifying that everything passed.** The ROLE hand map in report_webxray.mjs still said Yang & Yue tried webXray "third of four" where the content page had been corrected to "second", and the section D verification table still said Ghostery trackerdb was "(MIT)". Both fixed at the source and re-run, so the "unedited output" now agrees with the page it certifies. The reviewer is right that check_page_numbers.mjs cannot catch this class -- "third" and "MIT" are not numerals -- and that gap is now stated in *What could not be established*.
ACCEPTED (smaller):
4. "Treat webXray as **unobtainable**" was contradicted by the page's own practice: every figure on it was computed from the surviving copy. Reworded to "obtainable but not redistributable, and not installable", with the artefact- appendix consequence spelled out. 5. Ghostery trackerdb is named as a live option but is absent from the measured comparison. The omission and its reason (per-company .eno files plus a separate patterns layer, not a single domain->owner map) are now stated in the comparison section, labelled an omission rather than a judgement. 6. The reader could not assemble a pipeline. A new *Assembling the pipeline* section gives the six steps, including the one that was entirely missing: resolve the VISITED site to an owner too and drop same-owner requests. Without it, google.com embedding gstatic.com counts as third-party tracking. 7. The actionable answer sat ~120 lines after the lede. Jump links to *Choosing a resolution source now* and *Assembling the pipeline* added to the lede, which now says plainly that everything between is the evidence.
NOTED, not acted on in this sitting:
8. Discoverability: the wiki's only treatment of domain-to-company resolution lives under a dead tool's name. The reviewer is right that the earlier rejection of a separate topic page was weak. Mitigated by adding a link from [[Privacy:Requests]], which is where a reader asking "whose request is this?" actually lands. A ''design:ownership_resolution'' page that this one feeds is worth considering and is recorded as such rather than done. 9. The 16-row schema table "could halve". Kept: its fill-rate column is the evidence for "most of that ambition is unfilled", which is the section's claim, and a reader checking one field wants the row.
— Reviewer 1: figures versus script ——————————————
Still running when the page was published. Its brief was to re-run all three scripts and diff every figure against the real output. That check was also run directly, repeatedly, throughout the session: check_page_numbers.mjs passes whole-page (not windowed) on both pages against the concatenated output of all three scripts, check_tables.mjs passes on both, check_attributions.mjs passes 15 of 15, and the report's own figure verifier locates 26 of 26 literal per-paper figures in the cited sources. Anything reviewer 1 reports after publication goes into the page history, not into this log.
I. Unedited output: scripts/report_webxray.mjs
Corpus: 5859 extracted papers from CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf and IEEE S&P, 2010-2026.
Baseline populations: 1120 papers ran a crawl; 4439 classified or labelled something.
=== A. Population: the schema signal versus the full-text sweep ===
Schema signal: tools[].name matching /webx[\s-]?ray/i with usedOrMentioned in {used, produced} fires on 7 papers.
Not used/produced (compared/mentioned/unclear): 0 papers.
Full-text sweep of paper.cols.txt for the same pattern: 15 papers, 0.3% of the 5859-paper corpus and 1.3% of the 1120 that ran a crawl.
Schema papers not in the sweep: none (a sweep miss would mean the extractor read a rendering the sweep cannot see).
Sweep papers the schema misses: 8.
Spellings in tools[].name: "webxray" (3), "webXray" (2), "WebXRay" (1), "WebXray" (1).
Spelling-fold residue: 0 -- every spelling is a case variant of one token. There is no fork under another name in the corpus.
ROLE hand map: 15 entries; sweep papers with no verdict: 0; verdicts for papers no longer in the sweep: 0.
=== B. What role webXray plays, by hand verdict ===
Role Papers Share of 15
--------------- ------ -----------
owner-list-only 7 46.7%
citation 4 26.7%
compared 1 6.7%
subject 1 6.7%
miscitation 1 6.7%
instrument 1 6.7%
Papers that actually ran webXray or read its owner list: 8 of 15.
Of those 8, 7 used only the owner list and 1 ran the crawler.
The one paper that ran the crawler is WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w -- webXray's own author's paper.
Per paper:
Paper Role What was used
--------------------------------------------------------------------------------------------------------------------------- --------------- --------------------------------------------------------------------------------------------------------------------------------
CCS/2016/online-tracking-a-1-million-site-measurement-and-analysis compared crawler, as a baseline whose browser is criticised
WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w instrument crawler + owner list + policy extraction
WWW/2019/before-and-after-gdpr-the-changes-in-third-party-presence-at-public-and-private citation webxray.org cited as the crawler used by a related study; this paper uses its own
IEEE-SP/2020/do-cookie-banners-respect-my-choice-measuring-legal-compliance-of-banners-from-i owner-list-only owner list
IMC/2020/analyzing-third-party-service-dependencies-in-modern-web-services-have-we-learne citation owner list in the reference list only; the paper builds its own TLD + SAN + SOA heuristic
PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen owner-list-only owner list (cited as “Tim Libert's library”), SECOND of four sources tried in order: CrunchBase, webXray, TLS certificate, WHOIS
NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri owner-list-only owner list, retrieved from the Internet Archive
IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati owner-list-only owner list, third by priority of three merged lists
PETS/2022/atom-ad-network-tomography owner-list-only owner list, alongside WHOIS and TLS certificates
PETS/2022/omnicrawl-comprehensive-measurement-of-web-tracking-with-real-desktop-and-mobile owner-list-only owner list
PETS/2022/who-knows-i-like-jelly-beans-an-investigation-into-search-privacy citation another paper's use of the crawler, described in related work
USENIX/2022/when-sally-met-trackers-web-tracking-from-the-users-perspective owner-list-only owner list, one of three merged lists
IMC/2023/a-first-look-at-the-privacy-harms-of-the-public-suffix-list subject webXray is one of the repositories measured as shipping a frozen Public Suffix List copy
PETS/2024/connecting-the-dots-tracing-data-endpoints-in-iot-devices miscitation describes Libert's webXray but cites Cinco Network's WebXRay (Held, IJNM 1998), an unrelated 1998 network-management product
NDSS/2025/transparency-or-information-overload-evaluating-users-comprehension-and-perceptions-of-the-ios-app-privacy-report citation owner list, described in related work
=== C. Which snapshot of the owner list did they use? ===
The owner list has no version field and no release tags: it is a single JSON file on a branch.
A paper can only pin it by naming a date, a commit or an archive snapshot.
IEEE-SP/2020/do-cookie-banners-respect-my-choice-measuring-legal-compliance-of-banners-from-i: COMMIT: "WebXRay commit 04c3c8e8 (2019-06-18)", in a reproducibility table that pins the Disconnect list the same way ("commit eb817fb1 (2019-12-10)")
IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati: nothing -- no date, commit or snapshot
NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri: partial: "as available in the Internet Archive", no date and no snapshot id
PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen: nothing -- no date, commit or snapshot
PETS/2022/atom-ad-network-tomography: nothing -- no date, commit or snapshot
PETS/2022/omnicrawl-comprehensive-measurement-of-web-tracking-with-real-desktop-and-mobile: nothing -- no date, commit or snapshot
USENIX/2022/when-sally-met-trackers-web-tracking-from-the-users-perspective: nothing -- no date, commit or snapshot
WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w: nothing -- no date, commit or snapshot
(IMC/2020/analyzing-third-party-service-dependencies-in-modern-web-services-have-we-learne: reference dated "June 29, 2018" -- a citation, not a use, so it is not counted below)
Papers that used the list and say anything at all about which snapshot: 2 of 8 (25.0%).
Papers that name an exact commit: 1 of 8 (12.5%).
Matte et al. is the model to copy: it pins webXray AND Disconnect to commits in a reproducibility table.
=== D. Venue and year shape ===
Year Papers naming webXray Of which used the crawler or list
---- --------------------- ---------------------------------
2016 1 0
2018 1 1
2019 1 0
2020 3 2
2021 1 1
2022 5 4
2023 1 0
2024 1 0
2025 1 0
Venue Papers naming webXray
------- ---------------------
CCS 1
IEEE-SP 2
IMC 2
NDSS 2
PETS 5
USENIX 1
WWW 2
=== E. The ownership-resolution landscape: full-text sweeps ===
Each row is an UPPER BOUND: a full-text match, not a hand-verified use. The two
smallest are hand-verified above and below; the rest are not, and are labelled so.
Untightened /disconnect/i matches 700 papers -- almost none of which mean the list; "disconnect" is a common English word and the CSP literature uses it as a technical term. Hence the list-sense pattern, which gives 74.
Resource Papers matching Share of 5859 Hand-verified?
----------------------- --------------- ------------- -----------------
Public Suffix List 101 1.7% no -- upper bound
Disconnect (list sense) 74 1.3% no -- upper bound
Tracker Radar 32 0.5% yes, all 32
WhoTracks.me 23 0.4% no -- upper bound
Crunchbase 23 0.4% no -- upper bound
webXray 15 0.3% yes, all 15
Papers matching ANY of webXray / Tracker Radar / WhoTracks.me / Crunchbase / Disconnect-as-a-list:
136 papers (2.3% of the corpus; 12.1% of the 1120 that crawled).
Year Corpus papers Naming an ownership resource Share
----- ------------- ---------------------------- -----
2010 119 0 0.0%
2011 116 1 0.9%
2012 151 0 0.0%
2013 125 0 0.0%
2014 166 0 0.0%
2015 190 0 0.0%
2016 182 2 1.1%
2017 231 4 1.7%
2018 254 5 2.0%
2019 402 9 2.2%
2020 404 15 3.7%
2021 379 13 3.4%
2022 546 19 3.5%
2023 719 19 2.6%
2024 690 17 2.5%
2025* 770 21 2.7%
2026* 415 11 2.7%
* 2025-2026 are the provisional corpus edge: CCS 2026 and IMC 2026 have not been held,
and IEEE S&P / WWW 2026 abstracts are not in OpenAlex, so selection under-samples them.
=== F. Tracker Radar names three artefacts, not one ===
What "Tracker Radar" meant Papers Share of 32
--------------------------- ------ -----------
dataset-ownership 11 34.4%
dataset-tracker-or-category 9 28.1%
collector-crawler 9 28.1%
citation 2 6.3%
compared 1 3.1%
TR_ROLE hand map: 32 entries; unverdicted sweep hits: 0; stale verdicts: 0.
Papers using Tracker Radar for domain-to-company ownership: 11. Earliest: 2021.
Papers using the Collector, which is a Puppeteer crawler and carries no ownership data at all: 9.
The Collector has its own page (Programming:Crawler:Tracker Radar Collector); it is not an ownership resource.
Ownership use of Tracker Radar over time, against webXray:
Year Tracker Radar for ownership webXray crawler or list
----- --------------------------- -----------------------
2010 0 0
2011 0 0
2012 0 0
2013 0 0
2014 0 0
2015 0 0
2016 0 0
2017 0 0
2018 0 1
2019 0 0
2020 0 2
2021 1 1
2022 0 4
2023 2 0
2024 1 0
2025* 4 0
2026* 3 0
=== G. Per-paper figures quoted on the page, checked against paper.cols.txt ===
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | 91.27% of successfully loaded pages initiated a third-party request | /91\.27/
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | average of 10.89 unique third-party domains per page | /10\.89/
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | the crawl: Alexa top one million, October 2017 | /In October 2017, a computer based at a United States academic .{0,60}institution is used to scan one million popular websites/
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | 938,093 pages loaded and 248,029 policy links extracted | /938,093 are successfully loaded/
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | the policy-link denominator | /248,\s?029 pages are extracted/
OK IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | 3,913 domains appear in at least one of the three lists | /3,913 domains in any of these lists/
OK IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | one single conflict between the automated approach and the three lists | /just one single conflict/
OK IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | priority order Disconnect, WhoTracks.me, webxray | /Disconnect first, WhoTracks\.me second, and webxray third/
OK PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen | 411 of 762 mobile-specific trackers resolved to an organization | /411 trackers/
OK PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen | 762 mobile-specific trackers is the denominator | /762 mobile-\s?specific trackers/
OK PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen | WHOIS privacy proxies appear in the top-10 organization table | /Redacted For Privacy 34/
OK PETS/2020/a-comparative-measurement-study-of-web-tracking-on-mobile-and-desktop-environmen | the other four proxy strings in that table: Domains By Proxy 25, Whois Guard 14, Global Domain Privacy Services 8, Whois Privacy 7 (34+25+14+8+7 = 88 trackers, arithmetic done on the page) | /Domains By Proxy 25.{0,200}Whois Guard 14.{0,400}Global Domain Privacy Services 8 Whois Privacy 7/
OK PETS/2022/who-knows-i-like-jelly-beans-an-investigation-into-search-privacy | the related study webXray was used for: 22,484 adult websites | /22,484 adult websites/
OK CCS/2016/online-tracking-a-1-million-site-measurement-and-analysis | webXray described as PhantomJS-based, with the stripped-down-browser criticism | /WebXray is a PhantomJS based tool/
OK NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | owner list taken from the Internet Archive | /as available in the Internet Archive/
OK NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | 2,175 candidate site pairs, 1,146 confirmed same-entity, about eight person-hours | /2,175 site pairs for further checks, out of which 1,146 are operated by the same entity/
OK NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | the owner list added 133 same-party relations their own method had not found | /133 additional same-party relations/
OK NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | the misses that motivated the manual work: twitch.tv / twitchcdn.net | /frequently miss connections among two hostnames, e\.g\., twitch\.tv and twitchcdn\.net/
OK NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | AMBIGUOUS -- NOT PUBLISHED AS A PERCENTAGE: "does account for 1,096 of our 1,146 found connections meaning that it alone does not suffice". The two halves of the sentence contradict each other and the published PDF reads the same way, so no coverage figure is taken from it. | /does account for 1,096 of our 1,146 found connections/
OK IEEE-SP/2020/do-cookie-banners-respect-my-choice-measuring-legal-compliance-of-banners-from-i | both lists pinned to commits in a reproducibility table | /Disconnect list commit eb817fb1 \(2019-12-10\) WebXRay commit 04c3c8e8 \(2019-06-18\)/
OK WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | the author's own coverage limitation: the list holds major ad networks, not the long tail | /database of .{0,60}domain ownership primarily contains major ad networks rather .{0,80}than small clients/
OK IMC/2023/a-first-look-at-the-privacy-harms-of-the-public-suffix-list | timlib/webXray listed among repositories shipping a frozen Public Suffix List | /timlib\/webXray 27/
OK PETS/2024/connecting-the-dots-tracing-data-endpoints-in-iot-devices | the miscitation: Cinco Network's WebXRay, 1998 | /Cinco Network's WebXRay/
OK PETS/2023/privacy-rarely-considered-exploring-considerations-in-the-adoption-of-third-part | five categorisations compared; they "differ in granularity and focus" | /categorizations differ in granularity and focus/
OK USENIX/2026/the-state-of-passkeys-studying-the-adoption-and-security-of-passkeys-on-the-web | Tracker Radar Entity Map used to group same-organization domains | /Tracker Radar Entity Map/
OK IMC/2024/diffaudit-auditing-privacy-practices-of-online-services-for-children-and-adolesc | whois plus Tracker Radar to find the parent organization of an eSLD | /parent organization owner of this domain, using whois/
26 of 26 literal figures/quotes located in the cited paper's .cols rendering.
=== H. Evidence quotes behind the schema tuples ===
partial 69% WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | webxray | methodology | "the webxray software platform is used to monitor third-party network traffic generated by loading a given web page and attribute such traffic to the entities which receive the data."
partial 70% WWW/2018/an-automated-approach-to-auditing-disclosure-of-third-party-data-collection-in-w | classification:webxray attribution database | methodology | "webxray searches for them in an internal database of domain ownership. The webxray attribution database is the product of years of detective work"
partial 79% NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | webXray | methodology | "We augment our list with same-entity entries from the most up-to-date list used by webXray [14] as available in the Internet Archive."
partial 79% NDSS/2021/whos-hosting-the-block-party-studying-third-party-blockage-of-csp-and-sri | classification:webXray Domain Owner List | methodology | "We augment our list with same-entity entries from the most up-to-date list used by webXray [14] as available in the Internet Archive."
exact 100% IEEE-SP/2020/do-cookie-banners-respect-my-choice-measuring-legal-compliance-of-banners-from-i | WebXRay | results | "We matched tracking domains to company names using the Disconnect list [10]. We find whether they are part of the TCF by checking if any company name linked to a tracker domain in WebXRay's database [40] is present in the Global Vendor List"
exact 100% IEEE-SP/2020/do-cookie-banners-respect-my-choice-measuring-legal-compliance-of-banners-from-i | classification:IAB Global Vendor List | results | "We find whether they are part of the TCF by checking if any company name linked to a tracker domain in WebXRay's database [40] is present in the Global Vendor List (version 168)."
below-threshold 58% PETS/2022/atom-ad-network-tomography | WebXray | methodology | "We used external data sources including WHOIS records, TLS certificates, and WebXray [61] to identify the parent organizations of each identified tracker."
partial 92% PETS/2022/omnicrawl-comprehensive-measurement-of-web-tracking-with-real-desktop-and-mobile | webXray | methodology | "Finally, for every request, we used webXray [62] data to determine the provenance of the requests."
exact 100% PETS/2022/omnicrawl-comprehensive-measurement-of-web-tracking-with-real-desktop-and-mobile | classification:webXray | methodology | "we used webXray [62] data to determine the provenance of the requests"
partial 86% USENIX/2022/when-sally-met-trackers-web-tracking-from-the-users-perspective | webxray | methodology | "Once the tracking domains are identified, we map the domain names to organizations based on three manually-curated lists: Disconnect [13], WhoTracks.me [12] and webxray [31]."
partial 81% USENIX/2022/when-sally-met-trackers-web-tracking-from-the-users-perspective | classification:Disconnect, WhoTracks.me, and webxray | methodology | "We map the domain names to organizations based on three manually-curated lists: Disconnect [13], WhoTracks.me [12] and webxray [31]."
partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | webxray | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])"
partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:Disconnect | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])"
partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:WhoTracks.me | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])"
partial 67% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:webxray | methodology | "The first is based on three manually-curated lists (Disconnect [30], WhoTracks.me [31] and webxray [32])"
exact 100% IEEE-SP/2022/journey-to-the-center-of-the-cookie-ecosystem-unraveling-actors-roles-and-relati | classification:graph-based label propagation algorithm (custom) | methodology | "We validated our approach by using the manually compiled lists as a “ground truth” reference: we then looked for conflicts"
Summary: 16 quotes: 4 exact, 11 partial (>=60% of 4-word windows), 1 below threshold.
Below-threshold is not "unsupported": every one checked by hand was present, mangled by a column splice or a dropped citation marker.
=== Z. Every number on the page that does NOT come from this corpus ===
These are measured by scripts/owner_dbs.py against live snapshots of the three
ownership databases, or read out of a repository or licence. They are listed here
so scripts/check_page_numbers.mjs can tell them from corpus figures.
owner_dbs.py, snapshots of 2026-08-17: webXray 827 owners / 3,215 domains; Tracker Radar 19,148 / 38,368; Disconnect 1,887 / 7,850.
owner_dbs.py: webXray owners with a parent_id 319 of 827 (38.6%); tree depth up to 6; largest owner groupm with 620 domains.
owner_dbs.py: coverage of 45,525 registrable third-party domains -- webXray 657 (1.4%), Tracker Radar 5,539 (12.2%), Disconnect 2,277 (5.0%).
owner_dbs.py: prevalence-weighted coverage -- webXray 54.5%, Tracker Radar 79.3%, Disconnect 75.8%.
owner_dbs.py: top 100 by prevalence -- webXray 70%, Tracker Radar 95%, Disconnect 91%; top 1,000 -- 26 / 67 / 67%; top 10,000 -- 5 / 27 / 16%.
owner_dbs.py: pairwise "needs a human" disagreement -- webXray vs TR 197 of 601 (32.8%), webXray vs Disconnect 216 of 461 (46.9%), TR vs Disconnect 584 of 1,532 (38.1%).
owner_dbs.py: 16,396 of 47,836 domain_summary.json rows are hostnames not registrable domains; 19 rows are not hostnames at all, one of them the literal string "null".
webXray licence: PolyForm Strict License 1.0.0 (LICENSE.md in the surviving copy).
Tracker Radar and Disconnect licences: CC BY-NC-SA 4.0 (LICENSE and entities.json "license" field).
webXray requirements.txt pins lxml 4.6.2, psycopg2-binary 2.8.6, textstat 0.7.0, websocket-client 0.57.0.
webXray's bundled ccSLD-patches.txt header: "current as of 20160428".
github.com/timlib/webXray and .../webXray_Domain_Owner_List: HTTP 404 on 2026-08-17; the timlib user account itself returns 200.
J. scripts/owner_dbs.py, in full
Published here rather than on the content page: it is 396 lines and reading it is an audit task.
- owner_dbs.py
#!/usr/bin/env python3 """Compare the three domain-to-company ownership databases used in web measurement: webXray's ``domain_owners.json``, DuckDuckGo Tracker Radar's ``entity_map.json``, and Disconnect's ``entities.json``. The question the script answers is the one a measurement paper actually has to answer: **if I resolve a third-party domain to a company, does it matter which list I use?** It reports, for each list, how many owners and domains it carries, how much of the third-party surface it can name an owner for (unweighted and weighted by how often you actually meet the domain), and how often two lists that both know a domain disagree about who owns it. Inputs are fetched live and hashed, so a figure quoted from the output is pinned to a snapshot rather than to "the list". python3 owner_dbs.py --cache ./cache # fetch (or reuse cache), print report python3 owner_dbs.py --cache ./cache --disagreements 40 # + sample disagreements Prevalence weighting uses Tracker Radar's own ``domain_summary.json`` prevalence (share of crawled top sites that request the domain). That is a Tracker Radar measurement, so the weighting favours no list less than it favours Tracker Radar itself -- the coverage numbers for webXray and Disconnect are therefore measured on Tracker Radar's view of the third-party surface, and the script says so rather than pretending to a neutral denominator. """ import argparse import hashlib import json import os import re import sys import urllib.request SOURCES = { # webXray's owner list. The upstream repository github.com/timlib/webXray # is gone (HTTP 404); this is the newest surviving copy of webXray 3.x. "webxray": "https://raw.githubusercontent.com/thezedwards/webXray/master/webxray/resources/domain_owners/domain_owners.json", "tr_entity_map": "https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/entity_map.json", "tr_domain_map": "https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/domain_map.json", "tr_domain_summary": "https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/domain_summary.json", "disconnect_entities": "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/entities.json", } PSL_URL = "https://publicsuffix.org/list/public_suffix_list.dat" # Legal-form suffixes only. Deliberately not "group", "media", "technologies" # or "digital": those are part of a company's name often enough that stripping # them would manufacture agreement. SUFFIXES = [ "incorporated", "inc", "llc", "l l c", "ltd", "limited", "plc", "llp", "lp", "corporation", "corp", "company", "co", "gmbh", "ag", "kg", "kgaa", "mbh", "sa", "s a", "sas", "sarl", "srl", "spa", "bv", "b v", "nv", "n v", "ab", "as", "oy", "oyj", "aps", "sro", "s r o", "pty", "pte", "pvt", "kk", "kabushiki kaisha", "co ltd", "holdings", "holding", "sl", ] SUFFIX_RE = re.compile(r"\b(" + "|".join(sorted(SUFFIXES, key=len, reverse=True)) + r")\b") def fetch(name, cache): path = os.path.join(cache, name + ".json") if not os.path.exists(path): os.makedirs(cache, exist_ok=True) req = urllib.request.Request(SOURCES[name], headers={"User-Agent": "owner-dbs/1.0"}) with urllib.request.urlopen(req, timeout=120) as r, open(path, "wb") as f: f.write(r.read()) raw = open(path, "rb").read() return json.loads(raw), hashlib.sha256(raw).hexdigest()[:16], len(raw) def fetch_psl(cache): path = os.path.join(cache, "public_suffix_list.dat") if not os.path.exists(path): os.makedirs(cache, exist_ok=True) req = urllib.request.Request(PSL_URL, headers={"User-Agent": "owner-dbs/1.0"}) with urllib.request.urlopen(req, timeout=120) as r, open(path, "wb") as f: f.write(r.read()) raw = open(path, "rb").read() # The PSL has TWO sections and the split matters more than any other choice # in this script. ICANN rules are real TLDs and registry suffixes; PRIVATE # rules are suffixes companies asked to have treated as boundaries -- # `googleapis.com` is one of them. Folding with the private section leaves # `fonts.googleapis.com` standing as its own "registrable domain", and an # exact-key lookup then fails even though all three lists name # `googleapis.com` -> Google. So both sections are loaded separately. icann, private, exceptions = set(), set(), set() section = "icann" for line in raw.decode("utf8").splitlines(): stripped = line.strip() if "BEGIN PRIVATE DOMAINS" in stripped: section = "private" continue if "BEGIN ICANN DOMAINS" in stripped: section = "icann" continue if not stripped or stripped.startswith("//"): continue if stripped.startswith("!"): exceptions.add(stripped[1:]) else: (icann if section == "icann" else private).add(stripped) return icann, private, exceptions, hashlib.sha256(raw).hexdigest()[:16] def registrable(host, rules, exceptions): """eTLD+1 of a hostname per the PSL algorithm, or None if there is none. Needed because Tracker Radar's domain_summary.json is keyed by *hostname* for 16,396 of its 47,836 entries (fonts.googleapis.com and ajax.googleapis.com are separate rows), while all three ownership lists key on the registrable domain. Comparing coverage without this step charges webXray and Disconnect for subdomains they were never meant to hold. """ labels = host.split(".") for i in range(len(labels)): candidate = ".".join(labels[i:]) if candidate in exceptions: return ".".join(labels[i + 1:]) or None best = 0 for i in range(len(labels)): candidate = ".".join(labels[i:]) wildcard = ".".join(["*"] + labels[i + 1:]) if candidate in rules or wildcard in rules: best = max(best, len(labels) - i) if best == 0: best = 1 # unknown TLD: treat as one label if best >= len(labels): return None # the host *is* a public suffix return ".".join(labels[-(best + 1):]) def lookup(host, mapping): """Owner for a hostname, trying the host then each parent label sequence. A list keyed on `googleapis.com` must answer for `fonts.googleapis.com`. Exact-key lookup is the single easiest way to manufacture a coverage hole, and it is what the first version of this script did. Stops at two labels so it can never walk up to a bare TLD. """ labels = host.split(".") for i in range(len(labels) - 1): candidate = ".".join(labels[i:]) if candidate in mapping: return mapping[candidate], candidate return None, None def norm_name(s): s = str(s).lower() s = re.sub(r"[’']", "", s) s = re.sub(r"[^a-z0-9]+", " ", s).strip() prev = None while prev != s: # "Foo Co., Ltd." needs two passes prev = s s = SUFFIX_RE.sub(" ", s).strip() s = re.sub(r"\s+", " ", s) return s def main(): ap = argparse.ArgumentParser() ap.add_argument("--cache", default="./cache") ap.add_argument("--disagreements", type=int, default=0, help="print this many domain-level disagreements per pair") args = ap.parse_args() print("=" * 78) print("Domain-to-company ownership databases: shape, coverage, agreement") print("=" * 78) print() data = {} print("Inputs (sha256 prefix of the exact bytes these figures were computed from):") for name in SOURCES: obj, digest, nbytes = fetch(name, args.cache) data[name] = obj print(f" {name:20s} {digest} {nbytes:>10,} bytes {SOURCES[name]}") print() # ---- webXray ----------------------------------------------------------- wx = data["webxray"] wx_owner = {} # domain -> owner name wx_domains_per_owner = {} wx_by_id = {e["id"]: e for e in wx} for e in wx: wx_domains_per_owner[e["id"]] = len(e["domains"]) for d in e["domains"]: wx_owner[d.lower()] = e["name"] wx_children = sum(1 for e in wx if e["parent_id"] is not None) def depth(e, seen=()): if e["parent_id"] is None: return 1 if e["id"] in seen: return 99 # cycle guard, printed if it fires return 1 + depth(wx_by_id[e["parent_id"]], seen + (e["id"],)) wx_depths = {} for e in wx: wx_depths[depth(e)] = wx_depths.get(depth(e), 0) + 1 # ---- Tracker Radar ----------------------------------------------------- tr_dm = data["tr_domain_map"] tr_owner = {d.lower(): v["entityName"] for d, v in tr_dm.items()} tr_em = data["tr_entity_map"] # ---- Disconnect -------------------------------------------------------- dc = data["disconnect_entities"]["entities"] dc_owner_props, dc_owner_res = {}, {} for name, v in dc.items(): for d in v.get("properties", []): dc_owner_props[d.lower()] = name for d in v.get("resources", []): dc_owner_res[d.lower()] = name dc_owner = dict(dc_owner_res) dc_owner.update(dc_owner_props) # properties are the ownership claim print("--- A. Shape ---------------------------------------------------------") print() rows = [ ("webXray domain_owners.json", len(wx), len(wx_owner), "yes (parent_id)", "purpose, country, trade bodies, per-language policy URLs"), ("Tracker Radar entity_map.json", len(tr_em), len(tr_owner), "no (flat)", "displayName, aliases; prevalence in a sibling file"), ("Disconnect entities.json", len(dc), len(dc_owner), "no (flat)", "properties vs resources split; category in services.json"), ] w = max(len(r[0]) for r in rows) print(f"{'List':{w}} {'Owners':>7} {'Domains':>8} {'Hierarchy':16} What else per owner") for r in rows: print(f"{r[0]:{w}} {r[1]:>7,} {r[2]:>8,} {r[3]:16} {r[4]}") print() print(f"webXray owners with a parent_id: {wx_children} of {len(wx)} " f"({100*wx_children/len(wx):.1f}%). Tree depths: " + ", ".join(f"depth {k}: {v}" for k, v in sorted(wx_depths.items()))) print(f"webXray domains per owner: median " f"{sorted(wx_domains_per_owner.values())[len(wx)//2]}, " f"max {max(wx_domains_per_owner.values())} " f"({max(wx_domains_per_owner, key=wx_domains_per_owner.get)})") dc_prop_only = sum(1 for d in dc_owner_props if d not in dc_owner_res) dc_res_only = sum(1 for d in dc_owner_res if d not in dc_owner_props) print(f"Disconnect: {len(dc_owner_props):,} distinct 'properties' domains, " f"{len(dc_owner_res):,} 'resources' domains; " f"{dc_prop_only:,} properties-only, {dc_res_only:,} resources-only.") multi = sum(1 for name, v in dc.items() if len(set(v.get("properties", []))) > 1) print(f"Disconnect entities naming more than one property domain: {multi:,} of " f"{len(dc):,} ({100*multi/len(dc):.1f}%) -- the rest are one-domain entities, " f"i.e. an ownership claim that carries no grouping information.") print() print("--- B. webXray's purpose and jurisdiction vocabulary -----------------") print() for field in ("uses", "platforms", "trade_groups"): tally = {} owners_with = 0 for e in wx: if e[field]: owners_with += 1 for v in e[field]: tally[v] = tally.get(v, 0) + 1 print(f"{field}: {owners_with} of {len(wx)} owners ({100*owners_with/len(wx):.1f}%) carry at " f"least one value; {len(tally)} distinct values: " + ", ".join(f"{k} ({v})" for k, v in sorted(tally.items(), key=lambda kv: -kv[1]))) countries = {} for e in wx: if e["country"]: countries[e["country"]] = countries.get(e["country"], 0) + 1 with_country = sum(1 for e in wx if e["country"]) top = sorted(countries.items(), key=lambda kv: -kv[1])[:10] print(f"country: {with_country} of {len(wx)} owners ({100*with_country/len(wx):.1f}%) carry one; " f"{len(countries)} distinct codes; top 10: " + ", ".join(f"{k} ({v})" for k, v in top)) for field in ("aliases", "notes", "site_privacy_policy_urls", "gdpr_statement_urls", "ccpa_urls", "opt_out_urls", "health_segment_urls", "crunchbase_id"): n = sum(1 for e in wx if e[field]) print(f"owners with a non-empty {field}: {n} of {len(wx)} ({100*n/len(wx):.1f}%)") langs = {} for e in wx: for lang, _ in e["site_privacy_policy_urls"]: langs[lang] = langs.get(lang, 0) + 1 print(f"distinct languages in site_privacy_policy_urls: {len(langs)}; top: " + ", ".join(f"{k} ({v})" for k, v in sorted(langs.items(), key=lambda kv: -kv[1])[:8])) print() # ---- webXray, resolved up the ownership tree --------------------------- # webXray records DoubleClick as its own owner whose parent_id is google. # Tracker Radar records doubleclick.net as "Google LLC" directly. Comparing # the two without walking webXray's parent chain measures a difference in # granularity and calls it a difference in fact. def root_of(e): seen = set() while e["parent_id"] is not None and e["id"] not in seen: seen.add(e["id"]) e = wx_by_id[e["parent_id"]] return e wx_root_owner = {} for e in wx: for d in e["domains"]: wx_root_owner[d.lower()] = root_of(e)["name"] reparented = sum(1 for d in wx_owner if wx_owner[d] != wx_root_owner[d]) print(f"Domains where webXray's immediate owner differs from the root of its " f"ownership tree: {reparented:,} of {len(wx_owner):,} " f"({100*reparented/len(wx_owner):.1f}%).") print() print("--- C. Coverage of the third-party surface ---------------------------") print() summary = data["tr_domain_summary"] icann, private, exceptions, psl_hash = fetch_psl(args.cache) print(f"Public Suffix List: {psl_hash} {len(icann):,} ICANN rules, " f"{len(private):,} PRIVATE rules, {len(exceptions):,} exceptions {PSL_URL}") print("The ICANN/PRIVATE split is the most consequential choice in this script.") print("`googleapis.com` is a PRIVATE rule, so folding with the private section") print("leaves fonts.googleapis.com standing as its own 'registrable domain' --") print("and an exact-key lookup then finds no owner for it, even though all three") print("lists name googleapis.com -> Google. Both rules are therefore reported.") print() raw_keys = list(summary) bad = [k for k in raw_keys if "." not in k] def build(rules_set): prev, folded = {}, 0 for host, v in summary.items(): host = host.lower() if "." not in host: continue # see the 'null' note below reg = registrable(host, rules_set, exceptions) if reg is None: continue if reg != host: folded += 1 # A registrable domain's weight is the *largest* prevalence among its # hostnames, not the sum: one site can request fonts.googleapis.com # and ajax.googleapis.com, so summing would double-count sites. This # makes every weighted coverage figure a conservative lower bound. prev[reg] = max(prev.get(reg, 0.0), v["prevalence"]) return prev, folded prev_icann, folded_icann = build(icann) prev_full, folded_full = build(icann | private) print(f"domain_summary.json rows: {len(raw_keys):,}. " f"{sum(1 for k in raw_keys if k.count('.') >= 2):,} are keyed by hostname " f"rather than registrable domain.") print(f" ICANN-section fold: merges {folded_icann:,} rows -> " f"{len(prev_icann):,} registrable domains") print(f" ICANN+PRIVATE fold: merges {folded_full:,} rows -> " f"{len(prev_full):,} registrable domains") print(f"Rows dropped as not hostnames at all: {len(bad)} {bad!r} " "-- a literal 'null' key with a prevalence attached is a defect in the " "published data, not a domain.") print() print("Denominator: those registrable third-party domains, i.e. domains Tracker") print("Radar's own crawl of regional top-site lists actually saw. This is Tracker") print("Radar's view of the surface, not a neutral one.") print() LISTS = (("webXray", wx_owner), ("Tracker Radar", tr_owner), ("Disconnect (properties+res)", dc_owner)) def coverage(prev, walk): rows = [] total = sum(prev.values()) for label, m in LISTS: if walk: hit = [d for d in prev if lookup(d, m)[0] is not None] else: hit = [d for d in prev if d in m] rows.append((label, len(hit), 100 * len(hit) / len(prev), 100 * sum(prev[d] for d in hit) / total)) return rows VARIANTS = [ ("ICANN fold + parent-label lookup <- USE THIS", prev_icann, True), ("ICANN fold + exact-key lookup", prev_icann, False), ("ICANN+PRIVATE fold + parent-label lookup", prev_full, True), ("ICANN+PRIVATE fold + exact-key lookup <- THE TRAP", prev_full, False), ] for name, prev, walk in VARIANTS: print(f"{name} (universe {len(prev):,})") print(f" {'List':30} {'Named':>8} {'Share':>7} {'Prevalence-weighted':>20}") for label, n, share, wshare in coverage(prev, walk): print(f" {label:30} {n:>8,} {share:>6.1f}% {wshare:>19.1f}%") print() fg = summary.get("fonts.googleapis.com", {}).get("prevalence") print(f"The single row that drives most of that gap: fonts.googleapis.com, prevalence " f"{fg:.3f}. googleapis.com is a PRIVATE PSL rule, and all three lists name it: " f"webXray={lookup('googleapis.com', wx_owner)[0]!r}, " f"TR={lookup('googleapis.com', tr_owner)[0]!r}, " f"Disconnect={lookup('googleapis.com', dc_owner)[0]!r}.") print("The bottom variant is what the first version of this script did, and it") print("understates every list. The gap between the top and bottom rows is a") print("measurement artefact, not a property of any list -- report which rule you") print("used, because it moves the answer by more than the lists differ.") print() # Everything below uses the recommended rule. prev = prev_icann total_prev = sum(prev.values()) universe = sorted(prev) owner_of = {label: {d: lookup(d, m)[0] for d in universe} for label, m in (("webXray", wx_owner), ("webXray-root", wx_root_owner), ("Tracker Radar", tr_owner), ("Disconnect", dc_owner))} for n in (100, 1000, 10000): topn = sorted(universe, key=lambda d: -prev[d])[:n] line = f"top {n:>5} by prevalence: " line += " ".join( f"{label} {100*sum(1 for d in topn if owner_of[label][d] is not None)/len(topn):.0f}%" for label in ("webXray", "Tracker Radar", "Disconnect")) print(line) print() named_by_none = [d for d in universe if owner_of["webXray"][d] is None and owner_of["Disconnect"][d] is None] print(f"Domains in the universe that neither webXray nor Disconnect names an owner " f"for: {len(named_by_none):,} ({100*len(named_by_none)/len(universe):.1f}%), " f"{100*sum(prev[d] for d in named_by_none)/total_prev:.1f}% of prevalence weight.") print("Top 15 of those by prevalence (Tracker Radar's owner in brackets):") for d in sorted(named_by_none, key=lambda x: -prev[x])[:15]: print(f" {d:34} prev={prev[d]:.4f} [{owner_of['Tracker Radar'][d] or 'TR: none'}]") top_unowned = max(named_by_none, key=lambda x: prev[x]) print(f"Most prevalent domain no list can name an owner for: {top_unowned}, " f"prevalence {prev[top_unowned]:.3f} (rounded to 3 dp for quoting).") dropped = {k: summary[k]["prevalence"] for k in bad} print("Dropped rows and their prevalence, rounded to 3 dp for quoting: " + ", ".join(f"{k}={v:.3f}" for k, v in sorted(dropped.items(), key=lambda kv: -kv[1])[:3])) print() print("--- D. Do two lists that both know a domain agree on the owner? ------") print() pairs = [("webXray", wx_owner, "Tracker Radar", tr_owner), ("webXray-root", wx_root_owner, "Tracker Radar", tr_owner), ("webXray", wx_owner, "Disconnect", dc_owner), ("webXray-root", wx_root_owner, "Disconnect", dc_owner), ("Tracker Radar", tr_owner, "Disconnect", dc_owner)] disagreement_samples = {} for a_label, _a_raw, b_label, _b_raw in pairs: # Parent-label lookup here too, for the same reason as section C. a, b = owner_of[a_label], owner_of[b_label] both = [d for d in universe if a[d] is not None and b[d] is not None] agree_raw = [d for d in both if a[d] == b[d]] agree_norm = [d for d in both if norm_name(a[d]) == norm_name(b[d])] sub = [d for d in both if d not in agree_norm and (norm_name(a[d]) in norm_name(b[d]) or norm_name(b[d]) in norm_name(a[d]))] dis = [d for d in both if d not in agree_norm and d not in sub] disagreement_samples[(a_label, b_label)] = sorted(dis, key=lambda x: -prev[x]) print(f"{a_label} vs {b_label}: {len(both):,} domains named by both") print(f" identical owner string {len(agree_raw):>7,} " f"({100*len(agree_raw)/len(both):.1f}%)") print(f" agree after legal-suffix fold {len(agree_norm):>7,} " f"({100*len(agree_norm)/len(both):.1f}%)") print(f" one name contains the other {len(sub):>7,} " f"({100*len(sub)/len(both):.1f}%) [e.g. Amazon / Amazon Technologies]") print(f" neither {len(dis):>7,} " f"({100*len(dis)/len(both):.1f}%) <- needs a human") wdis = sum(prev[d] for d in dis) / sum(prev[d] for d in both) print(f" ...weighted by prevalence, the 'needs a human' share is {100*wdis:.1f}%") print() if args.disagreements: print("--- E. Sampled disagreements (highest prevalence first) --------------") print() for (a_label, b_label), ds in disagreement_samples.items(): a, b = owner_of[a_label], owner_of[b_label] print(f"{a_label} vs {b_label}:") for d in ds[:args.disagreements]: print(f" {d:32} prev={prev[d]:.4f} {a_label}={a[d]!r} {b_label}={b[d]!r}") print() print("--- F. Named-entity residue of the suffix fold -----------------------") print() unchanged = [e["name"] for e in wx if norm_name(e["name"]) == e["name"].lower()] print(f"webXray owner names the fold leaves untouched: {len(unchanged)} of {len(wx)} " f"({100*len(unchanged)/len(wx):.1f}%). The fold only removes legal forms; it " "merges no synonyms, so every figure in section D is a lower bound on real " "agreement and an upper bound on real disagreement.") return 0 if __name__ == "__main__": sys.exit(main())
J2. Its unedited output
Run as python3 scripts/owner_dbs.py –cache out/webxray/cache –disagreements 25.
============================================================================== Domain-to-company ownership databases: shape, coverage, agreement ============================================================================== Inputs (sha256 prefix of the exact bytes these figures were computed from): webxray e53760188e6dc9aa 1,023,079 bytes https://raw.githubusercontent.com/thezedwards/webXray/master/webxray/resources/domain_owners/domain_owners.json tr_entity_map c4c3f97dbea6cb1e 4,741,528 bytes https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/entity_map.json tr_domain_map a11bc2580f664544 10,442,377 bytes https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/domain_map.json tr_domain_summary 7a303228d812a41c 16,310,837 bytes https://raw.githubusercontent.com/duckduckgo/tracker-radar/main/build-data/generated/domain_summary.json disconnect_entities 93e4f54036de1b39 412,191 bytes https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/entities.json --- A. Shape --------------------------------------------------------- List Owners Domains Hierarchy What else per owner webXray domain_owners.json 827 3,215 yes (parent_id) purpose, country, trade bodies, per-language policy URLs Tracker Radar entity_map.json 19,148 38,368 no (flat) displayName, aliases; prevalence in a sibling file Disconnect entities.json 1,887 7,850 no (flat) properties vs resources split; category in services.json webXray owners with a parent_id: 319 of 827 (38.6%). Tree depths: depth 1: 508, depth 2: 211, depth 3: 80, depth 4: 24, depth 5: 2, depth 6: 2 webXray domains per owner: median 1, max 620 (groupm) Disconnect: 5,843 distinct 'properties' domains, 4,148 'resources' domains; 3,702 properties-only, 2,007 resources-only. Disconnect entities naming more than one property domain: 551 of 1,887 (29.2%) -- the rest are one-domain entities, i.e. an ownership claim that carries no grouping information. --- B. webXray's purpose and jurisdiction vocabulary ----------------- uses: 761 of 827 owners (92.0%) carry at least one value; 38 distinct values: marketing (484), hosting (102), audience_measurement (78), video (38), general (34), security (27), customer_relationship_management (27), social_media (27), design_optimization (23), code (16), ecommerce (8), compliance (7), location (6), search (5), information_services (5), font (5), holding_company (5), content_recommendation (5), government_licensing (5), weather (4), domain_registration (4), network_services (4), gaming (3), information_service (2), publishing (2), tag_manager (2), public_opinion_monitoring (2), search_engine (2), payment_platform (1), egovernment (1), health (1), financial_services (1), accesibility (1), uncategorized (1), content_reccomendation (1), trustmark (1), website_certification (1), malware (1) platforms: 803 of 827 owners (97.1%) carry at least one value; 5 distinct values: web (777), mobile (249), tv (176), iot (20), email (5) trade_groups: 104 of 827 owners (12.6%) carry at least one value; 9 distinct values: nai (85), daa (51), iab (36), amm (7), daac (2), edaa (1), mcma (1), ana (1), mma (1) country: 826 of 827 owners (99.9%) carry one; 36 distinct codes; top 10: US (487), CN (114), UK (46), DE (36), FR (15), CA (14), JP (13), RU (10), IL (9), SE (8) owners with a non-empty aliases: 275 of 827 (33.3%) owners with a non-empty notes: 263 of 827 (31.8%) owners with a non-empty site_privacy_policy_urls: 591 of 827 (71.5%) owners with a non-empty gdpr_statement_urls: 132 of 827 (16.0%) owners with a non-empty ccpa_urls: 4 of 827 (0.5%) owners with a non-empty opt_out_urls: 13 of 827 (1.6%) owners with a non-empty health_segment_urls: 52 of 827 (6.3%) owners with a non-empty crunchbase_id: 34 of 827 (4.1%) distinct languages in site_privacy_policy_urls: 69; top: eng (554), chi (90), ger (81), fre (71), spa (64), jpn (54), ita (46), por (44) Domains where webXray's immediate owner differs from the root of its ownership tree: 2,175 of 3,215 (67.7%). --- C. Coverage of the third-party surface --------------------------- Public Suffix List: 155b43d46932e933 6,941 ICANN rules, 3,290 PRIVATE rules, 8 exceptions https://publicsuffix.org/list/public_suffix_list.dat The ICANN/PRIVATE split is the most consequential choice in this script. `googleapis.com` is a PRIVATE rule, so folding with the private section leaves fonts.googleapis.com standing as its own 'registrable domain' -- and an exact-key lookup then finds no owner for it, even though all three lists name googleapis.com -> Google. Both rules are therefore reported. domain_summary.json rows: 47,836. 16,396 are keyed by hostname rather than registrable domain. ICANN-section fold: merges 15,651 rows -> 32,369 registrable domains ICANN+PRIVATE fold: merges 2,339 rows -> 45,525 registrable domains Rows dropped as not hostnames at all: 19 ['null', '[2a01:4f9:2a:26e0::2]', '[2604:2dc0:100:5ce5::]', '[2001:41d0:800:4623::]', '[2001:41d0:602:556f::]', '[2604:8380:2e00:5::2]', '[2604:4500:8:2ea::2]', '[2604:8380:3300:1::2]', '[2604:8380:2900:15::2]', '[2001:41d0:403:579b::]', '[2001:41d0:306:44e6::]', '[2604:4500:a:432::2]', '[2402:1f00:8201:4a2::]', '[2604:4500:6:5a0::2]', '[2604:4500:21:8::4]', '[2402:1f00:8001:2518::]', '[2402:1f00:8300:c97::]', '[2604:8380:2f00:16::2]', '[2001:41d0:700:782c::]'] -- a literal 'null' key with a prevalence attached is a defect in the published data, not a domain. Denominator: those registrable third-party domains, i.e. domains Tracker Radar's own crawl of regional top-site lists actually saw. This is Tracker Radar's view of the surface, not a neutral one. ICANN fold + parent-label lookup <- USE THIS (universe 32,369) List Named Share Prevalence-weighted webXray 669 2.1% 58.6% Tracker Radar 5,581 17.2% 84.3% Disconnect (properties+res) 2,268 7.0% 80.5% ICANN fold + exact-key lookup (universe 32,369) List Named Share Prevalence-weighted webXray 669 2.1% 58.6% Tracker Radar 5,581 17.2% 84.3% Disconnect (properties+res) 2,268 7.0% 80.5% ICANN+PRIVATE fold + parent-label lookup (universe 45,525) List Named Share Prevalence-weighted webXray 11,150 24.5% 59.7% Tracker Radar 18,099 39.8% 84.8% Disconnect (properties+res) 10,389 22.8% 80.6% ICANN+PRIVATE fold + exact-key lookup <- THE TRAP (universe 45,525) List Named Share Prevalence-weighted webXray 657 1.4% 54.5% Tracker Radar 5,539 12.2% 79.3% Disconnect (properties+res) 2,277 5.0% 75.8% The single row that drives most of that gap: fonts.googleapis.com, prevalence 0.369. googleapis.com is a PRIVATE PSL rule, and all three lists name it: webXray='Google APIs', TR='Google LLC', Disconnect='Google'. The bottom variant is what the first version of this script did, and it understates every list. The gap between the top and bottom rows is a measurement artefact, not a property of any list -- report which rule you used, because it moves the answer by more than the lists differ. top 100 by prevalence: webXray 71% Tracker Radar 98% Disconnect 94% top 1000 by prevalence: webXray 26% Tracker Radar 69% Disconnect 68% top 10000 by prevalence: webXray 5% Tracker Radar 29% Disconnect 17% Domains in the universe that neither webXray nor Disconnect names an owner for: 29,896 (92.4%), 14.4% of prevalence weight. Top 15 of those by prevalence (Tracker Radar's owner in brackets): tiktokw.us prev=0.0406 [ByteDance Ltd.] consentmanager.net prev=0.0359 [consentmanager AB] rapidedge.io prev=0.0247 [TR: none] raptivecdn.com prev=0.0231 [TR: none] tracookiepixel.xyz prev=0.0228 [TR: none] growplow.events prev=0.0228 [TR: none] shopifycdn.com prev=0.0181 [Shopify Inc.] digitalaudience.io prev=0.0152 [Social Audience B.V.] openwebmp.com prev=0.0130 [TR: none] userway.org prev=0.0122 [TR: none] copper6.com prev=0.0113 [TR: none] ahrefs.com prev=0.0112 [Ahrefs Pte Ltd] anyrtb.com prev=0.0111 [TR: none] sparteo.com prev=0.0108 [TR: none] axiom.co prev=0.0102 [TR: none] Most prevalent domain no list can name an owner for: tiktokw.us, prevalence 0.041 (rounded to 3 dp for quoting). Dropped rows and their prevalence, rounded to 3 dp for quoting: null=0.024, [2a01:4f9:2a:26e0::2]=0.000, [2604:2dc0:100:5ce5::]=0.000 --- D. Do two lists that both know a domain agree on the owner? ------ webXray vs Tracker Radar: 612 domains named by both identical owner string 29 (4.7%) agree after legal-suffix fold 305 (49.8%) one name contains the other 109 (17.8%) [e.g. Amazon / Amazon Technologies] neither 198 (32.4%) <- needs a human ...weighted by prevalence, the 'needs a human' share is 29.0% webXray-root vs Tracker Radar: 612 domains named by both identical owner string 34 (5.6%) agree after legal-suffix fold 276 (45.1%) one name contains the other 97 (15.8%) [e.g. Amazon / Amazon Technologies] neither 239 (39.1%) <- needs a human ...weighted by prevalence, the 'needs a human' share is 51.1% webXray vs Disconnect: 464 domains named by both identical owner string 171 (36.9%) agree after legal-suffix fold 213 (45.9%) one name contains the other 34 (7.3%) [e.g. Amazon / Amazon Technologies] neither 217 (46.8%) <- needs a human ...weighted by prevalence, the 'needs a human' share is 44.5% webXray-root vs Disconnect: 464 domains named by both identical owner string 164 (35.3%) agree after legal-suffix fold 195 (42.0%) one name contains the other 39 (8.4%) [e.g. Amazon / Amazon Technologies] neither 230 (49.6%) <- needs a human ...weighted by prevalence, the 'needs a human' share is 64.1% Tracker Radar vs Disconnect: 1,538 domains named by both identical owner string 82 (5.3%) agree after legal-suffix fold 634 (41.2%) one name contains the other 320 (20.8%) [e.g. Amazon / Amazon Technologies] neither 584 (38.0%) <- needs a human ...weighted by prevalence, the 'needs a human' share is 29.7% --- E. Sampled disagreements (highest prevalence first) -------------- webXray vs Tracker Radar: doubleclick.net prev=0.4456 webXray='DoubleClick' Tracker Radar='Google LLC' googlesyndication.com prev=0.2115 webXray='AdSense' Tracker Radar='Google LLC' adnxs.com prev=0.1463 webXray='Xandr' Tracker Radar='Microsoft Corporation' jsdelivr.net prev=0.1242 webXray='jsDelivr' Tracker Radar='Prospect One' rubiconproject.com prev=0.1223 webXray='Rubicon Project' Tracker Radar='Magnite, Inc.' bing.com prev=0.1160 webXray='Bing' Tracker Radar='Microsoft Corporation' amazon-adsystem.com prev=0.1067 webXray='Amazon Marketing Services' Tracker Radar='Amazon Technologies, Inc.' linkedin.com prev=0.1054 webXray='LinkedIn' Tracker Radar='Microsoft Corporation' smartadserver.com prev=0.0752 webXray='Smart AdServer' Tracker Radar='Smartadserver S.A.S' bidswitch.net prev=0.0746 webXray='Bidswitch' Tracker Radar='IPONWEB GmbH' turn.com prev=0.0661 webXray='Turn' Tracker Radar='Amobee, Inc' 2mdn.net prev=0.0616 webXray='DoubleClick' Tracker Radar='Google LLC' scorecardresearch.com prev=0.0584 webXray='ScorecardResearch' Tracker Radar='comScore, Inc' dotomi.com prev=0.0583 webXray='Dotomi' Tracker Radar='Conversant LLC' 1rx.io prev=0.0546 webXray='Blinkx' Tracker Radar='RhythmOne' sitescout.com prev=0.0540 webXray='SiteScout' Tracker Radar='Centro, Inc.' simpli.fi prev=0.0519 webXray='simpli.fi' Tracker Radar='Simplifi Holdings Inc.' googleadservices.com prev=0.0510 webXray='AdSense' Tracker Radar='Google LLC' youtube.com prev=0.0485 webXray='YouTube' Tracker Radar='Google LLC' rfihub.com prev=0.0429 webXray='Rocketfuel' Tracker Radar='Zeta Global' loopme.me prev=0.0423 webXray='Loopme' Tracker Radar='Online Media Solutions Ltd. dba Brightcom' licdn.com prev=0.0373 webXray='LinkedIn' Tracker Radar='Microsoft Corporation' agkn.com prev=0.0347 webXray='Neustar Marketing' Tracker Radar='TransUnion LLC' intentiq.com prev=0.0337 webXray='Intent IQ' Tracker Radar='Almondnet Group' ytimg.com prev=0.0327 webXray='YouTube' Tracker Radar='Google LLC' webXray-root vs Tracker Radar: googletagmanager.com prev=0.5754 webXray-root='Alphabet' Tracker Radar='Google LLC' google.com prev=0.4525 webXray-root='Alphabet' Tracker Radar='Google LLC' doubleclick.net prev=0.4456 webXray-root='Alphabet' Tracker Radar='Google LLC' gstatic.com prev=0.4013 webXray-root='Alphabet' Tracker Radar='Google LLC' googleapis.com prev=0.3692 webXray-root='Alphabet' Tracker Radar='Google LLC' google-analytics.com prev=0.3489 webXray-root='Alphabet' Tracker Radar='Google LLC' googlesyndication.com prev=0.2115 webXray-root='Alphabet' Tracker Radar='Google LLC' adnxs.com prev=0.1463 webXray-root='AT&T' Tracker Radar='Microsoft Corporation' rubiconproject.com prev=0.1223 webXray-root='Rubicon Project' Tracker Radar='Magnite, Inc.' rlcdn.com prev=0.1098 webXray-root='Acxiom' Tracker Radar='LiveRamp Holdings, Inc.' yahoo.com prev=0.0984 webXray-root='Verizon' Tracker Radar='Yahoo Inc.' tapad.com prev=0.0973 webXray-root='Telenor' Tracker Radar='Tapad, Inc.' smartadserver.com prev=0.0752 webXray-root='Smart AdServer' Tracker Radar='Smartadserver S.A.S' turn.com prev=0.0661 webXray-root='Singtel' Tracker Radar='Amobee, Inc' lijit.com prev=0.0656 webXray-root='Federated Media' Tracker Radar='Sovrn Holdings' 2mdn.net prev=0.0616 webXray-root='Alphabet' Tracker Radar='Google LLC' pippio.com prev=0.0594 webXray-root='Acxiom' Tracker Radar='LiveRamp Holdings, Inc.' dotomi.com prev=0.0583 webXray-root='Here, There & Everywhere' Tracker Radar='Conversant LLC' 1rx.io prev=0.0546 webXray-root='Marimedia' Tracker Radar='RhythmOne' simpli.fi prev=0.0519 webXray-root='GTCR' Tracker Radar='Simplifi Holdings Inc.' googleadservices.com prev=0.0510 webXray-root='Alphabet' Tracker Radar='Google LLC' teads.tv prev=0.0486 webXray-root='Altice SA' Tracker Radar='Teads ( Luxenbourg ) SA' youtube.com prev=0.0485 webXray-root='Alphabet' Tracker Radar='Google LLC' 360yield.com prev=0.0467 webXray-root='Azerion' Tracker Radar='Improve Digital BV' fwmrm.net prev=0.0439 webXray-root='Comcast' Tracker Radar='FreeWheel' webXray vs Disconnect: doubleclick.net prev=0.4456 webXray='DoubleClick' Disconnect='Google' googlesyndication.com prev=0.2115 webXray='AdSense' Disconnect='Google' facebook.net prev=0.1830 webXray='Facebook' Disconnect='Meta' facebook.com prev=0.1665 webXray='Facebook' Disconnect='Meta' adnxs.com prev=0.1463 webXray='Xandr' Disconnect='Microsoft' jsdelivr.net prev=0.1242 webXray='jsDelivr' Disconnect='Volentio JSD' rubiconproject.com prev=0.1223 webXray='Rubicon Project' Disconnect='Magnite' bing.com prev=0.1160 webXray='Bing' Disconnect='Microsoft' casalemedia.com prev=0.1114 webXray='Index Exchange' Disconnect='IndexExchange' linkedin.com prev=0.1054 webXray='LinkedIn' Disconnect='Microsoft' crwdcntrl.net prev=0.0972 webXray='Lotame' Disconnect='PublicisGroupe' liadm.com prev=0.0755 webXray='LiveIntent' Disconnect='ZetaGlobal' smartadserver.com prev=0.0752 webXray='Smart AdServer' Disconnect='Equativ' bidswitch.net prev=0.0746 webXray='Bidswitch' Disconnect='Criteo' turn.com prev=0.0661 webXray='Turn' Disconnect='Nexxen' sharethrough.com prev=0.0659 webXray='Sharethrough' Disconnect='Equativ' bidr.io prev=0.0619 webXray='Beeswax' Disconnect='Comcast' 2mdn.net prev=0.0616 webXray='DoubleClick' Disconnect='Google' scorecardresearch.com prev=0.0584 webXray='ScorecardResearch' Disconnect='comScore' dotomi.com prev=0.0583 webXray='Dotomi' Disconnect='PublicisGroupe' outbrain.com prev=0.0550 webXray='Outbrain' Disconnect='Teads' 1rx.io prev=0.0546 webXray='Blinkx' Disconnect='Nexxen' sitescout.com prev=0.0540 webXray='SiteScout' Disconnect='BasisTechnologies' postrelease.com prev=0.0513 webXray='Nativo' Disconnect='Life360' googleadservices.com prev=0.0510 webXray='AdSense' Disconnect='Google' webXray-root vs Disconnect: google.com prev=0.4525 webXray-root='Alphabet' Disconnect='Google' doubleclick.net prev=0.4456 webXray-root='Alphabet' Disconnect='Google' gstatic.com prev=0.4013 webXray-root='Alphabet' Disconnect='Google' googleapis.com prev=0.3692 webXray-root='Alphabet' Disconnect='Google' google-analytics.com prev=0.3489 webXray-root='Alphabet' Disconnect='Google' googlesyndication.com prev=0.2115 webXray-root='Alphabet' Disconnect='Google' facebook.net prev=0.1830 webXray-root='Facebook' Disconnect='Meta' facebook.com prev=0.1665 webXray-root='Facebook' Disconnect='Meta' adnxs.com prev=0.1463 webXray-root='AT&T' Disconnect='Microsoft' jsdelivr.net prev=0.1242 webXray-root='Prospect One' Disconnect='Volentio JSD' rubiconproject.com prev=0.1223 webXray-root='Rubicon Project' Disconnect='Magnite' casalemedia.com prev=0.1114 webXray-root='Index Exchange' Disconnect='IndexExchange' rlcdn.com prev=0.1098 webXray-root='Acxiom' Disconnect='LiveRamp' yahoo.com prev=0.0984 webXray-root='Verizon' Disconnect='Yahoo!' tapad.com prev=0.0973 webXray-root='Telenor' Disconnect='Tapad' crwdcntrl.net prev=0.0972 webXray-root='Lotame' Disconnect='PublicisGroupe' liadm.com prev=0.0755 webXray-root='LiveIntent' Disconnect='ZetaGlobal' smartadserver.com prev=0.0752 webXray-root='Smart AdServer' Disconnect='Equativ' bidswitch.net prev=0.0746 webXray-root='IPONWEB' Disconnect='Criteo' turn.com prev=0.0661 webXray-root='Singtel' Disconnect='Nexxen' sharethrough.com prev=0.0659 webXray-root='Sharethrough' Disconnect='Equativ' lijit.com prev=0.0656 webXray-root='Federated Media' Disconnect='Sovrn' bidr.io prev=0.0619 webXray-root='Beeswax' Disconnect='Comcast' 2mdn.net prev=0.0616 webXray-root='Alphabet' Disconnect='Google' pippio.com prev=0.0594 webXray-root='Acxiom' Disconnect='LiveRamp' Tracker Radar vs Disconnect: facebook.net prev=0.1830 Tracker Radar='Facebook, Inc.' Disconnect='Meta' facebook.com prev=0.1665 Tracker Radar='Facebook, Inc.' Disconnect='Meta' jsdelivr.net prev=0.1242 Tracker Radar='Prospect One' Disconnect='Volentio JSD' casalemedia.com prev=0.1114 Tracker Radar='Index Exchange, Inc.' Disconnect='IndexExchange' crwdcntrl.net prev=0.0972 Tracker Radar='Lotame Solutions, Inc.' Disconnect='PublicisGroupe' stackadapt.com prev=0.0781 Tracker Radar='Collective Roll' Disconnect='StackAdapt' liadm.com prev=0.0755 Tracker Radar='LiveIntent Inc.' Disconnect='ZetaGlobal' smartadserver.com prev=0.0752 Tracker Radar='Smartadserver S.A.S' Disconnect='Equativ' bidswitch.net prev=0.0746 Tracker Radar='IPONWEB GmbH' Disconnect='Criteo' creativecdn.com prev=0.0724 Tracker Radar='RTB House S.A.' Disconnect='RTBHouse' turn.com prev=0.0661 Tracker Radar='Amobee, Inc' Disconnect='Nexxen' sharethrough.com prev=0.0659 Tracker Radar='Sharethrough, Inc.' Disconnect='Equativ' bidr.io prev=0.0619 Tracker Radar='Beeswax' Disconnect='Comcast' dotomi.com prev=0.0583 Tracker Radar='Conversant LLC' Disconnect='PublicisGroupe' temu.com prev=0.0555 Tracker Radar='Pinduoduo Inc.' Disconnect='PDD Holdings' outbrain.com prev=0.0550 Tracker Radar='Outbrain' Disconnect='Teads' 1rx.io prev=0.0546 Tracker Radar='RhythmOne' Disconnect='Nexxen' sitescout.com prev=0.0540 Tracker Radar='Centro, Inc.' Disconnect='BasisTechnologies' blismedia.com prev=0.0532 Tracker Radar='Blis Global Ltd' Disconnect='DT' simpli.fi prev=0.0519 Tracker Radar='Simplifi Holdings Inc.' Disconnect='Simpli.fi' postrelease.com prev=0.0513 Tracker Radar='Nativo, Inc' Disconnect='Life360' ipredictive.com prev=0.0506 Tracker Radar='Adelphic, Inc.' Disconnect='Viant' contextweb.com prev=0.0481 Tracker Radar='Pulsepoint, Inc.' Disconnect='Internet Brands' a-mo.net prev=0.0474 Tracker Radar='Monet Engine Inc.' Disconnect='AdaptMX' 360yield.com prev=0.0467 Tracker Radar='Improve Digital BV' Disconnect='Azerion' --- F. Named-entity residue of the suffix fold ----------------------- webXray owner names the fold leaves untouched: 782 of 827 (94.6%). The fold only removes legal forms; it merges no synonyms, so every figure in section D is a lower bound on real agreement and an upper bound on real disagreement.
K. Unedited output: scripts/owner_adjudication.py
Run as python3 scripts/owner_adjudication.py –table.
30 disagreements adjudicated 2026-08-17 against primary sources; 2 failed the sourcing bar and are EXCLUDED from every tally below, leaving 28. Excluded: 360yield.com (UNRESOLVED -- no dated primary source), fwmrm.net (acquired 2014; post-2026 spinoff UNRESOLVED) Selected as the highest-prevalence disagreements, NOT sampled at random: these tallies describe this set and are not an error rate for any list. List current stale granularity error absent webXray 1 17 4 1 5 Tracker Radar 8 12 6 2 0 Disconnect 21 0 0 0 7 webXray: has an entry for 23 of 28; of those, 1 name today's owner (4% of its own entries). Tracker Radar: has an entry for 28 of 28; of those, 8 name today's owner (29% of its own entries). Disconnect: has an entry for 21 of 28; of those, 21 name today's owner (100% of its own entries). The 'absent' column cannot be read as a coverage result either: the rows were ranked by Tracker Radar's own prevalence field, so Tracker Radar covering all 28 of 28 is partly how the sample was drawn. Rows scored as an outright error rather than staleness: 3 -- 1rx.io (webXray), jsdelivr.net (Tracker Radar), stackadapt.com (Tracker Radar) adnxs.com Microsoft Corporation stale current current https://www.prnewswire.com/news-releases/att-agrees-to-microsoft-acquisition-of-xandr-301448996.html rubiconproject.com Magnite, Inc. stale current current https://investor.magnite.com/news-releases/news-release-details/rubicon-project-and-telaria-complete-merger-following yahoo.com Yahoo Inc. (Apollo-managed funds majority) stale current absent https://www.apollo.com/insights-news/pressreleases/2021/09/apollo-funds-complete-acquisition-of-yahoo-161530593 facebook.com Meta Platforms, Inc. stale stale current https://about.fb.com/news/2021/10/facebook-company-is-now-meta/ bidr.io Comcast (FreeWheel/Beeswax) stale stale current https://corporate.comcast.com/press/releases/freewheel-acquires-beeswax turn.com Nexxen International Ltd. stale stale current https://investors.nexxen.com/news-releases/news-release-details/tremor-international-tremor-announces-closing-amobee-acquisition 1rx.io Nexxen International Ltd. error stale current https://nexxen.com/tremor-international-group-rebrands-as-nexxen/ outbrain.com Teads Holding Co. stale stale current https://investors.teads.com/news-releases/news-release-details/outbrain-completes-change-corporate-name-teads smartadserver.com Equativ stale stale current https://www.equativ.com/press/smart-adserver-rebrands-as-equativ sharethrough.com Equativ stale stale current https://www.equativ.com/press/equativ-and-sharethrough-will-now-operate-under-equativ-brand-solidifying-global-position-as-leading-end-to-end-media-platform postrelease.com Life360, Inc. (Nativo) stale stale current https://ads.life360.com/newsroom/life360-completes-acquisition-of-nativo-and-surpasses-50-million-us-mau crwdcntrl.net Publicis Groupe S.A. (Epsilon/Lotame) stale stale current https://www.publicisgroupe.com/en/news/press-releases/publicis-to-acquire-lotame-the-world-s-leading-independent-end-to-end-data-solution dotomi.com Publicis Groupe S.A. (Epsilon/Conversant) stale granularity current https://www.globenewswire.com/news-release/2019/07/02/1877064/0/en/Publicis-Groupe-finalizes-the-acquisition-of-Epsilon.html agkn.com TransUnion LLC stale current absent https://www.globenewswire.com/news-release/2021/12/01/2344146/0/en/TransUnion-and-Neustar-Announce-Transaction-Close.html rlcdn.com LiveRamp Holdings, Inc. stale current absent https://www.sec.gov/Archives/edgar/data/0000733269/000119312518279280/d616065d8k12b.htm tapad.com Experian plc stale granularity absent https://www.experianplc.com/newsroom/press-releases/2020/experian-acquires-tapad contextweb.com Internet Brands, Inc. (PulsePoint) absent stale current https://www.pulsepoint.com/press-releases/internet-brands-to-acquire-pulsepoint temu.com PDD Holdings Inc. absent stale current https://www.sec.gov/Archives/edgar/data/1737806/000110465924051610/pdd-20231231x20f.htm lijit.com Sovrn Holdings, Inc. stale current absent https://lijit.com/ teads.tv Teads Holding Co. stale current current https://www.globenewswire.com/news-release/2025/02/03/3019410/0/en/Outbrain-Completes-the-Acquisition-of-Teads.html blismedia.com Deutsche Telekom AG (T-Mobile US) absent stale current https://report.telekom.com/interim-report-q2-2025/financial-statements/significant-events-and-transactions/changes-in-the-composition-of-the-group.html jsdelivr.net Volentio JSD Limited granularity error current https://www.jsdelivr.com/documents/data-processing-agreement.pdf stackadapt.com StackAdapt Inc. (independent) absent error current https://www.stackadapt.com/legal-document-centre bidswitch.net Criteo S.A. (IPONWEB) granularity granularity current https://criteo.investorroom.com/2022-08-03-CRITEO-REPORTS-STRONG-SECOND-QUARTER-2022-RESULTS intentiq.com AlmondNet Group granularity granularity absent https://www.intentiq.com/who-we-are/ ipredictive.com Viant Technology LLC (Adelphic) absent granularity absent https://www.viantinc.com/company/news/press-releases/viant-completes-integration-of-adelphic-into-viant-advertising-cloud/ simpli.fi Simplifi Holdings Inc. (GTCR + Blackstone) granularity granularity current https://www.blackstone.com/news/press/simpli-fi-a-leading-programmatic-advertising-platform-announces-completion-of-significant-investment-from-blackstone-at-1-5-billion-valuation/ casalemedia.com Index Exchange, Inc. (independent) current current current https://www.indexexchange.com/team/andrew-casale/ 360yield.com Azerion Group N.V. (Improve Digital) current granularity current https://improvedigital.com/about/ EXCLUDED fwmrm.net Comcast Corporation (FreeWheel) current current absent https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=0001166691 EXCLUDED
Related
References
- [1]
- Steffens, Marius; Musch, Marius; Johns, Martin; Stock, Ben (2021): "Who’s Hosting the Block Party? Studying Third-Party Blockage of CSP and SRI", in: Proceedings of the Network and Distributed System Security Symposium. (Link)
- [2]
- Musa, Maaz Bin; Nithyanand, Rishab (2022): "ATOM: Ad-network Tomography", in: Proceedings on Privacy Enhancing Technologies. (DOI)
- [3]
- Libert, Timothy (2018): "An Automated Approach to Auditing Disclosure of Third-Party Data Collection in Website Privacy Policies", in: Proceedings of the ACM Web Conference. (DOI)
- [4]
- Sánchez-Rola, Iskander; Dell'Amico, Matteo; Balzarotti, Davide; Vervier, Pierre-Antoine; Bilge, Leyla (2021): "Journey to the Center of the Cookie Ecosystem: Unraveling Actors' Roles and Relationships", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)
- [5]
- Matte, Célestin; Bielova, Nataliia; Santos, Cristiana Teixeira (2020): "Do Cookie Banners Respect my Choice? Measuring Legal Compliance of Banners from IAB Europe's Transparency and Consent Framework", in: Proceedings of the IEEE Symposium on Security and Privacy. (DOI)
- [6]
- Yang, Zhiju; Yue, Chuan (2020): "A Comparative Measurement Study of Web Tracking on Mobile and Desktop Environments", in: Proceedings on Privacy Enhancing Technologies. (DOI)
- [7]
- Jakaria, Md; Huang, Danny Yuxing; Das, Anupam (2024): "Connecting the Dots: Tracing Data Endpoints in IoT Devices", in: Proceedings on Privacy Enhancing Technologies. (DOI)
- [8]
- McQuistin, Stephen; Snyder, Peter; Perkins, Colin; Haddadi, Hamed; Tyson, Gareth (2023): "A First Look at the Privacy Harms of the Public Suffix List", in: Proceedings of the ACM Internet Measurement Conference. (DOI)
- [9]
- Englehardt, Steven; Narayanan, Arvind (2016): "Online Tracking: A 1-million-site Measurement and Analysis", in: Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, pp. 1388–1401. Association for Computing Machinery, New York, NY, USA. (DOI) (Link)
- [10]
- Utz, Christine; Amft, Sabrina; Degeling, Martin; Holz, Thorsten; Fahl, Sascha; Schaub, Florian (2023): "Privacy Rarely Considered: Exploring Considerations in the Adoption of Third-Party Services by Websites", Proceedings on Privacy Enhancing Technologies 2023(1):5-28. (DOI)
- [11]
- Jannett, Louis; Mayer, Andreas; Westers, Maximilian; Mladenov, Vladislav; Mainka, Christian; Schwenk, Jörg (2026): "The State of Passkeys: Studying the Adoption and Security of Passkeys on the Web", in: Proceedings of the USENIX Security Symposium. (Link)
- [12]
- Selmo, Carlos; Carisimo, Esteban; Bustamante, Fabián E.; Alvarez-Hamelin, J. Ignacio (2025): "Learning AS-to-Organization Mappings with Borges", in: Proceedings of the 2025 ACM Internet Measurement Conference, pp. 120-133. (DOI)
- [13]
- Wu, Xiaoyuan; Hu, Lydia; Zeng, Eric; Habib, Hana; Bauer, Lujo (2025): "Transparency or Information Overload? Evaluating Users’ Comprehension and Perceptions of the iOS App Privacy Report", in: Proceedings of the Network and Distributed System Security Symposium. (Link)
- [14]
- Gouda, Deepak; Dainotti, Alberto; Testart, Cecilia (2025): "Prefix2Org: Mapping BGP Prefixes to Organizations", in: Proceedings of the ACM Internet Measurement Conference. (DOI)
- [15]
- Dambra, Savino; Sanchez-Rola, Iskander; Bilge, Leyla; Balzarotti, Davide (2022): "When Sally Met Trackers: Web Tracking From the Users' Perspective", in: Proceedings of the USENIX Security Symposium. (Link)
