API change to trigger a daily update right after a JoinAdInterestGroup event.
gianni-99 opened this issue · 12 comments
This issue relates to improving the process of adding users to interest groups. Specifically the latency and processing of the tagging request and response from advertiser page scripts.
Moving to the header api as proposed elsewhere will reduce the need for iFrames on the advertiser page and it is a first step in this direction.
A second idea is to have a “lightweight” tagging request and response that only sets up the IG scaffolding in joinAdInterestGroup and rely on the update request to propagate the other IG data and ads. This would reduce the server side processing at tagging time.
To avoid losing the first (few?) auction opportunities due to 0 ads on device, we propose an API change for joinAdInterestGroup where, optionally, the first update request is triggered shortly after the join event. That could be achieved with:
- a parameter called something like triggerFirstUpdateDelayMs
Example:navigator.joinAdInterestGroup(myGroup,triggerFirstUpdateDelayMs);
- an optional fixed delay enabled by boolean called triggerEarlyUpdate that requests an early update with say a 1,000 ms delay (1 second). Example:
navigator.joinAdInterestGroup(myGroup,triggerEarlyUpdate);
The delay should be in the order of a few seconds at most.
Hello @gianni-99.
Interesting proposal. Agree with lightening the initial join-time footprint and deferring remainder to updates. Will you be bringing this to a Wednesday Chrome team WICG meeting?
Think the proposal is good. I expect it will be common for participants to minimize the effort around managing IGs by localizing definitions on update servers and having all new IGs just created as shells that aren't filled out until the update call.
Occurred to me in reading:
A second idea is to have a “lightweight” tagging request and response that only sets up the IG scaffolding in joinAdInterestGroup and rely on the update request to propagate the other IG data and ads.
It maybe useful to have the browser identify IGs that aren't complete enough to be functional and prioritize them for updating with a limited number of retries after which they are deleted.
Also noticed that the updateUrl is not a required property in the IG definition per this, seems like it should be required to avoid creating zombie IGs.
Yes it seems a good idea to present this in a Wednesday meeting.
RE: non functional IGs: they might still be useful. For example, if a user goes to an advertiser site before the campaign is fully rolled out, one might want to keep the relevant IG on device with low resource utilization (0 ads for example). The update would propagate the new ads as the campaign is fully rolled out. Hence, it might be a little difficult to identify truly zombie non functional IGs (no updateUrl and ads=[] could be a starting point).
RE: mandatory updateUrl. I agree that, if we implement the delayed ads population option, updateUrl would be necessary. I am not sure we need that requirement when one registers IGs with ads.
Hence, it might be a little difficult to identify truly zombie non functional IGs (no updateUrl and ads=[] could be a starting point).
Yes, I have observed IGs joining with neither updateURL
nor ads
, sometimes quite a few on a single page load, page after page. If these have appreciable impacts, either to storage or auction performance, then consider preventing their joining.
Yes, I have observed IGs joining with neither updateURL nor ads, sometimes quite a few on a single page load, page after page.
I've seen this as well. If folks don't have a way to query for the existence of an IG, the alternative is to assume it doesn't exist and try to create it at every opportunity. I think we're going to want some way of telling the browser to silently fail the request to create IG if it already exists.
RE: mandatory updateUrl. I agree that, if we implement the delayed ads population option, updateUrl would be necessary. I am not sure we need that requirement when one registers IGs with ads.
I suppose updateUrl isn't strictly necessary, but it means having IGs floating around that are unmodifiable and that raises a question about what to do if problems are discovered. I've worked on systems with similar restrictions on querying existing state and all we could do was blindly modify state and blindly request actions with no idea if they would be or applied or not and one of the capabilities we found we wanted that I think we may want with IGs also was the ability to ask the receiver to delete itself. I imagine folks are going to want to be able to proactively request browsers to immediately expire IGs if they exist and that would presumably have to happen via the updateUrl.
Thanks @gianni-99. Since frames/script activation is well-established, here's a cut at describing the deferral mechanism and a quick follow-on header implementation that would inherit it.
To avoid losing the first (few?) auction opportunities due to 0 ads on device, we propose an API change for joinAdInterestGroup where, optionally, the first update request is triggered shortly after the join event. That could be achieved with:
To confirm, the feature seeks to transfer the complete IG rendering from the page critical path to updateURL
's background thirty-second timeout. In other words, no reduction in the number of complete render calls. @thegreatfatzby, reducing expensive calls was in your sights in the Wednesday discussion, and it's desirable, but let's sketch a K.I.S.S. baseline.
- a parameter called something like triggerFirstUpdateDelayMs
Example:navigator.joinAdInterestGroup(myGroup,triggerFirstUpdateDelayMs);
- an optional fixed delay enabled by boolean called triggerEarlyUpdate that requests an early update with say a 1,000 ms delay (1 second). Example:
navigator.joinAdInterestGroup(myGroup,triggerEarlyUpdate);
The delay should be in the order of a few seconds at most.
Since PA still supports the 'legacy' two parameter joinAdInterestGroup
signature, how about a read-and-discard attribute (like lifetimeMs
that is converted to expirationTime
). Your first option offers flexibility, so (extending the explainer example):
const myGroup = {
"owner": "https://www.example-dsp.com",
"name": "womens-running-shoes",
"lifetimeMs": 2592000000,
"updateURL": "https://www.example-dsp.com/...",
"triggerFirstUpdateDelayMs": 3000
};
joinAdInterestGroup(myGroup);
Behaviors
Closing the page and navigations should be handled (not closing the browser), so the desired triggering is something analagous to fetchLater's contract. That is, Chrome will process the updateURL
after the timeout or when the page is unloaded, whichever comes first.
If triggerFirstUpdateDelayMs
is specified and updateURL
is not the call will throw.
Rapid Follow-on Header Implementation Proposal
A joinAdInterestGroup
header implementation could initially support only the 'shell' use case's minimal item set, later on solving marshaling arbitrary IG Javascript values from complex/nested Structured Field Values:
Join-Ad-Interest-Group: owner=%"https://www.example-dsp.com", name=%"womens-running-shoes", lifetimeMs=2592000000, updateURL=%"https://www.example-dsp.com/...", triggerFirstUpdateDelayMs=3000
A header that is not a dictionary or that does not include all these valid keys would not be processed.
Any other failures (parsing, Permissions, enrollment, &c) would likewise fail silently (unless some .well-known error reporting callback would be considered).
The header may appear multiple times and must not be coalesced (similar to how Set-Cookie
is handled).
String values are Display Strings since this seems closest to how PA specifies these values.
Hello @gianni-99. We discussed this issue in today's FLEDGE call. Response was positive - it all seems like a good idea.
To avoid losing the first (few?) auction opportunities due to 0 ads on device, we propose an API change for joinAdInterestGroup where, optionally, the first update request is triggered shortly after the join event. That could be achieved with:
- a parameter called something like triggerFirstUpdateDelayMs Example:navigator.joinAdInterestGroup(myGroup,triggerFirstUpdateDelayMs);
- an optional fixed delay enabled by boolean called triggerEarlyUpdate that requests an early update with say a 1,000 ms delay (1 second). Example:navigator.joinAdInterestGroup(myGroup,triggerEarlyUpdate);
The delay should be in the order of a few seconds at most.
I suggest we allow IGs to be created with a minimum set of values and flagged to indicate an update is required before they will be operational. If the flag is present, the browser adds the IG to a FIFO update queue which is processed by the browser opportunistically. Until the update is completed, the IGs are otherwise ignored. Attempts to create IGs with this flag that don't include the minimum set of values fail with an error.
Also, as suggested previously: I think we're going to want some way of telling the browser to silently fail the request to create IG if it already exists.
Reading through the meeting notes I see discussion about not persisting the update queue with @michaelkleber indicating it is undesirable, in part because of the possibility that errors would create failure cycles. I want to push back on that as I think it disincentivizes adoption of what I think may be a generally healthful capability.
I expect what I'll call 2-phase IG creation which separates IG creation concerns from IG asset population is going to be a popular pattern.
- It allows IG owners to maintain a lightweight distributed footprint for IG creation and concentrate IG asset management on the update server. Doing asset management through the update server is easier, reuses the process established for general updates, localizes problem detection and resolution and results in more consistent IG populations since they are all reading from a single source.
- It reduces the burden on websites supporting IG creation as creating a minimum viable IG is much simpler and lighter weight than creating fully functional ones.
- It provides the browser with opportunities for balancing resource requirements by allowing it to defer IG creation heavy-lifting until competition for resources is minimal, thus both having less impact on user experience and increasing the likelihood of IGs being successfully established.
However, if 2-phase IG creation is considered to be less reliable than all-at-once creation because there is a meaningful possibility the ephemeral update queue will be destroyed before the second phase is completed, folks will be reluctant to use it and in cases where they're compelled to, there will be a lot of competition to be at the front of the queue which is likely to cause problems.
So, rather than making the update queue ephemeral, I suggest we make it a persistent FIFO queue and just remove an IG to be updated from the queue prior to attempting to update it. If a crash occurs, the IG update won't be retried. If the update fails with an error indicating a transient problem, we allow the IG to be queued again up to N number of times, potentially with a backoff.
Summarizing 2-phase IG creation suggestions:
- Allow creation of minimum viable IGs that are required to include owner, name and updateURL and add a parameter to joinAdInterestGroup() to indicate the IG should be queued for immediate update with a default of false. If the flag is true, the browser adds the IG to a FIFO update queue which is processed by the browser opportunistically. Until the update is completed, the IGs are otherwise ignored. Attempts to create IGs with this flag that don't include the minimum set of values fail with an error.
- Add a parameter to joinAdInterestGroup() to indicate the IG should be replaced if it already exists and default to true. If the flag is false, the IG will be created if it doesn't exist and left untouched if it does, in either case the return value is the same.
A header-based join/leave/clear should also support fetchLater API.
Chrome is migrating keep-alive request handling from the “renderer” (front-end) to the “browser” process (back-end). Explainer. Attribution Reporting API (ARA) supports event and trigger header registrations on background requests, and this will move to the browser. ARA team has extended that hook so that fetchLater requests can also set ARA headers. Requesting that Protected Audience header processing also support fetchLater.