v152 · privacy · demo
Histogram Explorer
Private Aggregation added Laplace noise to every histogram bucket before reporting. This explorer lets you see what that noise actually looked like: pick a bucket key and true value, set epsilon, and watch how the noisy distribution shifts. Understanding the mechanism helps clarify why removal simplifies the stack.
sharedStorage (worklet host): checking…
bucket key
The histogram dimension. e.g. "ad placement = 1024"
true value
The contribution you want to report (e.g. conversion count × 100).
privacy budget ε
Lower ε = more noise = more privacy. Higher ε = less noise = more utility.
single noisy value
One report as the API would have sent it:
true value ↓
noisy reported value
signal / noise ratio
| metric | value |
|---|---|
| true value | — |
| expected noise std dev | — |
| last noisy value | — |
| error this sample | — |
| relative error | — |
| utility rating | — |
Utility:
distribution of 200 simulated noisy reports (click "Simulate 200 reports"):
x-axis: reported value | y-axis: count | red line: true value
what the API did
// Inside a Shared Storage worklet (now removed):
class MyOperation {
async run(data) {
// bucket = which histogram dimension (0–2^128)
// value = contribution (0–L1 budget, default 65536)
privateAggregation.contributeToHistogram({
bucket: BigInt(data.bucketKey),
value: data.value
});
// Browser adds Laplace noise:
// scale = sensitivity / epsilon (sensitivity = 1 by default)
// noisy = value + Laplace(0, scale)
// Then aggregates across users before releasing the report.
}
}
// Registered as: sharedStorage.run("my-op", { data: {...} })
The noise scale is sensitivity / epsilon. With epsilon = 1 and the default sensitivity of 1, the standard deviation is √2 ≈ 1.41. For a value of 500 that’s negligible. For a value of 5 it’s huge. That’s why low-count measurements were the hardest use case.