← 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.

Removed surface — reference for deletion, not adoption

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.

Source: draft — exposed interface; Chromium features.cc (M152 branch)

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.

Source: Private Aggregation API draft — report scheduling; ChromeStatus API record

contributeToHistogram(contribution)

The core method: queued one histogram contribution for the current worklet invocation.

Inputscontribution — 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)
Outputsundefined (fire-and-forget); the observable effect is a contribution added to the report assembled when the worklet invocation ends
ErrorsRangeError for the three validation failures above; TypeError now, post-disablement, because privateAggregation itself is undefined
ContextShared Storage worklets and Protected Audience script runners, secure contexts only; receiver must be the worklet-global privateAggregation
NowGuard 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).

Inputsevent (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)
Outputsundefined; the contribution was recorded against the event and materialized only if that event fired
ErrorsTypeError for an unrecognized (non-reserved.) event name; RangeError for the same bucket/value validation as contributeToHistogram(); TypeError now, post-disablement
ContextSame two worklet globals; in Chromium additionally gated by the PrivateAggregationApiErrorReporting runtime flag (shipped IDL; flag experimental in runtime_enabled_features.json5)
NowGuard 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.

Inputsoptions (optional PADebugModeOptions, default {}) — debugKey: required bigint, an opaque caller-chosen marker attached to debug reports
Outputsundefined; subsequent contributions in the context emitted debug reports
ErrorsWebIDL 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)
ContextSame two worklet globals; idempotent within a context (subsequent calls only update the key)
NowDelete 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. PADebugModeOptionsdebugKey (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:

BrowserSupportEvidence
ChromeWas exposed in Shared Storage / Protected Audience worklets; deprecated from 144, removal filed at 152milestone=152 listing; feature notes
EdgeFollows ChromiumChromium-based; no separate position on record
FirefoxNever implementedmozilla/standards-positions #805 (“proposal appears stale”)
SafariNever implementedWebKit/standards-positions #189 (“proposal withdrawn”)
Source: chromestatus.com/feature/4683382919397376; vendor position records as linked per row

security and privacy

Source: Private Aggregation API draft; ChromeStatus API record