← Deprecate and remove: Private Aggregation API
v152 · privacy sandbox · web idl · removed
PrivateAggregation interface
The removed JavaScript surface of the Private Aggregation API: a worklet-global object with three methods — contributeToHistogram(), contributeToHistogramOnEvent(), and enableDebugMode() — plus its two dictionaries. Documented here exactly as specified and as shipped, so existing callers can audit, guard, and delete their usage. See the overview for the removal timeline and migration paths.
Every contract on this page describes an API on a published removal path (Intent to Deprecate and Remove; ChromeStatus 4683382919397376). As disablement rolls out, privateAggregation is undefined in worklet globals and any call throws TypeError — guard with typeof privateAggregation !== "undefined" or delete the calls.
syntax
Normative IDL from the final published draft (§ the exposed interface), verbatim:
[Exposed=(InterestGroupScriptRunnerGlobalScope,SharedStorageWorklet),
SecureContext]
interface PrivateAggregation {
undefined contributeToHistogram(PAHistogramContribution contribution);
undefined contributeToHistogramOnEvent(DOMString event,
record<DOMString, any> contribution);
undefined enableDebugMode(optional PADebugModeOptions options = {});
};
dictionary PAHistogramContribution {
required bigint bucket;
required long value;
bigint filteringId = 0;
};
dictionary PADebugModeOptions {
required bigint debugKey;
};
The interface was exposed on the Shared Storage worklet global scope and the Protected Audience interest-group script runner global scope only, in secure contexts — never on window. As shipped in Chromium (Shared Storage side, private_aggregation.idl at the M149 branch), verbatim — note the shipped dictionary name PrivateAggregationHistogramContribution and the runtime gate on the on-event method:
[Exposed=(SharedStorageWorklet),
ContextEnabled=PrivateAggregationInSharedStorage]
interface PrivateAggregation {
[CallWith=ScriptState, RaisesException]
void contributeToHistogram(PrivateAggregationHistogramContribution contribution);
[CallWith=ScriptState, RaisesException,
RuntimeEnabled=PrivateAggregationApiErrorReporting]
void contributeToHistogramOnEvent(DOMString event,
PrivateAggregationHistogramContribution contribution);
[CallWith=ScriptState, RaisesException]
void enableDebugMode(optional PrivateAggregationDebugModeOptions options);
};
Source: Private Aggregation API draft — the exposed interface; Chromium private_aggregation.idl (M149 branch)
context and exposure
The object was reachable only as privateAggregation on the two worklet globals named in the IDL Exposed attribute. In Chromium the attribute on SharedStorageWorkletGlobalScope was gated by ContextEnabled=PrivateAggregationInSharedStorage (shared_storage_worklet_global_scope.idl), ultimately controlled by the kPrivateAggregationApi base feature with per-context Finch parameters enabled_in_shared_storage / enabled_in_fledge (features.cc, M152 branch). Ordinary documents, workers, and service workers never had access; there was no permissions-policy-gated document surface.
lifecycle of a contribution
Each contributeToHistogram() call queued a histogram contribution inside the worklet invocation; at the end of the invocation the browser assembled contributions into an aggregatable report (encrypted to the aggregation service’s public key), and later sent it to the reporting origin’s fixed .well-known endpoint — the full pipeline, its endpoints, and its sunset are on the aggregatable-reports page. Calls were fire-and-forget: they returned undefined immediately and no handle to the eventual report existed. With the API disabled, the queueing step no longer happens — calls throw TypeError at the property access itself.
contributeToHistogram(contribution)
The core method: queued one histogram contribution for the current worklet invocation.
| Inputs | contribution — a PAHistogramContribution: bucket (required bigint) must be contained in the range 0 to 2128, exclusive, or the method returns a RangeError; value (required long) must not be negative, or a RangeError; filteringId (optional bigint, default 0) must fit the context’s filtering-ID byte bound or a RangeError (all three per the draft’s contribution-validation algorithm) |
|---|---|
| Outputs | undefined (fire-and-forget); the observable effect is a contribution added to the report assembled when the worklet invocation ends |
| Errors | RangeError for the three validation failures above; TypeError now, post-disablement, because privateAggregation itself is undefined |
| Context | Shared Storage worklets and Protected Audience script runners, secure contexts only; receiver must be the worklet-global privateAggregation |
| Now | Guard or delete: typeof privateAggregation !== "undefined" before calling |
// REMOVED API — shown for audit/deletion only.
privateAggregation.contributeToHistogram({
bucket: 123456789n, // bigint, 0 <= bucket < 2**128
value: 25, // long, >= 0
filteringId: 7n // optional, defaults to 0n
});
Source: Private Aggregation API draft; Chromium IDL (M149 branch)
contributeToHistogramOnEvent(event, contribution)
A Protected-Audience-oriented variant that deferred the contribution until a named reportable event occurred (for example the reserved win/loss events of an auction).
| Inputs | event (DOMString) — per the draft, if the event name does not start with "reserved." the method throws a TypeError (non-reserved events are reserved for future per-API extension); contribution — a record/dictionary of contribution fields (the draft types it as record<DOMString, any>; the shipped Shared Storage IDL reuses PrivateAggregationHistogramContribution) |
|---|---|
| Outputs | undefined; the contribution was recorded against the event and materialized only if that event fired |
| Errors | TypeError for an unrecognized (non-reserved.) event name; RangeError for the same bucket/value validation as contributeToHistogram(); TypeError now, post-disablement |
| Context | Same two worklet globals; in Chromium additionally gated by the PrivateAggregationApiErrorReporting runtime flag (shipped IDL; flag experimental in runtime_enabled_features.json5) |
| Now | Guard or delete, as above |
// REMOVED API — shown for audit/deletion only.
// Protected Audience auction worklet, deferred to the win event:
privateAggregation.contributeToHistogramOnEvent("reserved.win", {
bucket: 42n,
value: 1
});
Source: Private Aggregation API draft; Chromium IDL (M149 branch)
enableDebugMode(options)
Opted the current context into debug mode: contributions also produced unencrypted, immediately sent debug reports, bypassing the aggregation service’s privacy protections. This is the bridge the deprecation plan told server-side-report users to rely on until full removal.
| Inputs | options (optional PADebugModeOptions, default {}) — debugKey: required bigint, an opaque caller-chosen marker attached to debug reports |
|---|---|
| Outputs | undefined; subsequent contributions in the context emitted debug reports |
| Errors | WebIDL dictionary validation (TypeError) when debugKey is missing or not a bigint; Chromium could disable debug mode independently via the debug_mode_enabled_at_all base-feature parameter, in which case calls “will essentially have no effect” (features.cc, M152 branch) |
| Context | Same two worklet globals; idempotent within a context (subsequent calls only update the key) |
| Now | Delete with the rest of the surface; debug reporting ends with the API |
// REMOVED API — shown for audit/deletion only.
privateAggregation.enableDebugMode({ debugKey: 1234n });
Source: Private Aggregation API draft; Chromium features.cc (M152 branch); ChromeStatus feature notes (debug-reports bridge)
dictionaries
PAHistogramContribution — the contribution shape: bucket (required bigint) identifies the histogram bucket, validated to 0 ≤ bucket < 2128; value (required long) is the amount contributed, validated non-negative; filteringId (optional bigint, default 0) lets aggregation-service queries partition results, validated against a context-defined byte bound. PADebugModeOptions — debugKey (required bigint), the marker carried on debug reports. Both dictionaries were input-only: passed by value into the methods above, never returned or observable afterward. Chromium shipped them under the names PrivateAggregationHistogramContribution and PrivateAggregationDebugModeOptions (shipped IDL).
// REMOVED API — dictionary shapes for reference.
// Spec names: PAHistogramContribution / PADebugModeOptions
// Shipped Chromium names: PrivateAggregationHistogramContribution /
// PrivateAggregationDebugModeOptions
{ bucket: 99n, value: 10, filteringId: 0n } // PAHistogramContribution
{ debugKey: 1234n } // PADebugModeOptions
Source: draft — exposed interface; Chromium IDL (M149 branch)
examples
A complete Shared Storage usage as it would have appeared before deprecation — kept for auditing existing code; the guard pattern beneath is the only snippet that should survive:
// REMOVED API — historical usage, for audit only.
class ReachMeasurer {
async run(data) {
const bucket = BigInt(data.campaignId);
privateAggregation.contributeToHistogram({ bucket, value: 1 });
}
}
register("reach-measurer", ReachMeasurer);
// Transition-safe guard (the only pattern to keep):
if (typeof privateAggregation !== "undefined") {
privateAggregation.contributeToHistogram({ bucket: 1n, value: 1 });
}
Source: usage pattern per the Private Aggregation API draft; guard per the Intent to Deprecate and Remove breakage analysis
browser compatibility
Interim table. No BCD entry exists for PrivateAggregation (checked in the BCD api/ directory, 2026-07-29) and webstatus.dev has no feature. Compiled from the linked primary sources:
| Browser | Support | Evidence |
|---|---|---|
| Chrome | Was exposed in Shared Storage / Protected Audience worklets; deprecated from 144, removal filed at 152 | milestone=152 listing; feature notes |
| Edge | Follows Chromium | Chromium-based; no separate position on record |
| Firefox | Never implemented | mozilla/standards-positions #805 (“proposal appears stale”) |
| Safari | Never implemented | WebKit/standards-positions #189 (“proposal withdrawn”) |
security and privacy
- Trust boundary: contributions were encrypted to the aggregation service’s key; the reporting origin could not read individual contributions (draft).
- Debug mode weakened that boundary deliberately — unencrypted per-event reports — which is why its use was limited to debugging and, in the deprecation plan, to a short bridge for former server-side-report users (feature notes).
- Removal adds no new data flow; any code path that keeps calling the API simply fails closed (
TypeError).