feat: add attribution extension for checkout sessions#295
feat: add attribution extension for checkout sessions#295jamesandersen wants to merge 2 commits intoUniversal-Commerce-Protocol:mainfrom
Conversation
Enable referring platforms to pass attribution data (UTM parameters, deduplication keys, platform-specific identifiers) through agentic checkout flows. Preserves merchant analytics and ROI measurement capabilities that are otherwise lost when checkout bypasses the merchant's website.
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?
| "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.
| "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.
…d privacy note - Extend attribution to Cart in addition to Checkout (following discount pattern) - Add minProperties: 1 on dedup_keys to prevent empty objects - Constrain custom values to string/number/boolean with maxProperties: 20 - Strengthen platform field from SHOULD to MUST match agent profile URL - Add Privacy Note section to docs
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. |
Enhancement Proposal: Attribution Extension
Summary
An optional
attributionextension for UCP checkout sessions that enables referring platforms to pass attribution data 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 attribution data 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 attribution data 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 checkout in$defs["dev.ucp.shopping.checkout"]usingallOfto compose ontocheckout.json, withucp_requestannotations specifying per-operation behavior.Attribution Payload:
platformUCP-Agentprofile URL.dedup_keysutmcustomplatformfieldDedup Keys:
event_idsession_idfbp,ga_session_id)UTM Parameters:
utm_source,utm_medium,utm_campaign,utm_content,utm_term,utm_idRequest Behavior:
createoptionalupdateoptionalcompleteoptionalUsage Examples
Google (Google Ads / Gemini) — A user discovers a product through a Google Shopping ad and completes the purchase via agentic checkout:
{ "attribution": { "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" }, "custom": { "click_id": "EAIaIQobChMI8bXe7...", "ad_group_id": "142345678901", "placement": "Google_Shopping", "gbraid": "WVLA4QjBkaJkZW..." } } }Meta — A user discovers a product through Meta's platform and their AI agent completes the purchase:
{ "attribution": { "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" }, "custom": { "click_id": "IwY2xjawOR56Fle...", "placement": "Meta_AI" } } }TikTok — A user discovers a product via TikTok and completes the purchase through an agentic flow:
{ "attribution": { "platform": "com.tiktok", "dedup_keys": { "event_id": "evt_tt_xyz789abc012" }, "utm": { "utm_source": "tiktok", "utm_medium": "paid_social", "utm_campaign": "spring_launch_2026" }, "custom": { "click_id": "E.C.P.abcdef123456..." } } }OpenAI (ChatGPT Shopping) — Even without a traditional campaign, the platform provides attribution context:
{ "attribution": { "platform": "com.openai", "dedup_keys": { "event_id": "evt_oai_def456ghi789" }, "utm": { "utm_source": "chatgpt", "utm_medium": "agentic", "utm_campaign": "shopping_recommendations" } } }Design Rationale
allOfcomposition ontocheckout.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. Attribution serves a different purpose: marketing analytics context. Mixing them would conflate security/risk data with marketing data.dedup_keysobject accommodates all models with optional fields.platformvalue SHOULD correspond to the domain of the platform'sUCP-Agentprofile URL, linking attribution identity to protocol identity without coupling to UCP-specific constructs.custom, keeping the core schema minimal and universal.Risks and Mitigations
custom.dedup_keysfields are all optional. Each platform populates only the fields relevant to its dedup model.Test Plan
attribution, verify it persists through update and complete operationsattributionis omitted entirely (optional extension)platformfield and route to correct analytics integrationGraduation Criteria
Code Changes
New Files:
source/schemas/shopping/attribution.json— Extension schema with$defscontainingattribution_payloadanddev.ucp.shopping.checkoutcompositiondocs/specification/attribution.md— Extension documentationModified Files:
mkdocs.yml— Added attribution extension to nav and llmstxt sections.cspell/custom-words.txt— Added attribution-related termsNote: No modifications to
checkout.jsonare required. UCP extensions compose onto checkout viaallOfin the extension schema (same pattern asfulfillment.json,discount.json).Discussion Points
customfield constraints: The current schema definescustomas an open object (additionalProperties: true) with no constraints on value types or size. The ACP Affiliate Attribution RFC applies constraints to its equivalentmetadatafield: keys MUST be strings; values MUST be strings, numbers, or booleans; arrays and nested objects are NOT permitted; implementations MAY enforce limits (e.g., ≤ 20 keys, ≤ 4KB total). Adopting similar constraints would provide cross-protocol consistency.References
checkout.json— Base checkout schema (extended viaallOf)Type of change
Checklist