Re: [attribution] Feedback on Attribution Level 1 draft

Thanks for the thoughtful reply, Martin. Mostly you've addressed my
concerns, or taken them to well-scoped issues in which discussion can
continue.

re: Discovering aggregation services

I'm comfortable with your explanation. I agree that the mechanics and
politics of aggregation service choice and availability are beyond the
scope of this specification. One thing to clarify: it sounds like it's
impossible for a conversion site to use an aggregation service that the
browser doesn't already support? There's no way for it to dynamically,
programmatically BYO an aggregation service? That seems fine to me, just
want to make sure I understand how this works.

re: Fetching aggregator config

It makes sense to me that much of this (separately identifying leader and
helper, fetching HPKE configs from trustworthy sources, guaranteeing that
aggregator config is available and sufficiently fresh) is a concern for the
browser and not the impression or conversion site JS.

I'll add one wrinkle that occurred to me while typing this: if the site JS'
entire view of a pair of aggregators and their attendant configuration is
just the leader aggregator URL, then what if the browser wants to offer
multiple aggregator pairs involving the same leader but different helpers?

Right now, I think you'd have to require the leader to add path components
to their DAP API URL to distinguish between helpers, which would work, but
is kind of awkward.

A fix for this could be to relax the requirement that the aggregation
service dictionary keys be a URL and instead say they're an opaque string,
which allows you to pack any information you want in there without imposing
anything on DAP aggregators. It's already defined as a `USVString`, but the
text describes it as a URL, so I'm not sure if that implies that the value
needs to be resolvable or routable in any way.

> Given that these [budget source] parameters might never traverse the wire
anywhere, is there any reason why this is a poor design choice?

No, I think a DAP task extension is appropriate for domain separation.
Thanks for clarifying the purpose of this.

re: `min_batch_size` = 20

DAP's guidance about `min_batch_size` is basically "think really hard about
how big your anonymity set needs to be", and it sounds like you've done
that, so I'm OK with it.

re: `time_precision` = 5

It sounds like the collector chosen batch mode may ignore report
timestamps, which is fine. The remaining consideration is timestamp as a
fingerprinting signal. DAP clients are required to round timestamps down to
the task time precision, meaning that this value would be a 5 second
resolution signal of when someone somewhere used the attribution API at
all. I think a decision needs to be made at the AL1 layer whether that's a
dangerous signal, in which case you would set the time precision higher
until you feel that an acceptable amount of information leaks.

re: Histogram layout consensus

I buy that this particular specification can only do so much to mitigate
these risks without unduly complicating deployment.
https://github.com/w3c/attribution/issues/58 strikes me as being about as
far as this document should go in addressing this. I'll pursue discussion
there.

Thanks,
Tim

On Mon, May 25, 2026 at 6:45 PM Martin Thomson <mt@mozilla.com> wrote:

