feat: add event context extension for cart and checkout sessions#295
feat: add event context extension for cart and checkout sessions#295jamesandersen wants to merge 1 commit intoUniversal-Commerce-Protocol:mainfrom
Conversation
c3072a5 to
bd739fb
Compare
| } | ||
| } | ||
| }, | ||
| "dev.ucp.shopping.checkout": { |
There was a problem hiding this comment.
Should attribution extension be applied to Cart as well, in addition to Checkout? Please see discounts extension as an example where it can extend both cart and checkout. In future, it could extend other events as well, but for now maybe starting with Cart and Checkout is a good idea. What do you think?
There was a problem hiding this comment.
Forgot to note it here earlier but did update the PR for this already.
There was a problem hiding this comment.
Would/should this be sent with every request one the Agent identifies the checkout session was initiated by an Event?
If so, what would this mean with multi-item cart/checkout where multiple items were added
| "dedup_keys": { | ||
| "type": "object", | ||
| "description": "Deduplication keys for reconciling this event with the merchant's own server-side reporting. Without these, the same transaction may be counted twice in analytics and reporting platforms.", | ||
| "properties": { |
There was a problem hiding this comment.
Both event_id and session_id are optional, making an empty dedup_keys: {} schema-valid and semantically meaningless. Should we add "minProperties": 1 to prevent this?
If dedup_keys is there, we should have alteast 1 additional property.
There was a problem hiding this comment.
Makes sense - updated
| "custom": { | ||
| "type": "object", | ||
| "description": "Platform-specific key-value pairs not covered by the structured fields above. Merchants pass these through to their analytics integrations based on the platform field.", | ||
| "additionalProperties": true |
There was a problem hiding this comment.
I think you flagged this as a discussion point, I think it is a good idea to add some constraints e.g
"additionalProperties": {
"type": ["string", "number", "boolean"]
},
"maxProperties": 50
There was a problem hiding this comment.
Even 50 feels pretty generous so just added this but set maxProperties to 20 as a start
| The merchant passes `event_id` and `fbp` (from `session_id`) to their | ||
| Conversions API integration. The shared `event_id` prevents duplicate event | ||
| counting between the platform's first-party event and the merchant's server-side | ||
| event. |
There was a problem hiding this comment.
Should we add a callout for privacy:
e.g something like -
Privacy Note:
Platforms and Businesses implementing this extension SHOULD ensure that the transmission of attribution data complies with applicable privacy laws and the user's consent preferences. Data passed via the utm, dedup_keys, or custom fields should only be used for the purposes of attribution and conversion reporting as authorized by the user.
There was a problem hiding this comment.
Good callout ... let me think about this a bit - the data flowing through here is ideally unrelated to the user (e.g. not derived from the user or user identifiable) but rather a flow between the agent and the business to replace data that normally flows via the website.
There was a problem hiding this comment.
Alright added some language to reinforce the privacy posture of this extension ... definitely open to more tweaks on the language but was trying to find something striking a reasonable balance of firmness without being anchored or implying any specific jurisdictions/ regulations / privacy policy / terms of service etc.
| "properties": { | ||
| "platform": { | ||
| "$ref": "types/reverse_domain_name.json", | ||
| "description": "Referring platform identifier (reverse domain naming). SHOULD correspond to the domain of the platform's UCP-Agent profile URL.", |
There was a problem hiding this comment.
What do you think about using MUST for better security? With SHOULD it is possible that a platform could pass com.google attribution while being a different platform entirely.
There was a problem hiding this comment.
Again, good call; updated.
c4b2cf1 to
9b6cfdf
Compare
|
Thanks @jamesandersen for quick iteration on the PR, it is looking quite good. We had an internal review on this and there are some interesting questions that we identified. We will add those shortly to the PR and we can do another pass. |
|
@amithanda just checking in ... is that round of questions available? As I'm in calls with some early candidates for UCP adoption - lack of visibility to the attribution source of the transaction is recurring theme so I'd love to find an aligned path forward so this can become available to merchants. |
|
|
||
| ## Overview | ||
|
|
||
| The Attribution extension enables referring platforms to pass attribution data |
There was a problem hiding this comment.
Is it expected for UCP to support attribution ?
May be UCP can provide the event_context and let the analytics / conversion tracking system perform the right attribution ?
There was a problem hiding this comment.
Thanks for taking a look @ashutosh-goog. I agree with the framing: UCP should supply context that downstream analytics and attribution systems consume, not perform attribution itself. Renaming this to event_context better reflects that role.
I'll update the PR with the rename from attribution → event_context along with the other changes discussed below.
| influencer link, or an AI agent's suggestion) and completes a purchase via | ||
| agentic checkout, the merchant loses the attribution data they normally receive | ||
| via URL parameters on their landing page. This extension preserves that data. | ||
|
|
There was a problem hiding this comment.
Completely agree on the premise hence the suggestion to supply this information as part of event context rather than as attribution information.
| "ucp": { | ||
| "version": "{{ ucp_version }}", | ||
| "capabilities": { | ||
| "dev.ucp.shopping.attribution": [ |
There was a problem hiding this comment.
Can we rename this event_context.
Consider user journey as follows.
The end user clicks an ad link which opens UCP experience in agent, End user then views the item, adds it to cart, and make purchase.
Advertiser is interested in all the events mentioned above for understanding the user-funnel, building the audience list for remarketing, as well as ads bidding including both lower funnel and upper funnel bidding.
These events can happen in short duration to one another or can be hours apart. In both the cases if UCP starts sending attribution information on all events, then it actually turns into marketing attribution solution.
Another option can be that UCP send event_context information which contains the clicks/utms/referral information and signals what causes this informationt to start.
In the example above only the view_item event would have the click data and rest would not have any additional information. The marketing analytics solution would perform the right attribution to help Advertiser understand what is driving there conversions.
There was a problem hiding this comment.
Yep, aligned with the reframing as per the earlier comment.
One nuance for agentic flows: unlike a traditional web funnel where view_item → add_to_cart → purchase are discrete events hitting the merchant's site, an agent integrated only for checkout has no UCP-level view_item or add_to_cart events at all — the Create Checkout call is the first and potentially only meaningful touchpoint before Complete Checkout. The event context needs to be available on whichever operations the integration actually uses, which is why keeping it optional across cart and checkout makes sense.
The merchant and their analytics stack can then decide how to attribute — UCP just ensures the context isn't lost when the web flow is bypassed. Does that work for you?
|
|
||
| | Field | Type | Required | Description | | ||
| |---------------|--------|----------|------------------------------------------------------------------------------------------------------| | ||
| | `platform` | string | Yes | Referring platform identifier using reverse domain naming (e.g., `com.google`, `com.meta`) | |
There was a problem hiding this comment.
UTM supports the utm_source_platform.
Do you think we could potentially use that and move it to UTM object?
There was a problem hiding this comment.
I'll add utm_source_platform to the UTM object so it's available for analytics tools that consume it.
I'd propose keeping the top-level platform field as well, since it serves a slightly different purpose: platform is the verified source identifier (reverse domain naming, MUST match the agent's UCP profile) that the merchant uses to route custom field values to the right integration. utm_source_platform is an analytics parameter consumed by tools like GA4. They'll often align, but separating them keeps the protocol-level identity distinct from the analytics payload.
Happy to discuss further if you think that's redundant — but my thinking is that the cost of having both is low, and it avoids overloading a marketing parameter with a protocol-identity role.
| **Key features:** | ||
|
|
||
| - Pass structured UTM parameters for compatibility with existing analytics tools | ||
| - Provide deduplication keys so merchants can reconcile agentic transactions |
There was a problem hiding this comment.
Can txn-id for purchase and event-id for non-purchase be used for dedupes ?
There was a problem hiding this comment.
Certainly possible. Among the major conversion funnel reporting tools I was looking at there seemed to be some repeated use of event_id (uniquely identifying discrete events along a purchase journey - add to cart, start checkout, complete checkout) and some concept of sessions.
The transaction id (order.id or possibly even order.name) is a good dedupe candidate - but as you noted kind of a special case that's possible when a purchase is complete. In this case the flow works in the opposite direction e.g. business -> platform (instead of platform -> business for event_id). In the interest of simplicity I didn't include it here but those fields are available via UCP and, if platform and business align, they could also be used.
| | Field | Type | Required | Description | | ||
| |---------------|--------|----------|------------------------------------------------------------------------------------------------------| | ||
| | `platform` | string | Yes | Referring platform identifier using reverse domain naming (e.g., `com.google`, `com.meta`) | | ||
| | `dedup_keys` | object | No | Deduplication keys for reconciling with the merchant's server-side reporting | |
There was a problem hiding this comment.
Is this for event dedupe then does it needs to be part of attribution Jason or may be outside of it ?
There was a problem hiding this comment.
I think your suggested reframing/renaming to event_context helps here 👍 .
The dedup keys are useful event context ... but I think fit better when not framed as attribution data.
1c8b347 to
959b8b3
Compare
|
@amithanda / @ashutosh-goog - Just updated the PR - again thanks for your comments; I'll be on the lookout for any more follow-ups. |
| "event_context": { | ||
| "platform": "com.google", | ||
| "dedup_keys": { | ||
| "session_id": "GA1.2.1234567890.1710300000" |
There was a problem hiding this comment.
sorry for being pedantic. Can we make this event_id for Google traffic as well.
Generally session is the Analytics concept (with configurable options) so UCP events will just have event-id.
There was a problem hiding this comment.
Not pedantic at all — good catch. Updated the Google example to use event_id and simplified the explanatory text.
7b3bef5 to
a5e5dec
Compare
igrigorik
left a comment
There was a problem hiding this comment.
Fresh-eyes: can signals offer a simpler and more robust solution for this problem?
As a thought experiment, consider...
Platforms SHOULD emit, under a reverse-domain key in
signals, the same key-value event and attribution pairs they would encode as URL query parameters on the equivalent browser-based landing flow, enabling businesses to use them with existing analytics integrations.
Example:
"signals": {
"dev.ucp.buyer_ip": "203.0.113.1",
"com.google.event": {
"utm_source": "google", "utm_medium": "cpc", "utm_campaign": "spring_2026",
"utm_id": "18234567890", "gclid": "EAIaIQobChMI...", "gbraid": "WVLA4QjBkaJk...",
"ad_group_id": "142345"
},
"com.meta.event": {
"utm_source": "meta", "utm_medium": "paid_social", "utm_campaign": "spring_sale",
"fbclid": "IwY2xjaw...", "fbc": "fb.1.1710300000000.IwY2xjaw...",
"fbp": "fb.1.1710300000000.1234567890", "event_id": "evt_abc123"
},
...
}Existing attribution systems own the vocabulary, UCP is the pipe. This gives each platform full control over how they model attribution, same as they do on the web today, and most importantly there is 1:1 parity between web (parsed window.location.search) vs. agent-provided attribution. The merchant takes the signals and forwards them verbatim to their existing infrastructure, no remapping, etc.
Why signals is appropriate
- Provenance match — platform-asserted, write-only, observational.
- Covers the full journey — catalog → cart → checkout → order.
- Namespace safety —
propertyNamespreventscom.google.event/com.meta.eventcollisions.
Only adjustment would be to update the description from "authorization and abuse prevention" to include marketing/referral provenance. Beyond that, we can document a best-practice and pattern for how platforms should emit this signal, but we don't need to define a unified schema -- each platform maps its existing attribution signals.
This path also eliminates the need for merchant to advertise support: this is a platform signal, its presence/absence does not change anything about the response or API shape offered by the merchant -- same contract as on the web, these signals are provided by the referrer and consumed at-will by the business.
Enhancement Proposal: Event Context Extension
Summary
An optional
event_contextextension for UCP cart and checkout sessions that enables referring platforms to pass referral context and deduplication keys through agentic checkout flows — preserving the merchant's analytics and ROI measurement capabilities that are otherwise lost when the checkout bypasses the merchant's website.Motivation
When a user discovers a product through any external channel — a paid ad, an organic recommendation, an influencer link, or an AI agent's suggestion — and completes a purchase via an agentic commerce protocol, the merchant loses the referral context they normally receive. In the traditional web flow, this data arrives via URL parameters on the merchant's landing page (e.g.,
utm_source,utm_campaign, platform-specific click IDs like gclid, fbclid, ttclid). With agentic checkout, the user never visits the landing page, so these parameters are never set.This creates two critical problems for merchants:
Merchants lose channel attribution and ROI visibility — Without campaign and channel identifiers flowing through to the conversion event, merchants cannot attribute sales to the channels that drove them. This breaks the analytics pipelines that merchants rely on to measure channel performance, optimize budgets, and evaluate return on spend. Tools like Google Analytics, Northbeam, and Triple Whale all depend on UTM parameters and click IDs arriving with the transaction to build attribution models. When these signals are missing, the merchant's analytics show agentic purchases as "direct" or "unattributed" traffic.
Conversion reporting double-counts transactions — When a purchase completes through an agentic flow, both the referring platform and the merchant's existing server-side integration (e.g., Meta Conversions API, Google Enhanced Conversions, TikTok Events API) may report the same transaction independently. Without a shared deduplication key, the same conversion is counted twice — inflating metrics and corrupting automated bidding data.
This affects every platform that refers users to merchant products through agentic checkout — including Google, Meta, TikTok, Snap, Pinterest, OpenAI/ChatGPT, and others.
Goals
Non-Goals
gclid+order_id, Meta/TikTok useevent_id, etc.)Related Work
Neither #180 nor #185 addresses the use case where the platform that referred a user to a product needs to pass referral context through the checkout flow to the merchant.
Detailed Design
Extension Schema
The extension follows the same composition pattern as
fulfillment.jsonanddiscount.json: defines the extended cart and checkout in$defs["dev.ucp.shopping.cart"]and$defs["dev.ucp.shopping.checkout"]usingallOfto compose ontocart.jsonandcheckout.json, withucp_requestannotations specifying per-operation behavior.Event Context Payload:
platformUCP-Agentprofile URL.dedup_keysutmcustomplatformfield. Values MUST be string, number, or boolean. Maximum 20 properties.Dedup Keys:
event_idsession_idfbp,ga_session_id)UTM Parameters:
utm_source,utm_medium,utm_campaign,utm_content,utm_term,utm_id,utm_source_platformRequest Behavior (Cart):
createoptionalupdateoptionalRequest Behavior (Checkout):
createoptionalupdateoptionalcompleteoptionalUsage Examples
Google (Google Ads / Gemini) — A user discovers a product through a Google Shopping ad and completes the purchase via agentic checkout:
{ "event_context": { "platform": "com.google", "dedup_keys": { "session_id": "GA1.2.1234567890.1710300000" }, "utm": { "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "spring_collection_2026", "utm_content": "60123456789", "utm_id": "18234567890", "utm_source_platform": "Google" }, "custom": { "click_id": "EAIaIQobChMI8bXe7...", "ad_group_id": "142345678901", "placement": "Google_Shopping", "gbraid": "WVLA4QjBkaJkZW..." } } }Google Ads deduplicates conversions using
gclid+order_id+conversion_date_time. Theorder_idis available via UCP's Order capability, so no separateevent_idis required for Google's dedup model.Meta — A user discovers a product through Meta's platform and their AI agent completes the purchase:
{ "event_context": { "platform": "com.meta", "dedup_keys": { "event_id": "evt_abc123def456", "session_id": "fb.1.1710300000000.1234567890" }, "utm": { "utm_source": "meta", "utm_medium": "paid_social", "utm_campaign": "spring_sale_2026", "utm_content": "6861203971771", "utm_id": "6861196821371", "utm_source_platform": "Meta" }, "custom": { "click_id": "IwY2xjawOR56Fle...", "placement": "Meta_AI" } } }The merchant passes
event_idandfbp(fromsession_id) to their Conversions API integration. The sharedevent_idprevents duplicate event counting between the platform's first-party event and the merchant's server-side event.TikTok — A user discovers a product via TikTok and completes the purchase through an agentic flow:
{ "event_context": { "platform": "com.tiktok", "dedup_keys": { "event_id": "evt_tt_xyz789abc012" }, "utm": { "utm_source": "tiktok", "utm_medium": "paid_social", "utm_campaign": "spring_launch_2026", "utm_source_platform": "TikTok" }, "custom": { "click_id": "E.C.P.abcdef123456..." } } }OpenAI (ChatGPT Shopping) — Even without a traditional campaign, the platform provides event context:
{ "event_context": { "platform": "com.openai", "dedup_keys": { "event_id": "evt_oai_def456ghi789" }, "utm": { "utm_source": "chatgpt", "utm_medium": "agentic", "utm_campaign": "shopping_recommendations" } } }Design Rationale
allOfcomposition ontocart.jsonandcheckout.jsonwithucp_requestannotations, matchingfulfillment.jsonanddiscount.json. Capability declarations (platform_schema,business_schema) follow the same pattern asfulfillment.json.signals— UCP'ssignalsproperty carries environment data for authorization and abuse prevention. Event context serves a different purpose: referral and marketing analytics context. Mixing them would conflate security/risk data with marketing data.dedup_keysobject accommodates all models with optional fields, and different analytics platforms (GA4, Adobe, Northbeam, Meta CAPI, etc.) handle dedup differently.platformvalue MUST correspond to the domain of the platform'sUCP-Agentprofile URL, linking identity to protocol identity without coupling to UCP-specific constructs.custom, keeping the core schema minimal and universal. Values constrained to string, number, or boolean with a maximum of 20 properties.Risks and Mitigations
custom.dedup_keysfields are all optional. Each platform populates only the fields relevant to its dedup model.Test Plan
event_context, verify it persists through update and complete operationsevent_contextis omitted entirely (optional extension)platformfield and route to correct analytics integrationGraduation Criteria
Code Changes
New Files:
source/schemas/shopping/event_context.json— Extension schema with$defscontainingevent_context_payload,dev.ucp.shopping.cart, anddev.ucp.shopping.checkoutcompositiondocs/specification/event-context.md— Extension documentationModified Files:
mkdocs.yml— Added event context extension to nav and llmstxt sections.cspell/custom-words.txt— Added related termsNote: No modifications to
checkout.jsonorcart.jsonare required. UCP extensions compose onto cart and checkout viaallOfin the extension schema (same pattern asfulfillment.json,discount.json).References
checkout.json— Base checkout schema (extended viaallOf)cart.json— Base cart schema (extended viaallOf)Type of change
Checklist