Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Creative pre-registration strategies #792

Open

Description

@rdgordon-index

As suggested in the explainer, sellers have the ability to fetch additional real-time signals based on a combination of renderURL and hostname (representing the publisher’s domain) that can be used during scoreAd() when scoring creatives. Specifically:

Similarly, sellers may want to fetch information about a specific creative, e.g. the results of some out-of-band ad scanning system

Checking whether the creative contents have been pre-approved by the seller. This could be implemented by an out-of-band creative review process…

In today’s programmatic ecosystem, buyers communicate their creative markup via the bid.adm during RTB, alongside other key bid metadata (advertiser domain, seat ID, IAB category, creative format, creative & campaign identifiers, etc.); however, no creative URL (aka renderURL) containing the markup is provided. As a result, there is no existing mechanism by which SSPs can obtain this URL for all existing creatives submitted in contextual auctions.

This necessarily means that all existing creatives are unable to be served in PA auctions, since creatives have to be pre-approved in order to be scored with a desirability > 0. Otherwise, the rejectReason for all PA creatives returned by scoreAd() would be pending-approval-by-exchange.

This also necessitates a mechanism to initiate such PA creative registration via renderURL, which poses some challenges, as outlined below.

The most naïve such mechanism, available today, would leverage the forDebuggingOnly.reportAdAuctionLoss() endpoint – that is, for any renderURL not found in the seller’s K/V server, initiate an API call to a seller endpoint to indicate that said renderURL has not yet been approved. According to #632 (comment), this function will be available until the end of 3PCD, and should suffice for short-term testing as well as during the 1% 3PCD time horizon.

Challenges with this approach:

  • A significant volume of unregistered created API calls from each device, for each such creative submitted via generateBid()

  • the K/V call doesn’t include a buyer origin - and the renderURL need not utilize the buyer origin – so there is no guaranteed way to map a URL to a given buyer (aka DSP)

  • Other key signals available in OpenRTB – such as adomain and seat – are not guaranteed to be made available to scoreAd() (and hence able to be passed into this debugging endpoint), despite them being required for creative registration. As quoted here

    The metadata accompanying the returned ad is not specified in this document, because sellers and buyers are free to establish whatever protocols they want here.

    As such, without an IAB standard for parameters like seat in renderURL, it’s unclear how buyers will be able to ensure that their creatives are being registered for all sellers.

Another alternative approach would be to somehow leverage the Private Aggregation API, but this shares all of the challenges above, as well as it being unclear how to bucket the fields required for registration (e.g. renderURL, seat, adomain). Furthermore, this also requires the immediate adoption of this API (and its requirement for TEE) in order to be able to start registering creatives, and as such, this does not seem like a short-term solution.

