| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| privacy:privacy_sandbox [2026/09/01 16:59] – Apply review findings: fix four folding false positives (FLEDGE/full-fledge, First Party Sets as a verb phrase, lowercase attribution reporting matching Apple SKAdNetwork), which moves the reach total 72->67 and several family counts; regenerate the by-ye karel.kubicek.claude | privacy:privacy_sandbox [2026/09/27 22:13] (current) – Removal-status refresh 2026-09-27: status column, top box, timeline, CDP/header sections re-based on a 14-build probe (151–156, incl. Chrome for Testing); new 'removal staircase, measured' subsection; M153 is no longer called the removal milestone; correc karel.kubicek.claude |
|---|
| * On **2025-10-17** Google announced it would **retire ten Privacy Sandbox technologies**: "Attribution Reporting API (Chrome and Android), IP Protection, On-Device Personalization, Private Aggregation (including Shared Storage), Protected Audience (Chrome and Android), Protected App Signals, Related Website Sets (including requestStorageAccessFor and Related Website Partition), SelectURL, SDK Runtime and Topics (Chrome and Android)".((Anthony Chavez, VP Privacy Sandbox, [[https://privacysandbox.google.com/blog/update-on-plans-for-privacy-sandbox-technologies|"Update on Plans for Privacy Sandbox Technologies"]], 2025-10-17. Fetched and quoted verbatim 2026-09-01.)) **CHIPS, FedCM and Private State Tokens continue.** | * On **2025-10-17** Google announced it would **retire ten Privacy Sandbox technologies**: "Attribution Reporting API (Chrome and Android), IP Protection, On-Device Personalization, Private Aggregation (including Shared Storage), Protected Audience (Chrome and Android), Protected App Signals, Related Website Sets (including requestStorageAccessFor and Related Website Partition), SelectURL, SDK Runtime and Topics (Chrome and Android)".((Anthony Chavez, VP Privacy Sandbox, [[https://privacysandbox.google.com/blog/update-on-plans-for-privacy-sandbox-technologies|"Update on Plans for Privacy Sandbox Technologies"]], 2025-10-17. Fetched and quoted verbatim 2026-09-01.)) **CHIPS, FedCM and Private State Tokens continue.** |
| * The same day, the UK CMA **closed** its Privacy Sandbox investigation and released Google from the commitments that had constrained the project since 2022. Case opened 2021-01-07, closed **2025-10-17**.(([[https://www.gov.uk/cma-cases/investigation-into-googles-privacy-sandbox-browser-changes|CMA case page, "Investigation into Google's 'Privacy Sandbox' browser changes"]]: "Case state: Closed", "Opened: 7 January 2021", "Closed: 17 October 2025". Fetched 2026-09-01.)) | * The same day, the UK CMA **closed** its Privacy Sandbox investigation and released Google from the commitments that had constrained the project since 2022. Case opened 2021-01-07, closed **2025-10-17**.(([[https://www.gov.uk/cma-cases/investigation-into-googles-privacy-sandbox-browser-changes|CMA case page, "Investigation into Google's 'Privacy Sandbox' browser changes"]]: "Case state: Closed", "Opened: 7 January 2021", "Closed: 17 October 2025". Fetched 2026-09-01.)) |
| * **They have not been removed yet.** As of **2026-09-01**, every one of those Chrome Platform Status "Deprecate and remove" entries is still marked //Proposed//, and Chromium **151.0.7922.34** exposes and answers every one of the APIs — measured on this page. Chrome stable today is **M152** (2026-08-25). The removal milestone for Topics, Protected Audience, Attribution Reporting, Shared Storage, Related Website Sets and ''requestStorageAccessFor'' is **M153, whose stable date is 2026-09-08**. | * **The ads APIs do nothing in any build from M152 on, but most of their methods are still defined.** As of **2026-09-27** (Chrome stable M154), this page probed fourteen builds from 151 to 156, four of them Google Chrome for Testing. In every one from 152 on, a Topics call throws, Attribution Reporting sends no request headers, and no Protected Audience auction runs. Yet ''document.browsingTopics'', ''navigator.runAdAuction'' and ''attributionSrc'' are still there, so **a ''typeof'' sweep detects stubs**. Gone outright: ''window.sharedStorage'' from 153, ''requestStorageAccessFor'' from 154. Fenced Frames are still present. Evidence and caveats are in [[#The removal staircase, measured]]. |
| * So there is a window, it is short, and **the browser version is the single most important thing to pin and report** in any Privacy Sandbox measurement. See [[#What to Report]]. | * **No public status source records what shipped when; the binaries do.** Chrome Platform Status still reads //Proposed//, milestone 153, for removals that have shipped, and has no Topics removal entry at all. The release notes put ''requestStorageAccessFor'' a milestone early. |
| | * **The last step is a field trial your crawler never joins.** Chrome is now removing the Topics and Protected Audience stubs themselves for real users: 1% of stable, with 10% and then 100% requested for October. A Playwright launch with a fresh profile has no variations seed (Playwright passes ''%%--disable-field-trial-config%%''), so your crawler keeps the stub. Puppeteer 25.5 does not pass that flag; we did not test whether its launch picks up a seed. Some real users will have no method at all, if that is what removing a stub does; no automation build can show it. |
| | * **The browser version, and the kind of binary, are the most important things to pin and report** in any Privacy Sandbox measurement. "The latest Chrome" is now a build in which the ads APIs do nothing. See [[#What to Report]]. |
| </WRAP> | </WRAP> |
| |
| * **Fledging Will Continue Until Privacy Improves** {[calderonio2024_fledging]}, USENIX Security 2024 — the only deployment-scale crawl of Protected Audience in this corpus, and the model for how to instrument one. Read §3 for the method (wrapper functions injected by Puppeteer) before you read the results. | * **Fledging Will Continue Until Privacy Improves** {[calderonio2024_fledging]}, USENIX Security 2024 — the only deployment-scale crawl of Protected Audience in this corpus, and the model for how to instrument one. Read §3 for the method (wrapper functions injected by Puppeteer) before you read the results. |
| * **Exploiting the Shared Storage API** {[nisenoff2025_exploiting]}, CCS 2025 — the most recent Privacy Sandbox measurement in the corpus, and the one that shows what the //attestation// artefacts give you for free. | * **Exploiting the Shared Storage API** {[nisenoff2025_exploiting]}, CCS 2025 — the most recent Privacy Sandbox measurement in the corpus, and the one that shows what the //attestation// artefacts give you for free. |
| * **Interest-disclosing Mechanisms for Advertising are Privacy-Exposing (not Preserving)** {[beugin2024_interest]}, PoPETs 2024 — the systematic privacy analysis of Topics, with the re-identification numbers everyone cites. | * **Interest-disclosing Mechanisms for Advertising are Privacy-Exposing (not Preserving)** {[beugin2024_interest]}, PoPETs 2024 — the systematic privacy analysis of Topics, with the most-cited re-identification numbers in this area. |
| * **A First Look at Related Website Sets** {[mcquistin2024_first]}, IMC 2024 — the template for measuring a Privacy Sandbox //governance// artefact (a GitHub list and its pull requests) rather than a browser API. | * **A First Look at Related Website Sets** {[mcquistin2024_first]}, IMC 2024 — the template for measuring a Privacy Sandbox //governance// artefact (a GitHub list and its pull requests) rather than a browser API. |
| * Then the primary sources, because no paper is current: Google's own [[https://privacysandbox.google.com/overview/status|Privacy Sandbox feature status]] page and the per-feature entries on [[https://chromestatus.com/|Chrome Platform Status]]. | * Then the primary sources, because no paper is current: Google's own [[https://privacysandbox.google.com/overview/status|Privacy Sandbox feature status]] page and the per-feature entries on [[https://chromestatus.com/|Chrome Platform Status]] for ship dates and plans. Neither records the removals, so for what the binaries actually do, read [[#The removal staircase, measured]]. |
| |
| ===== What Shipped, and What Is Being Removed ===== | ===== What Shipped, and What Is Being Removed ===== |
| |
| Every row was checked on **2026-09-01** against Chrome Platform Status' JSON API and Google's own status page — not against documentation, blog posts or memory. The //Detection// column is the expression this page measured in Chromium 151.0.7922.34; read [[#Presence is not availability, and neither is a return value]] before you use it. | Ship milestones were checked on **2026-09-01** and removal status on **2026-09-27**, against Chrome Platform Status' JSON API, Chrome's release notes, the blink-dev intent threads, Google's own status page and fourteen binaries (ten Chromium, four Google Chrome for Testing) — not against documentation, blog posts or memory. The //Detection// column is the expression this page measured. From M152 most of these expressions test for a **stub**, so read [[#Presence is not availability, and neither is a return value]] before you use one. |
| |
| ^ API ^ Former names ^ Shipped ^ Status on 2026-09-01 ^ Detection expression ^ | ^ API ^ Former names ^ Shipped ^ Status on 2026-09-27 ^ Detection expression ^ |
| | **Topics** | FLoC (different design) | M115, 2023-07-18 | Enabled by default. **Removal proposed, M153** | ''typeof document.browsingTopics'' | | | **Topics** | FLoC (different design) | M115, 2023-07-18 | **Stub from M152**: the call throws, the method remains. No Chrome Platform Status removal entry | ''typeof document.browsingTopics'' — true of the stub | |
| | **Protected Audience** | FLEDGE, TURTLEDOVE | M115, 2023-07-18 | Enabled by default. **Removal proposed, M153** | ''%%'joinAdInterestGroup' in navigator%%'' | | | **Protected Audience** | FLEDGE, TURTLEDOVE | M115, 2023-07-18 | **No auction runs from M152** (headless shell; full Chromium ran none in 151 either). The methods remain, a stub per the blink-dev plan. Removal entry //Proposed//, M153 | ''%%'joinAdInterestGroup' in navigator%%'' — true of the stub | |
| | **Attribution Reporting** | Conversion Measurement API | M115, 2023-07-18 | Enabled by default. **Removal proposed, M153** | ''%%'attributionSrc' in HTMLAnchorElement.prototype%%'' | | | **Attribution Reporting** | Conversion Measurement API | M115, 2023-07-18 | **Inert from M152**: no request header, no longer a known Permissions-Policy feature; ''attributionSrc'' remains. Removal entry //Proposed//, M153 | ''%%'attributionSrc' in HTMLAnchorElement.prototype%%'' — true in 156 | |
| | **Shared Storage** (incl. ''selectURL'') | — | M115, 2023-07-18 | **Removal proposed, M153** | ''%%'sharedStorage' in window%%'' | | | **Shared Storage** (incl. ''selectURL'') | — | M115, 2023-07-18 | **Removed from M153** (disabled in 152; full Chromium already refused it in 151). Removal entry //Proposed//, M153 | ''%%'sharedStorage' in window%%'' | |
| | **Private Aggregation** | — | M115, 2023-07-18 | **Removal proposed, M152.** Reachable only from Shared Storage and Protected Audience worklets | ''privateAggregation'' inside a worklet | | | **Private Aggregation** | — | M115, 2023-07-18 | "Deprecated and removed" in M152 per the release notes; it is no longer a known Permissions-Policy feature from M153. Removal entry //Proposed//, M152. Reachable only from Shared Storage and Protected Audience worklets | ''privateAggregation'' inside a worklet — not probed | |
| | **Fenced Frames** | — | M115, 2023-07-18 | **Removal proposed, M155** | ''%%'HTMLFencedFrameElement' in window%%'' | | | **Fenced Frames** | — | M115, 2023-07-18 | **Still present in 156.0.8075.0**, an early 156 build. Removal proposed, **M156** (the entry said 155 on 2026-09-01) | ''%%'HTMLFencedFrameElement' in window%%'' | |
| | **Related Website Sets** | First-Party Sets | M115, 2023-07-18 | **Removal proposed, M153.** The submission repository is **archived** | none — inferred from ''requestStorageAccess'' behaviour | | | **Related Website Sets** | First-Party Sets | M115, 2023-07-18 | Removal entry //Proposed//, M153; listed in the M153 release notes. **Not probed behaviourally.** The submission repository is **archived** | none — inferred from ''requestStorageAccess'' behaviour | |
| | ''requestStorageAccessFor()'' | — | M115, 2023-07-18 | **Removal proposed, M153** | ''%%'requestStorageAccessFor' in document%%'' | | | ''requestStorageAccessFor()'' | — | M115, 2023-07-18 | **Removed from M154** — one milestone after its entry and the release notes | ''%%'requestStorageAccessFor' in document%%'' | |
| | **CHIPS** — the ''Partitioned'' cookie attribute | — | **M114, 2023-05-30** | **Continues.** Explicitly kept on 2025-10-17 | none — no JS surface; set and read back a ''%%Partitioned; Secure%%'' cookie | | | **CHIPS** — the ''Partitioned'' cookie attribute | — | **M114, 2023-05-30** | **Continues.** Explicitly kept on 2025-10-17((A separate Chrome Platform Status entry, 5279664766713856, "Deprecate CHIPS and Relaunch in WebView", is about Android WebView only: its ''CookieManager'' cannot query partitioned cookies. It is //Proposed// with a WebView milestone of 128 and no Chrome desktop or Android milestone (fetched 2026-09-27). It does not affect Chrome.)) | none — no JS surface; set and read back a ''%%Partitioned; Secure%%'' cookie | |
| | **Storage Access API** | — | M115 per Chrome Platform Status; **"Chrome 119 and higher"** per Google's status page((The two Google sources disagree. Chrome Platform Status feature 5612590694662144 reports "Enabled by default", desktop milestone 115; ''privacysandbox.google.com/overview/status'' says "Storage Access API supported by default from Chrome 119 an higher" (//sic//). Both fetched 2026-09-01. If the exact milestone matters to your claim, test it against the binaries rather than trusting either.)) | **Continues** | ''%%'requestStorageAccess' in document%%'' | | | **Storage Access API** | — | M115 per Chrome Platform Status; **"Chrome 119 and higher"** per Google's status page((The two Google sources disagree. Chrome Platform Status feature 5612590694662144 reports "Enabled by default", desktop milestone 115; ''privacysandbox.google.com/overview/status'' says "Storage Access API supported by default from Chrome 119 an higher" (//sic//). Both fetched 2026-09-01. If the exact milestone matters to your claim, test it against the binaries rather than trusting either.)) | **Continues** | ''%%'requestStorageAccess' in document%%'' | |
| | **Private State Tokens** | Trust Tokens | M115, 2023-07-18 | **Continues.** Explicitly kept on 2025-10-17 | ''typeof document.hasPrivateToken'' | | | **Private State Tokens** | Trust Tokens | M115, 2023-07-18 | **Continues.** Explicitly kept on 2025-10-17 | ''typeof document.hasPrivateToken'' | |
| | **FedCM** | WebID | M108 | **Continues.** Explicitly kept on 2025-10-17 | ''%%'IdentityCredential' in window%%'' | | | **FedCM** | WebID | M108 | **Continues.** Explicitly kept on 2025-10-17 | ''%%'IdentityCredential' in window%%'' | |
| | **Bounce tracking mitigations** | — | M116, 2023-08-15 | **Continues.** Not an API — a heuristic that clears state | none | | | **Bounce tracking mitigations** | — | M116, 2023-08-15 (default-on for users who block third-party cookies followed later in 2023 — see [[Privacy:Browser storage#"We cleared cookies" is not a reset]]) | **Continues.** Not an API — a heuristic that clears state | none | |
| | **User-Agent Client Hints / UA reduction** | — | rollout from M89; deprecation trial ended 2023-09-23 | **Continues** | ''%%'userAgentData' in navigator%%'' | | | **User-Agent Client Hints / UA reduction** | — | rollout from M89; deprecation trial ended 2023-09-23 | **Continues** | ''%%'userAgentData' in navigator%%'' | |
| | **IP Protection** | Gnatcatcher | never shipped | **Discontinued** 2025-10-17. Its repository was archived 2025-11-03 | — | | | **IP Protection** | Gnatcatcher | never shipped | **Discontinued** 2025-10-17. Its repository was archived 2025-11-03 | — | |
| | **Privacy Budget** | — | never shipped | Never implemented in any browser | — | | | **Privacy Budget** | — | never shipped | Never implemented in any browser | — | |
| | **FLoC** | — | origin trial only, Chrome 89, 2021 | Withdrawn January 2022 and replaced by Topics | — | | | **FLoC** | — | origin trial only, Chrome 89, 2021 | Withdrawn January 2022 and replaced by Topics | — | |
| | **Privacy Sandbox on Android** (SDK Runtime, Topics, Protected Audience, Attribution, Protected App Signals, On-Device Personalization) | — | — | **All scheduled for phaseout** | not a web surface | | | **Privacy Sandbox on Android** (SDK Runtime, Topics, Protected Audience, Attribution, Protected App Signals, On-Device Personalization) | — | — | **All listed as //Deprecate and remove//** | not a web surface | |
| |
| Google's status page also lists **Fenced Storage Read, Private Proofs, Probabilistic Reveal Tokens** and **Script Blocking** as //Do not launch//, and **Partitioned Popins** and **Related Website Partition** as //Discontinue//. If you meet one of those names in a 2024 explainer, it never shipped.((''privacysandbox.google.com/overview/status'', "Last updated: August 14, 2026". Fetched 2026-09-01.)) | Google's status page also lists **Fenced Storage Read, Private Proofs, Probabilistic Reveal Tokens** and **Script Blocking** as //Do not launch//, and **Partitioned Popins** and **Related Website Partition** as //Discontinue//. If you meet one of those names in a 2024 explainer, it never shipped.((''privacysandbox.google.com/overview/status'', "Last updated: August 14, 2026". Fetched 2026-09-01 and again 2026-09-27, unchanged. It still files the removed Shared Storage under the same //Deprecate and remove// heading as the unremoved Fenced Frames, so it cannot tell you which have gone. Fetch it with ''?hl=en'': without it, this run was served the page in Spanish.)) |
| | |
| | ==== The removal staircase, measured ==== |
| | |
| | The table above is what you need to design a crawl. This one is the evidence for its status column. Each API is shown as Chrome Platform Status and the release notes describe it, and as the binaries behave. Fourteen builds were probed. **Google Chrome for Testing** 153.0.8010.52 and 154.0.8037.57 are the stable patches; 155.0.8059.12 is beta. 156.0.8075.0 is a pre-branch build: M156 branches on 2026-09-28, and "156" below means that build. No arm64 build of 152 exists. **Debian's arm64 Chromium** 152.0.7977.82, 153.0.8010.52 and 154.0.8037.57 are the stable patches. The rest are **Playwright's bundled headless shells and Chromium**: 151, and the pre-stable 152, 153, 154 and 155. All were launched through Playwright, headless, with a fresh profile. Playwright passes ''%%--disable-field-trial-config%%'', so none could hold a variations seed. "Known policy feature" means listed by ''document.featurePolicy.features()''. From 152 on, the three kinds of binary agree on every row. In 151 they do not: full Chromium already refused the Protected Audience auction and Shared Storage calls that the headless shell still ran. So where a change is dated "152" below, the comparison is headless shell against headless shell. |
| | |
| | ^ API ^ Chrome Platform Status removal entry ^ Chrome release notes ^ First build where the change was measured ^ Real-user rollout of the stub removal ^ |
| | | Topics | **none** | not listed, 150–154 | **152**: call throws ''NotSupportedError''. Method still defined in 156; ''browsing-topics'' still a known Permissions-Policy feature | 1% of M153+ stable; asked 2026-09-24 for 10% through Oct 15, 100% after | |
| | | Protected Audience | //Proposed//, M153 | M153, "planned for deprecation and removal" | **152**: the headless shell's auction fetches no bidding or decision script (full Chromium fetched none in 151 either); CDP interest-group surface gone. **153**: ''join-ad-interest-group'' and ''run-ad-auction'' no longer known policy features. Methods still defined in 156 | 1% of M152+ stable; asked 2026-09-24 for 10% through Oct 12, 100% from Oct 26 | |
| | | Attribution Reporting | //Proposed//, M153 | M153, "planned" | **152**: ''Attribution-Reporting-Eligible'' no longer sent; ''attribution-reporting'' no longer a known policy feature. ''attributionSrc'' still defined in 156 | no update after 2026-07-01 | |
| | | Shared Storage | //Proposed//, M153 | M153, "planned" | **152**: calls reject "Shared Storage is disabled" (full Chromium: already in 151). **153**: ''window.sharedStorage'' undefined. **154**: CDP surface gone | no update after 2026-07-07 | |
| | | Private Aggregation | //Proposed//, M152 | M152, "is deprecated and removed" | **153**: ''private-aggregation'' no longer a known policy feature. Worklet call not probed | the thread planned no stub; no update after 2026-07-08 | |
| | | Related Website Sets | //Proposed//, M153 | M153, "planned" | not probed. CDP ''Storage.getRelatedWebsiteSets'' present through 155, gone in 156.0.8075.0 and at tip-of-tree | not checked | |
| | | ''requestStorageAccessFor'' | //Proposed//, M153 | M153, "planned" | **154**: undefined (still defined in 153.0.8010.52) | not checked | |
| | | Fenced Frames | //Proposed//, **M156** | — | present in 156.0.8075.0 | — | |
| | |
| | **The plan behind the staircase.** The blink-dev removal intents of November 2025 said "deprecate in M144 and remove in M150". In June 2026 the Topics, Protected Audience, Attribution Reporting and Shared Storage threads each posted the same four steps. At **M150**, the settings UI is removed "via field trial", after which "all API invocations for field-trial enabled browsers will always reject". At **M152**, Chrome would "permanently remove the underlying implementation code for the API, and replace it with a lightweight stub API". Steps three and four remove the stub itself by field trial, 1% of stable first.((Quoted from the Protected Audience thread, Paul Jensen, blink-dev, 2026-06-12. The Topics, Attribution Reporting and Shared Storage threads carry the same four steps word for word. Private Aggregation's says "There is no need to replace it with a stub API". [[https://groups.google.com/a/chromium.org/g/blink-dev/c/k_nubsMb97g|k_nubsMb97g]] (Protected Audience), [[https://groups.google.com/a/chromium.org/g/blink-dev/c/_R85yctz4Rs|_R85yctz4Rs]] (Topics), [[https://groups.google.com/a/chromium.org/g/blink-dev/c/4K2RRt6VYCQ|4K2RRt6VYCQ]] (Attribution Reporting), [[https://groups.google.com/a/chromium.org/g/blink-dev/c/uh5Ke6qyegc|uh5Ke6qyegc]] (Shared Storage), [[https://groups.google.com/a/chromium.org/g/blink-dev/c/Ld7avyD0U0Q|Ld7avyD0U0Q]] (Private Aggregation), all fetched 2026-09-27. "Newest message" in the table means the newest date stamp in the server-rendered thread page; the count was not checked against Google Groups' own.)) Shared Storage did not follow its own plan: ''window.sharedStorage'' is gone from 153 without any field trial. None of the messages we fetched says whether the M150 rejection trial ever reached stable users. On 2026-09-24 the Protected Audience thread asked to hold the stub removal at "10% Stable ... (through Oct 12)" and to roll out to 100% "starting Oct 26". The Topics thread asked for 10% "through Oct 15" and 100% "after Oct 15". Both are requests, not events. |
| | |
| | Three things to take from it. First, **"stable M153" was never a single event**: behaviour changed at 152, some code left at 153, more at 154, and the stubs remain in 156. Second, **no public status source was right**. Chrome Platform Status still reads //Proposed// for removals that have shipped. The release notes put ''requestStorageAccessFor'' a milestone early and list nothing for M154. Google's status page files a removed API next to one that is still there. Third, **a feature-detection sweep in a 2026 crawl is detecting stubs.** And the kind of binary mattered even before the removal milestones: full Chromium 151 refused Shared Storage and ran no auction, while Playwright's default headless shell 151 did both — see [[#Presence is not availability, and neither is a return value]]. The probe and its full output are on the [[provenance:privacy:privacy_sandbox#Milestone probe, 2026-09-27|provenance page]]. |
| |
| ==== The timeline, because the roadmap is not the platform ==== | ==== The timeline, because the roadmap is not the platform ==== |
| | **2025-10-17** | **Ten technologies retired.** The CMA closes its investigation the same day | | | **2025-10-17** | **Ten technologies retired.** The CMA closes its investigation the same day | |
| | 2025-11-03 / 2025-11-21 | The ''ip-protection'' and ''related-website-sets'' GitHub repositories are archived | | | 2025-11-03 / 2025-11-21 | The ''ip-protection'' and ''related-website-sets'' GitHub repositories are archived | |
| | **2026-08-25** | **M152** reaches stable. Private Aggregation's removal is targeted here, still marked //Proposed// | | | 2026-06-11/12 | The four-step plan (M150 field-trial rejection, M152 stub, then field-trial removal of the stub) is posted to four of the five blink-dev removal intents; Private Aggregation's has no stub step | |
| | **2026-09-08** | **M153** stable date: the targeted removal milestone for Topics, Protected Audience, Attribution Reporting, Shared Storage, RWS and ''requestStorageAccessFor'' | | | **2026-08-25** | **M152** reaches stable. Topics calls throw, the headless shell stops running auctions, Attribution Reporting and Topics stop sending their request headers, and Shared Storage is disabled (measured). The release notes list Private Aggregation as removed | |
| | | **2026-09-08** | **M153** reaches stable. ''window.sharedStorage'' is gone (measured). The release notes list five "planned" removals; Chrome Platform Status still says //Proposed// | |
| | | **2026-09-22** | **M154** reaches stable. ''requestStorageAccessFor'' is gone, as is the CDP Shared Storage surface (measured). The release notes list no removals | |
| | | 2026-09-24 | blink-dev: stub removal at 1% of stable for Topics and Protected Audience; 10% then 100% requested for October | |
| |
| <WRAP tip> | <WRAP tip> |
| |
| ===== Detecting and Recording the APIs from a Crawl ===== | ===== Detecting and Recording the APIs from a Crawl ===== |
| | |
| | <WRAP tip> |
| | **If you start a crawl today (Chrome stable M154).** On any current build the ads APIs are stubs or gone, and their CDP events and request headers are gone with them. A current crawl can measure one thing: which site scripts still //call// the APIs, with the wrapper route below. To measure the APIs doing something you need a pinned pre-152 **chrome-headless-shell**, not full Chromium, which already refused the auction and Shared Storage in 151. Chrome-headless-shell 151 is the newest build in which this page saw an auction run. Your result is then about that binary, not about what users' browsers do. Report the items in [[#What to Report]]. |
| | </WRAP> |
| |
| ==== Presence is not availability, and neither is a return value ==== | ==== Presence is not availability, and neither is a return value ==== |
| |
| **Measured here, 2026-09-01, Chromium 151.0.7922.34 as shipped with Playwright 1.62.1.** Every Privacy Sandbox JS surface is present under the default flags of both Playwright and Puppeteer, and ''document.featurePolicy.allowsFeature()'' returns ''true'' for all six ads-API Permissions-Policy features (''browsing-topics'', ''join-ad-interest-group'', ''run-ad-auction'', ''attribution-reporting'', ''shared-storage'', ''private-aggregation''). Adding ''%%--enable-features=PrivacySandboxAdsAPIsOverride%%'' changed nothing, in either library. (Puppeteer was pointed at the same Chromium binary via ''chromium.executablePath()'', so this is a comparison of the two libraries' **default flag sets**, not of two browser builds.) | **Measured here, 2026-09-01, Chromium 151.0.7922.34 as shipped with Playwright 1.62.1** — a build from before the removals; for what changed at 152–156 see [[#The removal staircase, measured]]. Every Privacy Sandbox JS surface is present under the default flags of both Playwright and Puppeteer, and ''document.featurePolicy.allowsFeature()'' returns ''true'' for all six ads-API Permissions-Policy features (''browsing-topics'', ''join-ad-interest-group'', ''run-ad-auction'', ''attribution-reporting'', ''shared-storage'', ''private-aggregation''). Adding ''%%--enable-features=PrivacySandboxAdsAPIsOverride%%'' changed nothing, in either library. (Puppeteer was given ''chromium.executablePath()'', which is the full Chromium, while Playwright's default launched chrome-headless-shell. So this compared two libraries' default flag sets **and** two kinds of binary. Presence and Permissions-Policy answers were identical in both, and the 2026-09-27 probe confirms that for the two 151 builds.) |
| |
| That is the easy half. The hard half is that **calling them tells you nothing either**. On an HTTPS page served from a domain that is definitely not enrolled, every call returned a benign empty value rather than throwing: | That is the easy half. The hard half is that **calling them tells you nothing either**. On an HTTPS page served from a domain that is definitely not enrolled, seven of eight calls returned a benign empty value rather than throwing, and the eighth threw for a reason that has nothing to do with the Privacy Sandbox: |
| |
| <code> | <code> |
| navigator.runAdAuction() RETURNED null | navigator.runAdAuction() RETURNED null |
| sharedStorage.set() RETURNED undefined | sharedStorage.set() RETURNED undefined |
| | sharedStorage.worklet.addModule() OperationError: Rejecting load of https://…/w.js |
| | due to unexpected MIME type. |
| document.hasPrivateToken() RETURNED false | document.hasPrivateToken() RETURNED false |
| document.requestStorageAccess() RETURNED undefined | document.requestStorageAccess() RETURNED undefined |
| </code> | </code> |
| |
| The same four outputs came back from ''localhost'', from a mapped non-enrolled public-looking domain, with the ads-API override on, and with ''%%--privacy-sandbox-enrollment-overrides%%'' pointed at the origin. **A crawler cannot distinguish "the API is on and there was nothing to report" from "the API is off for this profile" from "this caller is not enrolled" by looking at the return value.** An empty Topics array is the expected result on a fresh profile with no history, and it is also what a disabled API gives you. | The one error is an artefact of the probe, not of the API: that server returns ''text/html'' for every path, and a worklet module must be served as JavaScript. It is left in rather than trimmed out, because the trimmed version was on this page for one revision and a reviewer caught the difference between "no call threw" and "no call threw except the one I removed". |
| |
| The consequence for a measurement is direct: **do not report "N% of sites can use the Topics API" from a feature-detection sweep.** Presence of the symbol is a fact about the browser build, identical on every site. The only site-level facts are (a) whether site code //called// the API, and (b) whether the caller is enrolled — and those need the instrumentation below. | The same four outputs came back from ''localhost'', from a mapped non-enrolled public-looking domain, with the ads-API override on, and with ''%%--privacy-sandbox-enrollment-overrides%%'' pointed at the origin. **Those calls ran in chrome-headless-shell**, which is what Playwright's ''headless: true'' launches. On 2026-09-27 the same calls went to the //full// Chromium 151 of the same Playwright release, via ''executablePath''. There ''sharedStorage.set()'' rejected with "sharedStorage is disabled", and an auction with a served bidding and decision script fetched neither script. The headless shell ran the same auction to a ''urn:uuid''. The shell lacks part of the settings layer a full browser has; that is our reading of the difference, and we did not test it. Either way, "which Chromium" includes "which kind of Chromium binary", and it changes results before any removal milestone. **A crawler cannot distinguish "the API is on and there was nothing to report" from "the API is off for this profile" from "this caller is not enrolled" by looking at the return value.** An empty Topics array is the expected result on a fresh profile with no history, and it is also what a disabled API gives you. |
| | |
| | The consequence for a measurement is direct: **do not report "N% of sites can use the Topics API" from a feature-detection sweep.** Presence of the symbol is a fact about the browser build, identical on every site — and from M152 the symbol is a stub that works on no site. The only site-level facts are (a) whether site code //called// the API, and (b) whether the caller is enrolled — and those need the instrumentation below. |
| |
| ==== Chrome DevTools Protocol: what it covers, and for how long ==== | ==== Chrome DevTools Protocol: what it covers, and for how long ==== |
| |
| Chromium's CDP ''Storage'' domain carries first-class Privacy Sandbox instrumentation, which is far cheaper than injecting wrappers. Enumerated from the browser's own ''/json/protocol'' descriptor, Chromium 151.0.7922.34, 2026-09-01: | Through M151 (interest groups) and M153 (Shared Storage), Chromium's CDP ''Storage'' domain carried first-class Privacy Sandbox instrumentation, far cheaper than injecting wrappers. Enumerated from the browser's own ''/json/protocol'' descriptor, Chromium 151.0.7922.34, 2026-09-01: |
| |
| ^ CDP ''Storage'' surface ^ Present in Chromium 151 ^ Present at Chromium tip-of-tree ^ | ^ CDP ''Storage'' surface ^ Present in Chromium 151 ^ Present at Chromium tip-of-tree ^ |
| | ''setSharedStorageTracking'', ''getSharedStorageMetadata'', ''getSharedStorageEntries'', ''setSharedStorageEntry'', ''deleteSharedStorageEntry'', ''clearSharedStorageEntries'', ''resetSharedStorageBudget'' | yes | **gone** | | | ''setSharedStorageTracking'', ''getSharedStorageMetadata'', ''getSharedStorageEntries'', ''setSharedStorageEntry'', ''deleteSharedStorageEntry'', ''clearSharedStorageEntries'', ''resetSharedStorageBudget'' | yes | **gone** | |
| | events ''interestGroupAccessed'', ''interestGroupAuctionEventOccurred'', ''interestGroupAuctionNetworkRequestCreated'', ''sharedStorageAccessed'', ''sharedStorageWorkletOperationExecutionFinished'' | yes | **gone** | | | events ''interestGroupAccessed'', ''interestGroupAuctionEventOccurred'', ''interestGroupAuctionNetworkRequestCreated'', ''sharedStorageAccessed'', ''sharedStorageWorkletOperationExecutionFinished'' | yes | **gone** | |
| | ''runBounceTrackingMitigations'', ''getRelatedWebsiteSets'' | yes | yes | | | ''runBounceTrackingMitigations'' | yes | yes | |
| | | ''getRelatedWebsiteSets'' | yes | **gone** (present through 155; absent from Chrome for Testing 156.0.8075.0 and from ''master'' on 2026-09-27) | |
| | | ''setAttributionReportingTracking'', ''setAttributionReportingLocalTestingMode'', ''sendPendingAttributionReports'' and the events ''attributionReportingSourceRegistered'', ''attributionReportingTriggerRegistered'', ''attributionReportingReportSent'', ''attributionReportingVerboseDebugReportSent'' | **no — removed before this build** | gone | |
| | anything for **Topics** | **no** | no | | | anything for **Topics** | **no** | no | |
| | anything for **Attribution Reporting** | **no** | no | | |
| |
| Tip-of-tree is the ''ChromeDevTools/devtools-protocol'' ''master'' descriptor, fetched 2026-09-01: the Privacy Sandbox commands and **all five events** are already absent there. **The instrumentation is being removed with the API.** If you intend to record Protected Audience or Shared Storage activity, pin a Chromium at or before the removal milestone and say which one; a crawl on evergreen Chrome will silently stop producing events. | Tip-of-tree is the ''ChromeDevTools/devtools-protocol'' ''master'' descriptor, fetched 2026-09-01: the Privacy Sandbox commands and **all five events** are already absent there. **The instrumentation is removed with the API, and sometimes first.** Measured in the shipping binaries' own ''/json/protocol'' on 2026-09-27: the three interest-group commands and three events are **gone from 152**, and the seven Shared Storage commands and two events are **gone from 154**. So to record Protected Audience activity you need **M151 or earlier**, and Shared Storage **M153 or earlier** — and Shared Storage calls already reject in 152. In practice both mean **M151 as chrome-headless-shell**, Playwright's default. It is the only 151 binary in which this page saw either API do anything; full Chromium 151 refused both. A crawl on evergreen Chrome produces no events at all. |
| | |
| | <WRAP important> |
| | **Attribution Reporting lost its CDP surface in April 2026 and its request header in M152.** The ''Storage'' domain carried three ARA commands and four ARA events — ''setAttributionReportingTracking'', ''setAttributionReportingLocalTestingMode'', ''sendPendingAttributionReports'', and ''attributionReportingSourceRegistered'', ''attributionReportingTriggerRegistered'', ''attributionReportingReportSent'', ''attributionReportingVerboseDebugReportSent''. Bisecting the ''devtools-protocol'' repository on 2026-09-01: all seven are present at commit ''1abe750809'' (2026-03-25) and gone at ''96e032552f'' (2026-04-02, "Roll protocol to r1608973"), so they left the protocol on **2026-04-02**. Chromium 151 rejects the toggle with a protocol error, measured. |
| | |
| | So the corpus's biggest gap — nobody has measured a deployed Attribution Reporting API — is **closable only retrospectively, on an older binary**: the API itself stopped sending its request header in M152, so no current build observes it by any route. M147 branched 2026-03-09 and reached stable 2026-04-07, so it should still carry the surface; M148 branched 2026-04-06, inside the removal window, so it is a coin flip. **That milestone mapping is inferred from branch points, not tested**: no build at or before M148 was available to this run, whose fourteen builds are 151–156. Check the binary's own ''/json/protocol'' before you build on it, which takes one HTTP request: |
| | |
| | ''%%chromium --headless --remote-debugging-port=9333 & curl -s localhost:9333/json/protocol | grep -c attributionReportingSourceRegistered%%'' |
| | </WRAP> |
| |
| This is the script this page ran, in full, not an abridged illustration: it stands up a local HTTPS origin with a bidding script, a decision script and a Shared Storage worklet, maps a non-''localhost'' name onto it, drives every API, and prints what CDP delivered. Pointing the same listeners at an ordinary site you do not control will usually print nothing, which is why the mock origin is part of the script rather than an exercise for the reader. | This is the script this page ran, in full, not an abridged illustration: it stands up a local HTTPS origin with a bidding script, a decision script and a Shared Storage worklet, maps a non-''localhost'' name onto it, drives every API, and prints what CDP delivered. Pointing the same listeners at an ordinary site you do not control will usually print nothing, which is why the mock origin is part of the script rather than an exercise for the reader. |
| 'Storage.sharedStorageAccessed', | 'Storage.sharedStorageAccessed', |
| 'Storage.sharedStorageWorkletOperationExecutionFinished', | 'Storage.sharedStorageWorkletOperationExecutionFinished', |
| | // The next two are deliberately left subscribed even though they are DEAD on |
| | // this build. The Attribution Reporting surface (3 commands, 4 events) was in |
| | // the CDP Storage domain until it was removed from the protocol between |
| | // 2026-04-01 and 2026-04-08. Chromium 151 no longer has it, and the |
| | // Storage.setAttributionReportingTracking toggle below is rejected. On a |
| | // Chromium from before that removal these two fire, and are the right way to |
| | // measure Attribution Reporting. |
| 'Storage.attributionReportingSourceRegistered', | 'Storage.attributionReportingSourceRegistered', |
| 'Storage.attributionReportingTriggerRegistered', | 'Storage.attributionReportingTriggerRegistered', |
| </file> | </file> |
| |
| Its real output on 2026-09-01: three toggles accepted, ''Storage.setAttributionReportingTracking'' **rejected with a protocol error** (it does not exist), and **seven** events delivered — one auction ''started'', two auction network requests (''bidderJs'' and ''sellerJs''), three ''sharedStorageAccessed'' (''set'', ''addModule'', ''run'') and one ''sharedStorageWorkletOperationExecutionFinished''. Removing the ''setSharedStorageTracking'' toggle drops that to three, so the toggles are load-bearing rather than decorative. | Its real output on 2026-09-01, reproduced unchanged except for identifiers and timestamps on 2026-09-27 (it launches Playwright 1.62.1's default, chrome-headless-shell 151): three toggles accepted, ''Storage.setAttributionReportingTracking'' **rejected with a protocol error** (it does not exist), and **seven** events delivered — one auction ''started'', two auction network requests (''bidderJs'' and ''sellerJs''), three ''sharedStorageAccessed'' (''set'', ''addModule'', ''run'') and one ''sharedStorageWorkletOperationExecutionFinished''. Removing the ''setSharedStorageTracking'' toggle drops that to three, so the toggles are load-bearing rather than decorative. |
| |
| A ''sharedStorageAccessed'' event carries ''accessTime'', ''scope'' (''window'' or the worklet), ''method'' (''set'', ''addModule'', ''run'', ''selectURL'', …), ''ownerOrigin'', ''ownerSite'' and the call's ''params'' — that is, everything needed to reproduce {[nisenoff2025_exploiting]}'s prevalence figure without writing a page-script wrapper at all. An auction produces ''interestGroupAuctionEventOccurred'' with a ''uniqueAuctionId'' and the full ''auctionConfig'', followed by ''interestGroupAuctionNetworkRequestCreated'' entries tagged ''bidderJs'' and ''sellerJs'' — the seller attribution that gives {[calderonio2024_fledging]}'s 99.8% figure. | A ''sharedStorageAccessed'' event carries ''accessTime'', ''scope'' (''window'' or the worklet), ''method'' (''set'', ''addModule'', ''run'', ''selectURL'', …), ''ownerOrigin'', ''ownerSite'' and the call's ''params'' — that is, everything needed to reproduce {[nisenoff2025_exploiting]}'s prevalence figure without writing a page-script wrapper at all, on a pinned pre-152 binary. An auction produces ''interestGroupAuctionEventOccurred'' with a ''uniqueAuctionId'' and the full ''auctionConfig'', followed by ''interestGroupAuctionNetworkRequestCreated'' entries tagged ''bidderJs'' and ''sellerJs'' — the seller attribution that gives {[calderonio2024_fledging]}'s 99.8% figure. |
| | |
| | ==== The cheapest surface of all: HTTP headers ==== |
| | |
| | Two of these APIs are substantially **declarative**, and a crawler that already records request and response headers — which is to say any crawler built for [[Privacy:Requests]] — can observe them with no wrappers and no CDP. The headers do not outlive the API, though. On 2026-09-27 a ''fetch()'' with the ''attributionReporting'' option carried ''Attribution-Reporting-Eligible'' in both Chromium 151 builds and in none of the twelve builds from 152 to 156. A ''fetch()'' with ''browsingTopics: true'' carried ''Sec-Browsing-Topics'' on exactly the same builds. On a current build, a header crawl sees whatever ''Attribution-Reporting-Register-*'' or ''Observe-Browsing-Topics'' headers servers may still send; we did not measure whether any do. It sees nothing the browser does with them. |
| | |
| | ^ Header ^ Direction ^ What it tells you ^ |
| | | ''Attribution-Reporting-Eligible'' | request | The browser is willing to register a source or trigger on this request. Its presence marks the request as ARA-relevant | |
| | | ''Attribution-Reporting-Register-Source'' | response | A source (an ad view or click) is being registered. The JSON value names the ''destination'' site; the reporting origin is implicit — it is whichever origin sent the header | |
| | | ''Attribution-Reporting-Register-Trigger'' | response | A conversion is being registered | |
| | | ''Sec-Browsing-Topics'' | request | The topics the browser is disclosing to this caller | |
| | | ''Observe-Browsing-Topics'' | response | The caller is asking the browser to record this page visit toward future topic calculation — i.e. it is //building// a profile, not just reading one | |
| | |
| | ''Sec-Browsing-Topics'' has one property worth knowing before you count it: per MDN, if the calling site is not enrolled for Topics, "attempting to create or modify ''Sec-Browsing-Topics'' fails silently, and any existing ''Sec-Browsing-Topics'' header is deleted".((MDN, [[https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Browsing-Topics|''Sec-Browsing-Topics'']], fetched 2026-09-01. All five headers above have MDN reference pages as of that date.)) So a header count is a count of **enrolled** callers by construction — which is the opposite of the JS-surface problem, and made the header the better instrument for "who is actually using this", on a pre-152 binary. |
| |
| ==== The wrapper-injection route, and why the corpus used it ==== | ==== The wrapper-injection route, and why the corpus used it ==== |
| |
| Topics and Attribution Reporting have no CDP surface at all, in any Chromium version checked. For those, the corpus's method is the one to copy: {[calderonio2024_fledging]} "used Puppeteer to orchestrate Chrome", visiting each domain in a fresh browser instance, and "injects wrapper functions into the page and logs all" calls to ''navigator.runAdAuction'', ''navigator.joinAdInterestGroup'' and ''navigator.leaveAdInterestGroup''. Inject the wrapper before any page script runs — ''page.addInitScript()'' in Playwright, ''page.evaluateOnNewDocument()'' in Puppeteer — and wrap ''document.browsingTopics'', the ''attributionReporting'' option on ''fetch'', and the ''attributionSrc'' setter on ''HTMLAnchorElement''/''HTMLImageElement'' the same way. | Topics has no CDP surface in any Chromium version checked, and Attribution Reporting no longer has one. For those, the corpus's method is the one to copy. It is also the only route that still sees something on a current build, because a stub is still a method a wrapper can intercept: site scripts that call ''document.browsingTopics()'' or ''navigator.runAdAuction()'' are still visible in 156, even though the calls do nothing. That tells you who still calls the API, not what the browser does. The method: {[calderonio2024_fledging]} "used Puppeteer to orchestrate Chrome", visiting each domain in a fresh browser instance, and "injects wrapper functions into the page and logs all" calls to ''navigator.runAdAuction'', ''navigator.joinAdInterestGroup'' and ''navigator.leaveAdInterestGroup''. Inject the wrapper before any page script runs — ''page.addInitScript()'' in Playwright, ''page.evaluateOnNewDocument()'' in Puppeteer — and wrap ''document.browsingTopics'' and the ''attributionReporting'' option on ''fetch'' the same way. |
| |
| Two things this costs you, both worth a sentence in your methods section: a wrapper is visible to page script and is therefore detectable ([[Programming:Crawler detection]]), and it sees only the main world unless you also install it into every frame and worklet. | **Do not try to catch ''attributionsrc'' by wrapping the IDL setter.** Wrapping ''HTMLAnchorElement.prototype.attributionSrc'' catches only the elements a script assigns to; markup that arrives as ''%%<img attributionsrc="…">%%'' in the server-rendered HTML is set by the parser, which never invokes the setter, so a crawl instrumented that way undercounts by however much of the ad markup is server-rendered — which for ad tags is most of it. Use a ''MutationObserver'' with ''attributeFilter'', a ''querySelectorAll('[attributionsrc]')'' sweep after load, or the header route above. |
| | |
| | Three things the wrapper route costs you, all worth a sentence in your methods section: a wrapper is visible to page script and is therefore detectable ([[Programming:Crawler detection]]); it sees only the main world unless you also install it into every frame and worklet; and it records //calls//, so an API a site uses purely declaratively is invisible to it. |
| |
| ==== Nothing outside Chromium implements the ads APIs ==== | ==== Nothing outside Chromium implements the ads APIs ==== |
| * **W3C ''Attribution Level 1''** is a live **W3C Working Draft** from the Private Advertising Technology Working Group, fetched 2026-09-01 at [[https://www.w3.org/TR/attribution/|w3.org/TR/attribution]]. Google's 2025-10-17 post says it will "continue to engage on it through the web standards process". No browser ships it. This is the surface to watch, not to measure. | * **W3C ''Attribution Level 1''** is a live **W3C Working Draft** from the Private Advertising Technology Working Group, fetched 2026-09-01 at [[https://www.w3.org/TR/attribution/|w3.org/TR/attribution]]. Google's 2025-10-17 post says it will "continue to engage on it through the web standards process". No browser ships it. This is the surface to watch, not to measure. |
| |
| **[[Programming:Crawler:OpenWPM|OpenWPM]] cannot observe any of this**, because it drives Firefox — still true at v0.36.0, released 2026-08-24, whose README opens "OpenWPM is built on top of Firefox". If your instrument is OpenWPM, a Privacy Sandbox measurement is not a configuration change, it is a different crawler. | **[[Programming:Crawler:OpenWPM|OpenWPM]] cannot observe any of this**, because it drives Firefox — still true at v0.37.0, released 2026-09-06, whose README says "OpenWPM is built on top of Firefox". If your instrument is OpenWPM, a Privacy Sandbox measurement is not a configuration change, it is a different crawler. |
| |
| ===== Populations You Can Reuse Without Crawling ===== | ===== Populations You Can Reuse Without Crawling ===== |
| |
| ^ Artefact ^ Where ^ Size today ^ What it is good for ^ | ^ Artefact ^ Where ^ Size today ^ What it is good for ^ |
| | **Enrollment report** | ''privacysandbox/attestation'' → ''enrollment_report.csv'' | **326 rows** | The company-level population. Columns: ''Enrollment Id'', ''Company Name'', ''Android APIs'', ''Chrome APIs'', ''SDK Names'', ''Site'' | | | **Enrollment report** | ''privacysandbox/attestation'' → ''enrollment_report.csv'' | **326 rows**. Repository **archived**, last push 2026-01-22 | The company-level population. Columns: ''Enrollment Id'', ''Company Name'', ''Android APIs'', ''Chrome APIs'', ''SDK Names'', ''Site'' | |
| | **Preloaded attestation list** | ''PrivacySandboxAttestationsPreloaded/privacy-sandbox-attestations.dat'', inside your own Chromium install | **263 sites**, component version **2025.7.18.0** | The list the browser itself enforces against. No network access needed | | | **Preloaded attestation list** | ''PrivacySandboxAttestationsPreloaded/privacy-sandbox-attestations.dat'', inside your own Chromium install | **263 sites**, component version **2025.7.18.0** | The list the browser itself enforces against. No network access needed | |
| | **Per-site attestation file** | ''%%https://<site>/.well-known/privacy-sandbox-attestations.json%%'' | one per enrolled site | Which APIs each site declared. {[nisenoff2025_exploiting]} fetched 289 of these and got **245 (85%)** | | | **Per-site attestation file** | ''%%https://<site>/.well-known/privacy-sandbox-attestations.json%%'' | one per enrolled site | Which APIs each site declared. {[nisenoff2025_exploiting]} fetched 289 of these and got **245 (85%)** | |
| | **Related Website Sets list** | ''GoogleChrome/related-website-sets'' → ''related_website_sets.JSON'' | **70 sets, 320 member domains**, 66 sets (94.3%) with at least one associated site. Repository **archived** | A complete census, not a sample. Also reachable in-browser via CDP ''Storage.getRelatedWebsiteSets'' | | | **Related Website Sets list** | ''GoogleChrome/related-website-sets'' → ''related_website_sets.JSON'' | **70 sets, 320 member domains**, 66 sets (94.3%) with at least one associated site. Repository **archived**, last push 2025-11-21 | A complete census, not a sample. Also reachable in-browser via CDP ''Storage.getRelatedWebsiteSets'' through M155; the command is gone from 156 and from tip-of-tree | |
| | **Topics taxonomy** | ''patcg-individual-drafts/topics'' → ''taxonomy_v2.md'' | **469 topics**. There is no v3 | The label space. Note the Android taxonomy is curated separately — do not conflate them | | | **Topics taxonomy** | ''patcg-individual-drafts/topics'' → ''taxonomy_v2.md'' | **469 topics**. Repository **archived**, last push 2025-11-07 — which is why there is no v3 | The label space. Note the Android taxonomy is curated separately — do not conflate them | |
| | |
| | **All three GitHub artefacts are archived repositories** (checked through the GitHub API on 2026-09-01), so these are final snapshots rather than feeds. That is convenient for reproducibility and misleading if you assume they still track reality. **New enrollment is closed** — Google's own enrollment page carries the banner "Privacy Sandbox private advertising APIs are being phased out. We will no longer accept new account creation and enrollment"((''privacysandbox.google.com/private-advertising/enrollment'', fetched 2026-09-01.)) — so you cannot enrol a research origin to test against. Use ''%%--privacy-sandbox-enrollment-overrides=https://your.origin%%'' instead, on a pinned pre-152 binary, and say in your paper that you did. On a current build the override enrols your origin in APIs that do nothing. |
| |
| The enrollment report is also a measurement in itself. Of its 326 rows, the Chrome APIs each enrollee asked for: | The enrollment report is also a measurement in itself. Of its 326 rows, the Chrome APIs each enrollee asked for: |
| | name "Privacy Sandbox" five or more times | **9** | 0.2% | | | name "Privacy Sandbox" five or more times | **9** | 0.2% | |
| |
| **This is the page's central limitation and it belongs at the top of the section rather than in a footnote.** A dozen papers in seven venues over sixteen years is not a literature; it is a handful of studies, and every generalisation on this page rests on them. Anything you want to know that the table below does not answer, the corpus cannot tell you — go to the specs and to Chrome Platform Status. | **This is the page's central limitation.** Eleven measuring papers across seven venues is not a literature; it is a handful of studies, and every generalisation on this page rests on them. Anything you want to know that the table below does not answer, the corpus cannot tell you — go to the specs and to Chrome Platform Status. |
| |
| ^ API family ^ Folded-in former names ^ Papers ^ | ^ API family ^ Folded-in former names ^ Papers ^ |
| |
| The field is crawling Chrome and not looking at what Chrome now does. | The field is crawling Chrome and not looking at what Chrome now does. |
| | |
| | The denominator is every web crawl, including the many with no reason to touch an ads API — a phishing crawl or a CSP census is not delinquent for ignoring Topics. So read the number as an upper bound on how far the field has //not// engaged, not as a defect rate. It is the magnitude that carries: fewer than one recent web crawl in twelve so much as names one of these APIs, in the years they were shipping by default in the browser most of those crawls drove. |
| |
| ^ Population ^ N ^ Name at least one API family ^ | ^ Population ^ N ^ Name at least one API family ^ |
| "Web crawl" is ''crawlConfig != null'' or ''studyTypes'' containing ''automated-web-crawl'', **and** ''platforms'' containing ''web''. The last row's denominator is papers that **stated** a browser: ''crawlConfig.browsers'' is stated by only 47.2% of the 1,120 crawling papers in the corpus, so 86 is a lower bound on Chrome-driving crawls, and 9.3% is a share of the ones that told you. | "Web crawl" is ''crawlConfig != null'' or ''studyTypes'' containing ''automated-web-crawl'', **and** ''platforms'' containing ''web''. The last row's denominator is papers that **stated** a browser: ''crawlConfig.browsers'' is stated by only 47.2% of the 1,120 crawling papers in the corpus, so 86 is a lower bound on Chrome-driving crawls, and 9.3% is a share of the ones that told you. |
| |
| If you are looking for a gap to fill, **Attribution Reporting is measured by nobody**. Three papers in 5,869 name it — a related-work list, a browser-permissions census that counts how often sites //feature-detect// it, and one arXiv citation in a reference list. Not one instruments it, crawls for it, or reports its deployment prevalence. Given the M153 target, the window to measure a deployed Attribution Reporting API in Chrome is now measured in days. | If you are looking for a gap to fill, **Attribution Reporting is measured by nobody**. Three papers in 5,869 name it — a related-work list, a browser-permissions census that counts how often sites //feature-detect// it, and one arXiv citation in a reference list. Not one instruments it, crawls for it, or reports its deployment prevalence. **That window has now closed in current Chrome**: from M152 the browser no longer sends the eligibility header, and the Permissions-Policy feature is unknown. What remains possible is a retrospective measurement on a pinned pre-M152 binary. It sees what sites still ask of the API, not what real users' browsers do. See the box in [[#Chrome DevTools Protocol: what it covers, and for how long]]. |
| | |
| | ==== The only post-2025 adoption numbers that exist are Chrome's own ==== |
| | |
| | The corpus stops in February 2025 (see [[#Open Questions]]). Chrome publishes usage figures as its justification for removal, inside the Chrome Platform Status "Deprecate and remove" entries, and as of 2026-09-01 they are the only measurement of what happened after the April 2025 reversal. **They are vendor telemetry, unaudited, with no stated methodology, and the unit is usually //page loads// rather than //sites//** — so they are not comparable with anything in the table below without saying which unit you mean. Quoted because there is nothing else, not because they are good: |
| | |
| | ^ API ^ What Chrome's own removal entry says ^ |
| | | Topics | "currently at 13% of page loads" in the entry filed 2025-10-22; the blink-dev follow-up of 2026-06-12 says "Currently the usage is 4.9% of page loads", and that of 2026-09-24 "The current usage is at 2%" | |
| | | Shared Storage | "currently at ~11% of page loads" | |
| | | Protected Audience | "Use of the ''joinAdInterestGroup()'' API has decreased by almost 100x and use of the ''runAdAuction()'' API has decreased by more than 10x. Of the auctions occurring today, virtually none of them have winners". On blink-dev: 1.1% of page loads on 2026-06-12. On 2026-09-23 "<0.005%", corrected the next day: "we misread the usage in the dashboard. We are actually still seeing ~ 1% usage" | |
| | | Related Website Sets | "currently at 71 sets", and ''requestStorageAccessFor'' "at about 0.95% of pageloads" | |
| | | Attribution Reporting | no usage figure given — the entry argues from "we expect adoption to decrease over time" | |
| | |
| | Entry figures fetched from ''chromestatus.com/api/v0/features/'' on 2026-09-01; blink-dev figures fetched 2026-09-27. Three things a reader should notice. **The vendor's own series changed definition when the API was deprecated.** A researcher on the Protected Audience thread asked why Chrome's "Fledge" use counter peaked at 7.7% in Q1 2026, after the retirement. Chrome's answer was that marking the API deprecated folded more of its surface into that counter: "It wasn't actually an increase in API usage, it was just a change in measurement." And within one day in September, Chrome's own reading of the same dashboard moved from "<0.005%" to "~ 1%". **The RWS set count in the entry (71) is not the count in the list today (70)**, because the entry is a snapshot from late 2025 and the list has since been archived — a one-set discrepancy, but a good illustration of why you date an artefact. And **Chrome's Shared Storage figure of ~11% of page loads sits next to {[nisenoff2025_exploiting]}'s 10.1% of //sites//** from February 2025; the closeness is a coincidence of units, not a corroboration. |
| |
| ==== What the corpus did measure ==== | ==== What the corpus did measure ==== |
| | |
| | **The inclusion rule, written down before the table rather than after it:** a paper earns a row if it //measured// a Privacy Sandbox mechanism — crawled for it, attacked it, simulated it against real traces, or analysed its deployed governance artefacts. The last two rows are deliberate exceptions and are marked as such: {[ali2023_navigating]} because it is the corpus's only cross-browser census of the storage surfaces these APIs sit on, and {[lin2024_browsing]} because it is the counterfactual — what actually changes when third-party cookies go — which is the premise the whole Privacy Sandbox rests on. Assignment was by hand, from the per-family paper lists printed in full on [[provenance:privacy:privacy_sandbox|the provenance page]]; disagree with it there. |
| |
| Each row names the paper's own population. Nothing here is a share of the corpus. | Each row names the paper's own population. Nothing here is a share of the corpus. |
| | {[lin2024_browsing]} IMC 2024 | what blocking third-party cookies actually changes | Tranco top 10,000; 7,490 domains crawled successfully | More than **90%** of domains showed **less than a 10%** screenshot difference with third-party cookies disabled — the "cookieless web looks different" premise is largely not true at the page level | | | {[lin2024_browsing]} IMC 2024 | what blocking third-party cookies actually changes | Tranco top 10,000; 7,490 domains crawled successfully | More than **90%** of domains showed **less than a 10%** screenshot difference with third-party cookies disabled — the "cookieless web looks different" premise is largely not true at the page level | |
| |
| One adjacent paper gives the CHIPS context without measuring the attribute: {[bahrami2025_cookieguard]} (IMC 2025) describes CHIPS as "an opt-in model for cookie partitioning" and contrasts it with Firefox's Total Cookie Protection and Safari's ITP, which partition by default — which is why a CHIPS adoption figure is a measure of //publisher and tracker uptake//, not of browser policy. ({[kancherla2025_least]} is cited on this page only for its third-party storage-access figures on [[Privacy:Browser storage]]; it never discusses CHIPS, and an earlier draft wrongly attached this claim to it.) The only dedicated CHIPS adoption study we found is outside these seven venues: Zöllner, Feldmann and Dao, //A First Look at Cookies Having Independent Partitioned State//, PAM 2025.((''doi.org/10.1007/978-3-031-85960-1_8'', pages 182–196. Verified against Crossref 2026-09-01. Note that {[rasaii2025_crumbs]} cites this paper with a different and incorrect DOI; use the one here.)) We have not read it and quote no figure from it. | One adjacent paper gives the CHIPS context without measuring the attribute: {[bahrami2025_cookieguard]} (IMC 2025) describes CHIPS as "an opt-in model for cookie partitioning" and contrasts it with Firefox's Total Cookie Protection, "isolating all storage (including cookies) on a per-site basis", and Safari's ITP. (The paper does not use the word "default" of Firefox and Safari; that gloss is ours, and it is supported by [[Privacy:Browser storage]] rather than by this paper.) — which is why a CHIPS adoption figure is a measure of //publisher and tracker uptake//, not of browser policy. ({[kancherla2025_least]} is cited on this page only for its third-party storage-access figures on [[Privacy:Browser storage]]; it never discusses CHIPS, and an earlier draft wrongly attached this claim to it.) The only dedicated CHIPS adoption study we found is outside these seven venues: Zöllner, Feldmann and Dao, //A First Look at Cookies Having Independent Partitioned State//, PAM 2025.((''doi.org/10.1007/978-3-031-85960-1_8'', pages 182–196. Verified against Crossref 2026-09-01. Note that {[rasaii2025_crumbs]} cites this paper with a different and incorrect DOI; use the one here.)) We have not read it and quote no figure from it. |
| |
| ===== Denominators and Pitfalls ===== | ===== Denominators and Pitfalls ===== |
| * **Presence, enablement and use are three different measurements**, and only the third is a property of the site. See [[#Presence is not availability, and neither is a return value]]. | * **Presence, enablement and use are three different measurements**, and only the third is a property of the site. See [[#Presence is not availability, and neither is a return value]]. |
| * **Enrollment is intent, not deployment.** 326 enrolled companies; four observed callers. | * **Enrollment is intent, not deployment.** 326 enrolled companies; four observed callers. |
| * **The browser version is the measurement.** These APIs shipped at M114–M116 in mid-2023 and are targeted for removal at M152–M155 in 2026. A crawl that does not report its Chrome version has reported nothing checkable, and a longitudinal series that spans the removal is measuring the browser, not the web. This is the [[Design:Longitudinal|longitudinal]] problem in its sharpest form. | * **The browser version is the measurement.** These APIs shipped at M114–M116 in mid-2023, and from M152 (August 2026) most of them are stubs, with more code leaving at 153 and 154 and Fenced Frames targeted for 156. A crawl that does not report its Chrome version has reported nothing checkable, and a longitudinal series that spans the removal is measuring the browser, not the web. This is the [[Design:Longitudinal|longitudinal]] problem in its sharpest form. |
| * **Your automation library is not a stock browser.** Playwright disables ''ThirdPartyStoragePartitioning'' by default, which is exactly the axis CHIPS is about — see [[Privacy:Browser storage#Partitioning: Your Crawler and a Real Browser Disagree]] and [[Programming:Stateful stateless#Since 2022 the engine decides, not you]]. Measured on this page: Playwright's default list does **not** disable any of the ads APIs. | * **Your automation library is not a stock browser.** Playwright disables ''ThirdPartyStoragePartitioning'' by default, which is exactly the axis CHIPS is about — see [[Privacy:Browser storage#Partitioning: Your Crawler and a Real Browser Disagree]] and [[Programming:Stateful stateless#Since 2022 the engine decides, not you]]. Measured on this page: Playwright's default list does **not** disable any of the ads APIs. |
| * **Cross-browser comparison is not available.** No non-Chromium engine implements the ads APIs, so "Chrome vs Firefox" on a Privacy Sandbox question compares an implementation with an absence. | * **Cross-browser comparison is not available.** No non-Chromium engine implements the ads APIs, so "Chrome vs Firefox" on a Privacy Sandbox question compares an implementation with an absence. |
| | * **A crawler profile is one point in a distribution of user settings.** Real Chrome users passed through the "Ad privacy" choice UI in 2023 and hold heterogeneous per-API toggle states; your fresh profile holds exactly one. Nothing in this corpus measures that distribution, so a site-level prevalence measured from a crawl is a measurement of what //your// profile was offered, not of what users experience. |
| * **What we could not establish**: whether Chrome's ads APIs are gated differently in the EEA or the UK than elsewhere. It would be reasonable to expect a DMA-driven consent gate, but reasonable is not measured: Google's two API-availability pages both return HTTP 404 as of 2026-09-01, we found no primary statement of the current regional behaviour anywhere on Google's documentation, and this run had a single vantage point. If your crawl is comparative across regions ([[Design:Crawling location]]), test this yourself and report what you found — do not assume either way. | * **What we could not establish**: whether Chrome's ads APIs are gated differently in the EEA or the UK than elsewhere. It would be reasonable to expect a DMA-driven consent gate, but reasonable is not measured: Google's two API-availability pages both return HTTP 404 as of 2026-09-01, we found no primary statement of the current regional behaviour anywhere on Google's documentation, and this run had a single vantage point. If your crawl is comparative across regions ([[Design:Crawling location]]), test this yourself and report what you found — do not assume either way. |
| |
| ===== What to Report ===== | ===== What to Report ===== |
| |
| - **The exact Chromium/Chrome version**, not "Chrome". ''151.0.7922.34'', not "the latest Chrome". Everything on this page changes between milestones. | - **The exact Chromium/Chrome version**, not "Chrome". ''151.0.7922.34'', not "the latest Chrome", which for these APIs is a build in which they do nothing. Everything on this page changes between milestones. Say, too, **which kind of binary**: Playwright's default ''headless: true'' launches chrome-headless-shell, and on 151 it ran an auction that the full Chromium of the same release did not. |
| - **The automation library and version**, and the full ''%%--enable-features%%'' / ''%%--disable-features%%'' lists you passed, because the library passes its own. | - **The automation library and version**, and the full ''%%--enable-features%%'' / ''%%--disable-features%%'' lists you passed, because the library passes its own. |
| - **Which observation surface** you used: CDP ''Storage'' events, injected JS wrappers, or the enrollment/attestation artefacts. They see different things and none of them sees all of it. | - **Which observation surface** you used: request and response headers, CDP ''Storage'' events, injected JS wrappers, or the enrollment/attestation artefacts. They see different things and none of them sees all of it. |
| - **Whether you enrolled or overrode enrollment**, and for which origins. | - **Whether you enrolled or overrode enrollment**, and for which origins. |
| - **The distinct-caller count** alongside any site-level prevalence. | - **The distinct-caller count** alongside any site-level prevalence. |
| - **Per-snapshot counts**, not only the union, for any repeated crawl. | - **Per-snapshot counts**, not only the union, for any repeated crawl. |
| - **The date the artefact list was taken**, for the enrollment report, the attestation ''.dat'' and the RWS list — all three change under you, and two of the three are now frozen by archival. | - **The date the artefact list was taken**, for the enrollment report, the attestation ''.dat'' and the RWS list. All three GitHub repositories are now archived, so the lists are frozen — but the ''.dat'' inside a Chromium install moves with the component updater in a stock launch (Playwright passes ''%%--disable-component-update%%'', so under Playwright yours is frozen at install), and an archived list is not the same as the list Chrome was enforcing on the day you crawled. |
| - **That the API still existed in your build**, stated as a fact you checked rather than assumed. After M153 this stops being pedantry. | - **That the API still worked in your build**, stated as a fact you checked rather than assumed — a call that did something, not a ''typeof''. From M152 the ''typeof'' answer is a stub for Topics and Protected Audience. |
| |
| ===== Open Questions ===== | ===== Open Questions ===== |
| |
| <WRAP todo> | <WRAP todo> |
| * **Nobody has measured a deployed Attribution Reporting API.** Three passing mentions in 5,869 papers, no instrumentation, no prevalence. The removal target is M153. | * **Nobody has measured a deployed Attribution Reporting API**, and nobody now can in current Chrome. It went inert in M152. Three passing mentions in 5,869 papers, no instrumentation, no prevalence. What remains is a retrospective crawl on a pinned pre-M152 binary. |
| * **Nobody has re-measured Protected Audience or Topics adoption after 2025-04-22.** {[calderonio2024_fledging]}'s crawl is from 2023 and {[nisenoff2025_exploiting]}'s from February 2025 — both before the retirement announcement. Chrome's own removal justification claims usage collapsed; no independent measurement of that collapse exists in this corpus. | * **Nobody independent has re-measured Protected Audience, Topics or Shared Storage adoption after February 2025.** {[calderonio2024_fledging]}'s crawl is from 2023 and {[nisenoff2025_exploiting]}'s from February 2025 — both before the retirement announcement. The only figures for the collapse are Chrome's own, quoted above; nobody has checked them, and the browser that produced them is the one being measured. |
| * **The RWS list has grown from 41 sets to 70** between {[mcquistin2024_first]}'s snapshot and today, and its repository is now archived. Nobody has published the end-state census or repeated the pull-request analysis on it. | * **The RWS list has grown from 41 sets to 70** between {[mcquistin2024_first]}'s snapshot and today, and its repository is now archived. Nobody has published the end-state census or repeated the pull-request analysis on it. |
| * **CHIPS adoption is measured once inside this corpus and once outside it**, both at around 1% of tracking cookies. CHIPS is one of the three APIs that survives; a proper longitudinal series on it is missing and now has a stable target to measure. | * **CHIPS adoption is measured once inside this corpus and once outside it**, both at around 1% of tracking cookies. CHIPS is one of the three APIs that survives; a proper longitudinal series on it is missing and now has a stable target to measure. |
| * **Whether the ads APIs are regionally gated** — see the last bullet of [[#Denominators and Pitfalls]]. | * **Whether the ads APIs are regionally gated** — see the last bullet of [[#Denominators and Pitfalls]]. |
| * **What replaces the CDP instrumentation.** Once ''Storage.setInterestGroupTracking'' and friends are gone, the archival question is whether anyone captured enough of the deployed ecosystem before it disappeared. If you have a crawl from 2023–2026 with these events in it, that dataset is about to become unrepeatable — see [[:artifacts|Artifacts]]. | * **What replaces the CDP instrumentation.** ''Storage.setInterestGroupTracking'' and friends left the shipping binary in M152, and the Shared Storage commands in M154. The archival question is now whether anyone captured enough of the deployed ecosystem before it disappeared. If you have a crawl from 2023–2026 with these events in it, that dataset is already unrepeatable in current Chrome — see [[:artifacts|Artifacts]]. |
| | * **When the stubs go.** Protected Audience and Topics stubs are being removed for real users by field trial. The last dates requested were 100% "starting Oct 26" and "after Oct 15" 2026. An automation build keeps the stub until the code is deleted — it is still there in 156.0.8075.0 — and no milestone for that is published. Re-run the probe on the [[provenance:privacy:privacy_sandbox|provenance page]] against the build you use. |
| </WRAP> | </WRAP> |
| |
| Corpus figures come from the 5,859-paper extraction over seven venues (CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf, IEEE S&P), 2010–2026; the full-text sweep covers the 5,869 papers with a rendered ''paper.cols.txt''. **Any claim here is a claim about those seven venues.** EuroS&P, ACSAC, RAID, AsiaCCS, CHI, SOUPS, PAM and WPES are not in it, and the CHIPS study named above is an example of relevant work that therefore does not appear in any count. 2025 and 2026 venue-years are provisional. | Corpus figures come from the 5,859-paper extraction over seven venues (CCS, IMC, NDSS, PETS, USENIX Security, TheWebConf, IEEE S&P), 2010–2026; the full-text sweep covers the 5,869 papers with a rendered ''paper.cols.txt''. **Any claim here is a claim about those seven venues.** EuroS&P, ACSAC, RAID, AsiaCCS, CHI, SOUPS, PAM and WPES are not in it, and the CHIPS study named above is an example of relevant work that therefore does not appear in any count. 2025 and 2026 venue-years are provisional. |
| |
| Every browser measurement on this page was taken on **2026-09-01** against **Chromium 151.0.7922.34** as shipped with Playwright 1.62.1, in a Linux container, headless. Non-Chromium engines were **not** probed first-hand: the Firefox build available here fails to launch in this environment, so the Firefox and Safari statements rest on Bugzilla and vendor documentation, not on measurement. | The browser measurements in [[#Detecting and Recording the APIs from a Crawl]] were taken on **2026-09-01** against **Chromium 151.0.7922.34** as shipped with Playwright 1.62.1, in a Linux container, headless. The removal-status measurements were taken on **2026-09-27** against fourteen arm64 builds, 151.0.7922.34 to 156.0.8075.0, listed in [[#The removal staircase, measured]]. Four are Google Chrome for Testing, which Google publishes for linux-arm64 only from 153. None is the Chrome that users run. Every build was launched through Playwright with a fresh profile and Playwright's own ''%%--disable-field-trial-config%%'', so none could hold a variations seed. Whether a Chrome for Testing build with a persistent profile and without those flags fetches one was not tested. Non-Chromium engines were **not** probed first-hand: the Firefox build available here fails to launch in this environment, so the Firefox and Safari statements rest on Bugzilla and vendor documentation, not on measurement. |
| |
| The full query log — every population and denominator, the report script and its unedited output, the folding rules with the regexes that were measured and rejected, the quote spot-checks, the external sources verified and the ones discarded — is at [[provenance:privacy:privacy_sandbox]]. Corpus-level caveats are on [[literature:corpus]]. | The full query log — every population and denominator, the report script and its unedited output, the folding rules with the regexes that were measured and rejected, the quote spot-checks, the external sources verified and the ones discarded — is at [[provenance:privacy:privacy_sandbox]]. Corpus-level caveats are on [[literature:corpus]]. |