> Hi Tim, thanks for the feedback.
>
> I'll respond to things inline, but most of your questions should be
> answered in the spec.  If they were, I'll give you citations;
> otherwise, you'll find the answer in the pull request.  I've split the
> changes off where it makes sense to do that, but there's a collection
> of minor stuff here:
>
> https://github.com/w3c/attribution/pull/440
>
> On Sat, May 23, 2026 at 2:13 AM Tim Geoghegan <timgeog+ietf@gmail.com>
> wrote:
> > ## Discovering aggregation services
> >
> > 3.3. Finding a Supported Aggregation Service [3] describes asking the
> browser for a list of aggregation services with
> `navigator.attribution?.aggregationServices`. How does an aggregation
> service get in that list? My expectation would be that ad networks are the
> ones who are arranging contractual relationships with aggregator operators,
> not the browsers. When they do that, is there some out-of-band process by
> which they register their aggregation services with browsers? Is there
> something akin to web PKI root store programs where browsers vet and
> monitor aggregation services?
>
> You have the right idea, but this is outside the scope of what this
> specification can deal with.  That said, we probably owe it to readers
> of this specification to spell that out.
>
> https://github.com/w3c/attribution/pull/436
>
> > Next, it appears that an aggregation service is represented as a
> key-value pair in a dictionary, where the key is a URL like
> https://aggregator.example/dap and the value is an
> `AttributionAggregationProtocol` value like `dap-18-histogram`. But in DAP,
> you need at the very least two URLs, one for each aggregator. In
> particular, it's important that the DAP client (which in this case is the
> user-agent) fetches each aggregator's HPKE configuration from a trusted
> source. Privacy won't hold up if the leader provides the helper's HPKE
> configuration. So: what exactly is available at
> https://aggregator.example/dap? Is it maybe a JSON document which in turn
> contains both aggregator URLs and other config and metadata? If so, what's
> the schema of that document, and who is responsible for constructing that
> document and serving it?
>
> We deal with these questions much later in the document.  At this
> early stage of the document, it's a detail that we don't think that
> someone (or at least someone who isn't up on the details of DAP)
> should concern themselves with.
>
> See Section 10.4 (as you mention) and
>
> https://w3c.github.io/attribution/#s-mpc:~:text=The%20URL%20for%20%22dap%2D18%2Dhistogram%22%20is%20expected%20to%20identify%20the%20DAP%20Leader%20role
>
> In short, the aggregationService URL is an identifier for an entire
> collection of configuration that the browser needs to have available
> before this API is called.  That includes the details for both leader
> and helper, which covers the HPKE config and base URLs.  The
> information can't be fetched for reasons related to web privacy; the
> browser needs to be basically hard-coded with the information for this
> to work.
>
> > 10.4. Unconfigured Browsers [5] discusses "prioritiz[ing] the
> acquisition of aggregation service configuration in a way that is not
> observable to sites" to avoid introducing a fingerprinting signal. This
> would include fetching HPKE configurations for DAP aggregators. But in DAP,
> those HPKE configs have a lifetime indicated by a `Cache-Control` header.
> So what if HPKE config expiration races with a site measuring a conversion?
> Is the user-agent required to avoid yielding control to conversion site
> JavaScript unless the user-agent has satisfied itself that it has an
> aggregation service config that will remain valid long enough for the site
> JS to run?
>
> The entire point of that section is to highlight that browsers can't
> just do inline fetching of HPKE configuration.  They need to have some
> process that is not vulnerable to this sort of leakage.  If that means
> proactive fetching rather than waiting for the cached value to expire,
> that's their problem to solve.
>
> If cache-control lifetimes on the resources served by DAP aggregators
> is too short for browsers to handle properly, then that might be
> something to add to browser requirements for their trust program.
>
> From my perspective, the implementation here is pretty simple.  If the
> browser is fetching the HPKE configuration in real time (and that is
> not my preferred outcome) then it needs to fetch proactively such that
> there is virtually no risk that it ever lacks the necessary HPKE
> configuration to answer requests.
>
> In practice, the best implementation strategy is to use whatever
> remote configuration system the browser already has.  The system in
> Firefox is called Remote Settings, and it allows us to deliver
> time-sensitive configuration information like this.  (We have not yet
> worked out what to do for those people who choose to disable this
> capability.  That's going to disable the API in a way that is visible
> to sites if we're not careful.  That visibility would be bad for
> privacy; the design is such that it should be impossible for a site to
> detect that the API is disabled.)
>
> > ## DAP integration
> >
> > 7.1.2. DAP Extensions [7] discusses extensions AL1 needs. Having clicked
> through to draft-thomson-ppm-dap-attribution-01, I'm not sure I understand
> the purpose of the `budget_source` extension. It's described as being
> opaque, so much so that the contents of the extension aren't even
> specified. But more to the point, it's not clear what, if anything, DAP
> aggregators are meant to do with this extension. If the idea is to
> introduce some kind of domain separation between one task and the next,
> couldn't that be achieved without an extension, for instance by using
> `task_info` or the task ID? [8] That being said, I don't object to a task
> extension that does nothing but indicate that all participants agree that
> some mechanism is in use.
>
> The mechanism is buried here:
>
>
> https://w3c.github.io/attribution/#dap-extensions:~:text=The%20extension%20codepoint%20for%20privacy%20budget%20source%2C%20mapped%20to%20the%20serialized%20host%20component%20of%20topLevelSite
>
> It doesn't carry a lot of explanation, but I don't think that there is
> much point in going into the design details here.  The plan was to
> have the explanation in the IETF doc, but I concede that it's a bit
> sparse there.  I'll juice that up a little.
>
> https://github.com/martinthomson/dap-attribution/pull/13
>
> Task diversity/domain separation is about all this achieves. The
> privacy architecture requires that reports for different sites cannot
> be aggregated together.  That means binding the identity of the thing
> that controls the privacy budget to the task.  The task_info parameter
> could be used for this much, but we have identified that as something
> that we might want to give sites access to (see
> https://github.com/w3c/attribution/issues/363 for discussion of that),
> so in the interests of keeping it clear this is moved to an extension.
>
> Given that these parameters might never traverse the wire anywhere, is
> there any reason why this is a poor design choice?
>
> > Also, 7.1.2. says the extensions are "necessary for this application".
> Is "necessary" enough or should this be an RFC 2119 MUST to ensure
> applications do the right thing w.r.t. constructing task extensions and
> HPKE AAD?
>
> This is a style/norms difference.  W3C specs generally don't both with
> MUST for the stuff that is described with algorithms, as much of the
> processing here is.  Implementations are required to run the
> algorithms, or an equivalent that is functionally indistinguishable to
> sites.  So yes, you can't implement this without this extension; the
> steps ensure that there is effectively a MUST-level requirement.  The
> "necessary" is explanation only.
>
> > Much of 7.1.3. Report Encryption for DAP [9] restates things already
> explicitly laid out in documents like draft-ietf-ppm-dap or
> draft-ietf-ppm-l1-bound-sum. For example, there's no need to dictate the
> use of Field128, because Prio3L1BoundSum is already defined to use that
> field and no other. Or in step 11, you say to construct report IDs by
> sampling 16 bytes from a CSPRNG, which duplicates the prescription in DAP
> 4.4.2 [10].
>
> This is one of the hard parts of this style of specification.  We have
> to spell out the algorithm in enough detail that it is complete.  The
> current approach is slightly overly-detailed as a result.  I've wound
> some of it back, but there's a ragged edge to deal with.  DAP doesn't
> have a clean interface I can invoke. It's almost fractal in nature,
> even.  (Nor would it be clean if it existed: there are far too many
> parameters.)
>
> In any case, after reviewing, I think that this is as close as a W3C
> spec can get to saying "do DAP".
>
> > I'm concerned about the risk of this document and PPM documents
> accidentally disagreeing, which is a headache for implementers and requires
> errata to clean up. Could AL1 say approximately "do the upload interaction
> per DAP section 4.4, using the Prio3L1BoundSum VDAF"?
>
> I share that concern.  But when I reviewed the procedures, the amount
> of DAP/PPM stuff that was duplicated was pretty small.  Some small
> pieces, but always in service of being able to say where the AL1
> pieces go.  The field point you make is a clear example of something
> that doesn't need to be fixed, but I couldn't see cuts that work
> elsewhere.  Without the small overlap, there's no way to explain how
> different values slot into the DAP/PPM pieces.
>
> I've opened a PR to tweak some of this:
>
> https://github.com/w3c/attribution/pull/437
>
> > `min_batch_size` is fixed to 20. Can you comment on this choice? Why is
> it fixed, and why 20? Same goes for the `time_precision` of 5.
>
> These are basically arbitrary values.  Unlike other DAP uses -- those
> that rely on shuffle DP, in particular -- the batch size doesn't
> really form any load-bearing part of the privacy architecture, so the
> value was chosen after not a lot of consideration and a short
> conversation with the group.  It could be 1, but my sense was that
> people might be uncomfortable with that.
>
> The time precision is, again, arbitrary.  We need a fixed value and
> this seemed like a reasonable choice.  I can't imagine any way in
> which this matters for anyone, except when you are attempting to use
> time in anti-replay in the aggregators.
>
> If you have suggestions for rationale that might guide this decision
> in a more principled fashion, I'm open to anything you might have.  I
> couldn't come up with anything.
>
> > `batch_mode` is TBD. OK, fine, the document isn't finished, but I'm
> curious: draft-thomson-ppm-dap-attribution-01 defines a "collector chosen"
> batch mode. Is the intent that AL1 will require that batch mode
> unconditionally or will it allow multiple batch modes? I think either is
> fine.
>
> It's only the code point that is TBD.  This fixes the batch mode to
> the "collector selected" mode.  No other mode is compatible with the
> architecture we've defined.  No hard reason to deny other modes, but
> they don't lead to better outcomes.
>
> > ## Histogram layout consensus
> >
> > I'm going to guess this has been argued about a bunch already. But here
> I go anyway.
> >
> > In 3.4. Saving Impressions [4], we learn that the `saveImpression` side
> indicates the `histogramIndex` into which the impression should be
> recorded. 4.1. Impression Store [18] tells us that the user-agent is meant
> to store both that index and the impression site where `saveImpression` was
> called.
> >
> > IIUC, the histogram buckets are labeled by site. So a particular
> `saveImpression` call creates an association between a histogram index and
> a site, right?
>
> That's only an example.  Sites need to work out what histogram
> labeling they want to use.
>
> The spec says:
> > Different groupings might be used for different purposes. For instance,
> grouping by creative (the content of an ad) might be used to learn which
> creative works best.
>
> > The measurement site doesn't need to agree on the histogram layout, but
> it does have to indicate the size of the histogram [12].
> >
> > All this means that every impression site has to share a consistent view
> of the histogram layout, and conversion sites at least have to agree with
> other sites on the size.
>
> Consistent use of indices is a natural requirement for this setup to
> work.  But it's not quite "every impression site".  It's "every
> impression that might be selected for attribution by a single
> conversion".  A site can use other fields, like the `matchValue`, to
> separate impressions out into different histograms.  For instance, you
> could have `matchValue=2` correspond to an impression site breakdown,
> `matchValue=3` correspond to a creative breakdown, and `matchValue=4`
> correspond to a combination of age demographic and impression site.
>
> (Just an aside: I note you say "conversion sites", plural.
> Impressions can target multiple impression sites, but that's a pretty
> advanced usage.  We do expect most ads to target one destination in
> most cases.  The coordination problems in usage here are already
> tricky enough.)
>
> > What if `a.example` and `b.example` both use the same index? Or what if
> two `saveImpression` calls from `a.example` use different indices? What if
> the conversion site comes along and indicates a histogram size smaller than
> what the impression sites expected? Do impressions whose indices are too
> large just get invalidated and discarded?
>
> As noted above, what an index means needs to be consistent only within
> the scope of impressions that are selected for attribution with a
> specific conversion.  So a.example and b.example can use the same
> indices, if that is what they want to do.  If they are saving
> impressions for different advertisers, there is no need to coordinate
> indices.  If the goal is to measure something other than the site in
> the histogram (because you want to know which creative performs best,
> for instance), then they will definitely want to use the same index,
> even if the impressions are expected to be included in the same
> histogram.  And there is always the `matchValue` that could be used to
> have the impressions fit into different histograms.
>
> All of this is just a toolkit, to be used any way the sites choose, so
> there is no clear set of rules to follow.  The explanation in this
> document is intended to help people start to understand how to use the
> API.  More advanced uses are very much possible.
>
> > I'm concerned about cases where impression sites disagreeing on
> histogram layout could undetectably corrupt aggregate output.
>
> Yes, this is probably the most obvious way in which the API could end
> up being not useful.  Multi-party coordination is a hard operational
> problem.
>
> The way we have designed the intermediary usage of the API is intended
> to mitigate against some of that.  An intermediary (read: ad tech) can
> avoid this problem by doing all of the work itself.  The impression
> saving and conversion measurement, when run by the same entity, is far
> less error prone in the way you identify.  Our expectation is that
> this will be the way that the API is first used.
>
> The other way to manage this is to have the source of ads provide all
> the necessary `saveImpression()` values.  That switches things back to
> a single point of control, reducing the likelihood that an error
> occurs.  Of course, this assumes a simpler deployment architecture
> than is typically part of the ad buy and distribution architectures
> out there, so even this is a non-trivial undertaking.
>
> It's important to recognize that we don't want to dismiss the
> operational challenges in getting this API to work well.  But there is
> only so much a specification can do with hand-holding.
>
> > What if the `saveImpression` and `measureConversion` API calls included
> a byte string identifying a particular histogram layout? Off the top of my
> head, it could be the digest of the bucket labels, ordered by histogram
> index. You could then also fold that histogram layout hash into the DAP
> task configuration, so that some site using stale JavaScript for whatever
> reason doesn't contaminate aggregations.
>
> That's not a bad idea.  This is, to a very rough approximation, what
> the `matchValue` field can achieve.  We discussed having that be a
> byte string for basically that reason.  But we concluded that an
> integer is easier to reason about for basic uses.  It loses some of
> the accidental misuse properties that you get from a checksum, but it
> takes less effort to propagate through various ad tech systems.
>
> See https://github.com/w3c/attribution/issues/58, which we still have
> open for consideration in a future iteration of the API design.  There
> are links to several related discussions.
>
> > ## Saving impressions
> >
> > 3.4. Saving Impressions [4] discusses the `options.priority` parameter,
> which is set by the impression site and later used to allocate credit at
> conversion measurement time (4.4.2.1). Aren't impression sites incentivized
> to exaggerate their priority to get more credit?
> >
> > This goes to a bigger question: what's the security model here? Are the
> impression and conversion sites adversaries, or is there an assumption of
> control by a common actor?
>
> We had some text about that already under the Ad Fraud section
> (https://w3c.github.io/attribution/#security-ad-fraud).  But I realize
> that this was a bit lightweight.
>
> https://github.com/w3c/attribution/pull/438 expands on that a little more.
>
> > It makes intuitive sense that impression sites may wish to constrain
> which sites can measure conversions via `options.{conversionSites,
> conversionCallers}`. But since the impression and conversion can be
> something like a week apart, does this pose an operational problem in
> deployments? What if the set of legitimate conversion sites has changed
> since the impression occurred?
>
> Yes, this goes back to the discussion above regarding the need for
> coordination.  Not a lot to be done to improve things.
>
> > ## Measuring conversions
> >
> > 2. Overview of Operation [11] says:
> >
> > > If the query found no impressions, or the privacy budget for the site
> is exhausted, a histogram consisting entirely of zeros (0) is constructed.
> >
> > We've done this in other DAP deployments, and it worked as far as hiding
> the fact that some event hadn't occurred. But the extra workload from
> summing zeroes was not insignificant, so much so that it wound up being a
> good tradeoff to deploy Oblivious HTTP to conceal the absence of an event
> instead of synthesizing empty contributions. That wouldn't work here,
> because you're trying to hide the absence of an event from the local
> JavaScript rather than some remote server. Anyway -- do you have a sense of
> what the proportion of zero to nonzero reports will be? i.e. how much work
> will be wasted? If the contributions are overwhelmingly zeroes, then it
> might be worth doing something about that.
>
> The overall volume corresponds directly to the number of conversions.
> So the expectation is that the cost is something that a site can
> directly account for.  For instance, if the conversion is a sale, then
> there is some amount of overhead in each sale to account for the cost
> of this attribution.  My understanding is that, while the cost might
> seem pretty big from your perspective, as a potential operator of the
> aggregation service, the overall cost is negligible relative to a sale
> or even account sign-up.  (Cost for customer acquisition through
> advertising varies greatly, but it is orders of magnitude greater than
> the cost of attribution.)
>
> > 3.5. Requesting Attribution for a Conversion [12] describes the
> `measureConversion` API. What happens if a conversion site calls
> `measureConversion` multiple times --
> >
> > - if the parameters are exactly the same both times?
> >   - Do both calls succeed, yielding identical histograms or does the
> second call fail?
> >   - Or does the second call yield (unbeknownst to the caller) an
> all-zeroes histogram because the first call consumed the impressions?
>
> Both should succeed, but the second might have an all-zero histogram.
> Not because the impressions got consumed, but because some amount of
> privacy budget is expended on both.  If the first spent all of the
> budget, the second is guaranteed to fail.
>
> > - if the two calls have distinct `options.aggregationService` values?
> >   - Is it allowed to measure the same conversions in two different
> aggregation services, e.g. to check that a TEE and an MPC compute the same
> results?
> >   - If you do allow that, does each call consume some epsilon?
>
> Yes, both queries would consume from the same budget.  Aggregation
> services are expected to follow the same basic differential privacy
> budget enforcement rules.  Of course, we don't have a TEE version
> specified today.
>
> We've discussed reliability and concluded that sites could manage
> this.  See https://github.com/w3c/attribution/issues/60
>
> > ## Document scope
> >
> > 1.5. Collective Privacy Effect [13] discusses the use of central
> differential privacy, calling it "the mathematical basis for the privacy
> design used in this specification". The nuts and bolts of central DP are
> out of scope of the document, instead being described in the privacy budget
> report extension report extension [14]. That's fair enough. But does that
> mean implementations can't or shouldn't do local DP?
>
> Local DP, if implemented without a way of knowing that there is extra
> noise, would constitute spoiling of the results.  None of the
> participants in the process indicated that they thought the
> privacy/utility balance of local DP would work.  In practice, we end
> up with shuffle DP, which is still not as good as the "central" DP we
> get from this.
>
> > Are there any collector<->aggregator interactions that need to be
> described? I suppose those are out of this document's scope, but where do
> they get written down?
>
> I think that DAP has that covered well enough.
>
> > ## Ticky-tacky gripes and typos
> >
> > 4.4.2.1. Last-N-Touch Attribution [15]:
> >
> > > Let sumCredit be the sum of credit’s items.
> >
> > Does this mean `sumCredit` is not necessarily 1.0f? What are the upper
> and lower bounds on `sumCredit`?
>
> It only needs to be finite.  You can split credit using something that
> sums to 1 perfectly [0.3, 0.7] or just make it whatever [1e3, 2e-3].
> The algorithm copes nicely and distributes the value proportionally,
> no matter the sum.
>
> I've opened https://github.com/w3c/attribution/pull/439
>
> > 1.5. Collective Privacy Effect [13]:
> >
> > > If attribution is justified, both these factors motivate the
> enablement of attribution for all users.
> >
> > To be clear, this means this feature is on by default in user-agents?
>
> That's not something that has been decided.  Nor is it something that
> the specification can mandate.  Each user agent will have to make
> their own determination about how the API is enabled and disabled.
>
>
> > 4.2. State For Privacy Budget Management [17] discusses the boolean
> attribution budget lock. I'm surprised the spec has to get this specific,
> and indeed there's a note saying "yeah you might not actually use a
> boolean". The relevant APIs return `Promise<Whatever>` anyway, so can't you
> just say "accessing the store must be threadsafe" and let implementations
> do the right thing? This is probably a W3C/web platform norm I'm unfamiliar
> with.
>
> Indeed it is.  I hate having to do this, but the specifications
> require that you have algorithms that clearly describe everything.
> (In writing this up, I realized that the implementation might be able
> to use a boolean in practice, rather than something like a mutex,
> because the web platform does tend to rely on thread confinement for a
> lot of things.  Still, the note is there for exactly that reason.)
>
> > In various places, the specification requires implementations to
> "attempt to mitigate side channels". This is good advice. What's explicitly
> discussed is timing side channels, but I wonder whether this prescription
> also includes keeping encryption keys or plaintext data out of the address
> space where impression or conversion site code runs? Perhaps that kind of
> separation is assumed in the web platform.
>
> Yeah, that's a very basic assumption that tends to hold generically.
>
> > That's it for now. I look forward to further discussion.
>
> Thanks again!
>
> ~~Martin
>

Received on Tuesday, 26 May 2026 18:22:33 UTC