Activity

  1. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    One thing we need to be careful with here is about leaking data - renderURLs haven't been checked for k-anonymity, and so requesting them can leak data (e.g., if we send them only when offered in a bid, then they could pass in a user ID for the publisher page that could be correlated with a user ID on the joining origin. 32 IGs could provide one bit of publisher page ID each, like: https://foo.test/bit-0-is-1?user=FreddyPharkas, https://foo.test/bit-1-is-0?user=FreddyPharkas, etc. Each URL has the full user ID in the joining origin, and one ordered bit from the top-level-site where the auction is running).

    Sending renderURLs on IG join would be more practical, but we don't know the seller origin to send the information to, and we'd need the IG to opt-in to sending the information (normally, offering a bid is considered to provide that permission).

    So I think we need to figure out the privacy story here on how we can implement this without creating a new cross-top-level-origin information leak.

  2. rdgordon-index commented on Sep 12, 2023

    @rdgordon-index
    ContributorAuthor

    renderURLs haven't been checked for k-anonymity

    Can you elaborate? As per https://github.com/WICG/turtledove/blob/main/FLEDGE.md#33-metadata-with-the-ad-bid, I wasn't expecting scoreAd() to ever receive a renderURL from generateBid() that didn't pass the k-anon check.

    If generateBid() picks an ad whose rendering URL is not yet above the browser-enforced microtargeting prevention threshold, then the function will be called a second time, this time with a modified interestGroup argument that includes only the subset of the group's ads that are over threshold. (The under-threshold ad will, however, be counted towards the microtargeting thresholding for future auctions for this and other users.)

  3. michaelkleber commented on Sep 12, 2023

    @michaelkleber
    Collaborator

    Sending on IG join would be great, from the privacy POV. If only IGs declared which sellers they were willing to bit with, this would be the preferred approach. But that hasn't been a required part of IG metadata until now. I suspect that if we propose it we will hear push-back, but maybe I'm being too pessimistic? Roni, want to pop my bubble quickly?

    Can you elaborate? As per https://github.com/WICG/turtledove/blob/main/FLEDGE.md#33-metadata-with-the-ad-bid, I wasn't expecting scoreAd() to ever receive a renderURL from generateBid() that didn't pass the k-anon check.

    We do pass bids along to scoreAd() even if they are for ads below the k-anon bar — we need to do that, otherwise we could never learn whether they would have been the winner, which is the condition for warming up their k-anonymity count.

  4. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    Only render URLs that win auctions (or rather, that would have won auctions) are registered with the k-anon server for the purposes of calculating k-anonymity, as otherwise, an ad could only be show to a single user, despite appearing in IGs for a lot of users. So if you're blocking ads that you've never seen before, they'll never reach the k-anon threshold. Therefore, this would need to be done for non-k-anon ads.

  5. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    And just to be clear - I mean the ads need to have won the top-level auction, in an environment that doesn't know whether they've met the k-anon threshold or not. My understanding is that you'd want to know the URL so it can be scanned before showing it anywhere. If that's not the case, and this can all be done after the ad has hit the k-anon threshold and we've already started showing the ad to users, this becomes much easier to do. We may need some sort of k-anon <renderURL, seller, component auction bool> check on how often an ad has won auctions, and once it's hit, have some way of conveying it to sellers, whether directly, or through an aggregation server of some sort.

  6. rdgordon-index commented on Sep 12, 2023

    @rdgordon-index
    ContributorAuthor

    My understanding is that you'd want to know the URL so it can be scanned before showing it anywhere.

    Correct.

    check on how often an ad has won auctions, and once it's hit, have some way of conveying it to sellers

    To be clear, there's no desire to trigger this registration under the k-anon threshold; in other words, if a creative won't be shown to N devices, then there's no need to register it "before" it reaches this threshold.

  7. rdgordon-index commented on Sep 12, 2023

    @rdgordon-index
    ContributorAuthor

    We do pass bids along to scoreAd() even if they are for ads below the k-anon bar

    Only render URLs that win auctions (or rather, that would have won auctions) are registered with the k-anon server for the purposes of calculating k-anonymity

    IMHO it isn't immediately obvious that from the explainer that this ever reaches scoreAd() -- though, upon further inspection, it's somewhat implied from this text in https://github.com/WICG/turtledove/blob/main/FLEDGE.md#12-interest-group-attributes (emphasis added):

    The browser will provide protection against microtargeting, by only rendering an ad if the same rendering URL is being shown to a sufficiently large number of people (e.g. at least 100 people would have seen the ad, if it were allowed to show)

  8. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    Agree that the explainer could be clearer on this point. I think this is the first case that's come up where the distinction really matters.

  9. rdgordon-index commented on Sep 12, 2023

    @rdgordon-index
    ContributorAuthor

    Sending on IG join would be great, from the privacy POV. If only IGs declared which sellers they were willing to bit with, this would be the preferred approach. But that hasn't been a required part of IG metadata until now. I suspect that if we propose it we will hear push-back, but maybe I'm being too pessimistic? Roni, want to pop my bubble quickly?

    That would add complexity if an existing buyer/IG wanted to start working with a new seller, correct? Would updateURL allow for post-join updates to a seller list?

    That being said, even if IG seller declaration were in place, that doesn't address the challenge of being able to leverage the metadata provided by generateBid() when registering these new creatives, as noted in the issue description. In other words, it's not solely about making renderURLs available off-device -- though that's definitely part of the challenge.

  10. rdgordon-index commented on Sep 12, 2023

    @rdgordon-index
    ContributorAuthor

    as otherwise, an ad could only be show to a single user, despite appearing in IGs for a lot of users

    Just so that I fully understand the privacy concern -- doesn't that situation arise the first time the ad across the k-anon threshold already?

  11. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    I think we could pass along renderURLs to new sellers when fetching the updateURL without any major new privacy issues, though that would potentially add a bunch of network requests and overhead (We'd need up update new sellers about renderURLs, and update old sellers about new renderURLs, so if we inform sellers directly from Chrome, that could be a lot of extra traffic).

    I don't think sending extra metadata specified by the IG affects the privacy characteristics here if we send the information on join (as opposed to on win on a 3P site, where it would need to be added to the k-anon check, at least). We are putting more complexity and overhead on the browser here for something that the browser doesn't really need to care about, unfortunately. Ideally we'd keep the browser API surface for this as minimal as possible.

  12. MattMenke2 commented on Sep 12, 2023

    @MattMenke2
    Contributor

    Just so that I fully understand the privacy concern -- doesn't that situation arise the first time the ad across the k-anon threshold already?

    So, ideally the DSP and SSP don't know when the ad reaches the k-anon threshold for the first time, so can't alter behavior based on that. It can only get so much information from loss reports, and auctions are run in a manner that limits information it can get out of them. Only doing the k-anon counting after it wins the auction is done in part to protect against exactly that sort of gaming the system.

  13. michaelkleber commented on Sep 15, 2023

    @michaelkleber
    Collaborator

    I'm still wondering whether we can find a safe way to make this happen at IG Join and Update time. Really this is kind of about the browser mediating a direct flow of information from DSP to SSP, if both of them are OK with us doing so. I'm thinking something like:

    (1) Suppose SSP X has run auctions in the past [period of time] in which X has invited DSP Y to be a buyer and some Y IG has placed a bid. (Each browser instance could keep track of this.)

    (2) Suppose the IG object on which DSP Y calls Join includes a new field 'OkayToTellSellersMyAdUrls': true.

    If both of those are true, then at the moment of IG Join, it seems to me like it would be OK for the browser to contact that SSP's KV server — if we knew the base URL somehow — and ask for the associated KV signals for each renderURL in the IG. And then if no KV signals came back, we could send the renderURL to some SSP-chosen scan-queueing endpoint, maybe as identified by the SSP in the KV response.

    This could even be one instead of two round-trips, since I don't think there's any need for the first one to go to a trusted server, this is just a question of what endpoints are set up to receive a lot of traffic (KV expecting calls on each auction) vs only a little (scan-queueing expecting traffic only when a new renderURL appears).

  14. rdgordon-index commented on Sep 19, 2023

    @rdgordon-index
    ContributorAuthor

    and the renderURL need not utilize the buyer origin

    As per the new guidance in https://github.com/WICG/turtledove/blob/main/FLEDGE.md#14-buyer-security-considerations :

    the ads renderURLs should not be same-origin with the interest group’s owner

    This confirms that there will be no a priori method to be able to associate a renderURL with a particular buyer (aka DSP), which is one of the challenges noted above.

  15. pm-harshad-mane commented on Oct 6, 2023

    @pm-harshad-mane

    This confirms that there will be no a priori method to be able to associate a renderURL with a particular buyer (aka DSP), which is one of the challenges noted above.

    In this situation, DSPs should tell SSP partners which domain they will use in the renderingURL so that SSP can keep track of it on their KV server to recognize the DSP partner from the renderingURL.

  16. 55 remaining items

  17. orrb1 commented on Jan 31, 2025

    @orrb1
    Collaborator

    Thanks for the follow-up questions, and for the discussion at the recent PA WICG Call. Responses inline.

    Can you confirm that you will plumb creativeScanningMetadata associated with each bid into scoreAd()?

    Yes, we will pass creativeScanningMetadata into scoreAd() as part of the browserSignals argument. We will do so for both the main ad as a new string-typed creativeScanningMetadata field of browserSignals, and for component ads as a new adComponentsCreativeScanningMetadata field of browserSignals, an array of strings-or-null.

    PA's Deals implementation introduced buyerAndSellerReportingId (aka BASRI) as carriage for a buyer's seat id as known to the seller. This value isn't proposed as a seller scoring KV fetch parameter. Sellers need seat for scoring (for everything, really), so as currently spec'd buyers are going to have to duplicate 'seat' in the creativeScanningMetadata structure. How about adding BASRI as a KV parameter?

    In PA WICG Call, we discussed how generateBid() must return a selectedBuyerAndSellerReportingId in order for that bid's buyerAndSellerReportingId to be included as a part of the browserSignals argument to scoreAd(). There was some feedback that it might be fairly standard to provide a selectedBuyerAndSellerReportingId, even if it's an empty string, so that buyerAndSellerReportingId would always be provided. As noted during that call, please recall that selecting a selectedBuyerAndSellerReportingId has k-anonymity implications as described in the Reporting IDs developer guide.


    There's another important distinction between buyerAndSellerReportingId and creativeScanningMetadata — buyerAndSellerReportingId (and all of the other reporting ID fields) may only be provided on main ads, not component ads. In scoreAd(), you get one bid with one main ad and possibly some component ads. However, the seller signals request may contain multiple main ads and any number of associated component ads, so that you can't necessarily determine which main ad is associated with each component ad. It is guaranteed that component ads will be on the same seller signals request as their enclosing main ad.

    Is it safe to assume that the seat expressed in buyerAndSellerReportingId for the main ad also applies to all of the component ads of a bid? Is it also safe to assume that any two ads/component ads that share an adomain would also share a seat? Combined, what I'm asking is - given the creativeScanningMetadata for all of the ads and component ads on a seller signals request, and the buyerAndSellerReportingId for the main ad alone, is that sufficient to infer the seat for the component ads in that request? If so, we could add a new query parameter, adBuyerAndSellerReportingIds, which would contain the buyerAndSellerReportingId for only the main ads of each seller signals request.

    Proposal currently specifies creativeScanningMetadata as a string as opposed to following the pattern/precedent set by IG.ads[].metadata that permits "any JSON serialisable value," which Chrome then stringifies via JSON.toString() internally. Can you follow the metadata handling?

    While metadata on the interest group and the adMetadata provided as an argument to scoreAd() are primarily intended to be provided as arguments to JavaScript functions, creativeScanningMetadata is primarily intended to be sent as a query parameter on the seller signals request. As a query parameter, creativeScanningMetadata is subject to both escaping and size limits on the request URL. As such, it's preferable for creativeScanningMetadata to be a simpler and more concise representation of the data needed for creative scanning, which is why we recommend having this field be string-typed instead of allowing any JSON-serializable value.

  18. eysegal commented on Feb 11, 2025

    @eysegal

    Hi @orrb1, so the buyer would be able to set relevant metadata in creativeScanningMetadata, like ad title and branding text, and that metadata will be available in the seller's Trusted Server?

    Thanks

  19. jeremybaoty commented on Feb 11, 2025

    @jeremybaoty

    Hi team, so we have also posted a proposal to make selectedBuyerAndSellerReportingId a key in the trustedScoringSignals request under the Github post for deals. This is quite related to Orr's comments above, and we would love your feedback in both proposals!

  20. omriariav commented on Feb 25, 2025

    @omriariav

    @orrb1 can you please take a look at. @eysegal comment? #792 (comment)

  21. orrb1 commented on Mar 5, 2025

    @orrb1
    Collaborator

    Hi all. Sorry for the delay.

    creativeScanningMetadata is a new string-typed field on the ads structure within each interest group. Interest group owners can add any information about that ad that they wish to share with sellers that can be used to support creative scanning. The value of the creativeScanningMetadata will be included in the arguments to scoreAd() as browserSignals.creativeScanningMetadata for ads and as browserSignals.adComponentsCreativeScanningMetadata for component ads; and included in the trusted scoring signals request URL in the adCreativeScanningMetadata query parameter for ads and in the adComponentCreativeScanningMetadata query parameter for component ads. More details are available in this explainer update.

    Please note, support for creativeScanningMetadata and sendCreativeScanningMetadata is now available for testing on 50% of Chrome Canary/Dev channel traffic. It can also be manually enabled using the --enable-features=FledgeTrustedSignalsKVv1CreativeScanning command line flag.

  22. dmdabbs commented on Mar 10, 2025

    @dmdabbs
    Contributor

    Please note, support for creativeScanningMetadata and sendCreativeScanningMetadata is now available for testing on 50% of Chrome Canary/Dev channel traffic. It can also be manually enabled using the --enable-features=FledgeTrustedSignalsKVv1CreativeScanning command line flag.

    A new entry for this (Creative scanning via BYOS/V1 trusted scoring signals) appeared the other day on the stable M134 Chromestatus entry as "Enabled by default." Did you mean 135 or beyond?

  23. orrb1 commented on Mar 18, 2025

    @orrb1
    Collaborator

    @dmdabbs - Point well taken. The chromestatus feature has been corrected.

    Support for creativeScanningMetadata and sendCreativeScanningMetadata is now available for testing on 50% of Chrome Beta channel traffic. It can also be manually enabled using the --enable-features=FledgeTrustedSignalsKVv1CreativeScanning command line flag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions