Event Triggering Guide
This guide explains when to trigger each event type and what data to retain from the Recommendations API for proper attribution tracking across the customer journey.
Overview
The event system tracks the complete customer journey from recommendation display through purchase. Each event builds upon the previous ones, creating a complete attribution chain that enables accurate analytics and reporting.
Event Flow Sequence
The customer journey can follow different paths depending on user interactions:
Common Flow Patterns:
Pattern 1: Product Detail View
Recommendations API → Slot Impressions → Click (on product) → View Products → Add to Cart → Checkout → Purchase
Pattern 2: Direct Add to Cart
Recommendations API → Slot Impressions → Click (on add to cart button) → Add to Cart → Checkout → Purchase
Pattern 3: Direct Purchase
Recommendations API → Slot Impressions → Click (on buy now button) → Purchase
Pattern 4: View Without Click
Recommendations API → Slot Impressions → View Products (direct navigation) → Add to Cart → Checkout → Purchase
1. Recommendations API Call
Reference: Recommendations API
When to trigger: When displaying product recommendations to a customer
Data to retain: Store all slot-level attribution data with customer ID for long-term persistence
The data structure below shows the final stored data after both recommendations are received AND user clicks. The fields come from different sources:
- From Recommendations API (stored when recommendations are received)
- From Click Event (added when user clicks)
- Storage Metadata (added by implementation)
Data Structure to Store:
// FINAL STORED DATA STRUCTURE (after recommendations + clicks)
{
customerId: "xxxxxxxxxxxxxxxxxxxxxxx",
productRecommendations: {
[productRefId]: {
// Sponsored slot data (with click data added later)
sponsored: {
// === FROM RECOMMENDATIONS API ===
routeId: "xxxxxxxxxxxxxxxxxxxxxxx",
widgetId: "xxxxxxxxxxxxxxxxxxxxxxx",
recommenderId: "xxxxxxxxxxxxxxxxxxxxxxx",
campaignId: "xxxxxxxxxxxxxxxxxxxxxxx",
tacticId: "xxxxxxxxxxxxxxxxxxxxxxx",
tacticLabel: "Featured Products",
placementId: "xxxxxxxxxxxxxxxxxxxxxxx",
bannerId: "xxxxxxxxxxxxxxxxxxxxxxx",
adSetId: "xxxxxxxxxxxxxxxxxxxxxxx",
adSetVersion: 1,
costPerClick: 0.5,
costPerAction: 1.0,
costPerMille: 0.25,
timeStamp: 638481477292391000,
hmacSalt: "xxxxxxxxxxxxxxxxxxxxxxx",
hmac: "xxxxxxxxxxxxxxxxxxxxxxx",
supplierId: "xxxxxxxxxxxxxxxxxxxxxxx",
retailBoostCollectionCampaignId: "xxxxxxxxxxxxxxxxxxxxxxx",
// === FROM CLICK EVENT (added when user clicks) ===
clickId: "xxxxxxxxxxxxxxxxxxxxxxx",
eventTime: "2024-03-01T14:00:00.000Z",
currentUrl: "https://www.example.com/products",
actionType: 1,
contextType: 1,
redirectUrl: "https://www.example.com/product/detail",
referralUrl: "https://www.example.com/category",
clickPosition: 3
},
// Organic slot data (with click data added later)
organic: {
// === FROM RECOMMENDATIONS API ===
routeId: "xxxxxxxxxxxxxxxxxxxxxxx",
widgetId: "xxxxxxxxxxxxxxxxxxxxxxx",
recommenderId: "xxxxxxxxxxxxxxxxxxxxxxx",
campaignId: "xxxxxxxxxxxxxxxxxxxxxxx",
tacticId: "xxxxxxxxxxxxxxxxxxxxxxx",
tacticLabel: "Featured Products"
// Note: No placementId, bannerId, adSetId or other Retail Media fields for organic slots
// === FROM CLICK EVENT (added when user clicks) ===
clickId: "xxxxxxxxxxxxxxxxxxxxxxx",
eventTime: "2024-03-05T14:00:00.000Z",
currentUrl: "https://www.example.com/products",
actionType: 1,
contextType: 1,
redirectUrl: "https://www.example.com/product/detail",
referralUrl: "https://www.example.com/category",
clickPosition: 3
},
// === STORAGE METADATA ===
recommendationTime: "2024-03-01T14:00:00.000Z",
lastUpdated: "2024-03-05T14:00:00.000Z"
}
}
}
Storage Requirements:
- Persistent storage by customer ID (not session-dependent)
- Product-level association - each product recommendation stored separately
- Separate sponsored and organic click storage - maintain both click types
- Sponsored-first usage - when both sponsored and organic attribution exist, prefer sponsored and fall back to organic if needed
- Long-term retention - keep data for attribution window (e.g., 30-90 days)
- Attribution limit cleanup - remove stored attribution data once it falls outside the attribution window
- Post-purchase cleanup - delete the specific attribution data (organic or sponsored) used in a Purchase event
- Independent click tracking - sponsored and organic clicks don't overwrite each other
2. Slot Impressions Event
Reference: Slot Impressions Event API
When to trigger: When a recommendation slot is displayed to a customer
Required data:
- Customer ID and session ID
- Current URL where slot is displayed
- Current slot's attribution data (from the recommendations API response for this specific slot)
- Product information for each product in the slot
Use the current slot's data, not stored data. Multiple slots across different pages can display the same product, so you need the attribution data specific to the slot being displayed.
Key fields (from current slot's Recommendations API response):
routeId
,widgetId
,recommenderId
,campaignId
,tacticId
,tacticLabel
,placementId
,bannerId
- Retail Media fields (for sponsored content):
adSetId
,adSetVersion
,costPerClick
,costPerAction
,costPerMille
,timeStamp
,hmacSalt
,hmac
,supplierId
retailBoostCollectionCampaignId
(for retailer boost)
3. Click Event
Reference: Click Event API
When to trigger: When a customer clicks on a recommended product or banner
Required data:
- Customer ID and session ID
- Generated
clickId
(client-side unique identifier) - Product
refId
that was clicked - Current slot's attribution data (from the recommendations API response for this specific slot)
- Action type and context type
Use the current slot's data for the Click event, not stored data. The stored data is used later for Add to Cart, Checkout, and Purchase events.
Critical requirements:
clickId
is mandatory and must be generated client-side as a GUID during the Click event- Store
clickId
in appropriate slot (sponsored or organic) for later events - Separate storage for sponsored and organic clicks
- Both sponsored and organic clicks contribute to attribution (sponsored attribution vs. organic attribution)
Route and Widget ID Requirements:
- General Rule: Both
routeId
andwidgetId
are REQUIRED for click events - Exception: Route and Widget IDs are NOT required when ALL conditions are met:
contextType = NativeButton
(ContextTypes.NativeButton = 11)- AND
actionType
is one of:ClickBuyNow
(ActionTypes.ClickBuyNow = 10)ClickExternalBuyNow
(ActionTypes.ClickExternalBuyNow = 11)AddProductToWishlist
(ActionTypes.AddProductToWishlist = 9)
Always Required Fields:
clickId
,actionType
,contextType
,currentUrl
,customerId
,sessionId
Valid click types for attribution:
- Sponsored clicks: Must have
adSetId
populated (for sponsored attribution) - Organic clicks: Must have valid
routeId
andwidgetId
(for organic attribution) - Native button clicks: Not attributed (not from recommendation slots)
4. View Products Event
Reference: View Products Event API
When to trigger: When a customer views a product page
Required data:
- Customer ID and session ID
- Product
refId
being viewed - Current URL of the product page
Attribution data (if available):
routeId
,widgetId
,recommenderId
,campaignId
,tacticId
referralUrl
(if applicable)bannerId
(if applicable)
Data Source:
- Use current slot's data if the user navigated from a recommendation slot
- Send without attribution if the view was not initiated from a slot
View Products events should be sent for ALL product views, regardless of attribution. This provides complete analytics on product view counts. Attribution data is included when available, but the event is still sent even without attribution.
5. Add to Cart Event
Reference: Add to Cart Event API
When to trigger: When a customer adds a product to their shopping cart
Required data:
- Customer ID and session ID
- Product information (
refId
,quantity
,price
) - Attribution data (source depends on context)
Data Source:
- From slot: Use current slot's data for the Click event, then use that Click event's data for Add to Cart
- From elsewhere (product page, etc.): Generate Click event with native button context, then use that Click event's data for Add to Cart
Critical requirements:
- Always generate Click event first before Add to Cart (regardless of source)
- From slot: Click event uses current slot's data (routeId, widgetId, etc.) and gets stored
- From elsewhere: Click event uses native button context (contextType: NativeButton, actionType: AddProductToCart) but does NOT get stored
- Add to Cart uses the Click event's data (including the generated clickId)
- Store both sponsored and organic clicks (both contribute to attribution) - native button clicks are not stored
Event Flow Scenarios:
Slot-Based Interactions (from Recommendation Widgets)
Scenario A: Click → View Products → Add to Cart
- First: Trigger Click event when user clicks on product in slot (generate
clickId
) - Use current slot's data for the Click event (routeId, widgetId, etc.)
- Store:
clickId
in sponsored/organic data slot - Then: Trigger View Products event when user views product page (use current slot's data)
- Finally: Trigger Add to Cart event when user adds product to cart (use stored data)
Scenario B: Direct Add to Cart from Slot
- First: Trigger Click event when user clicks "Add to Cart" button in slot (generate
clickId
) - Use current slot's data for the Click event (routeId, widgetId, etc.)
- Then: Trigger Add to Cart event using the Click event's data (including
clickId
) - Store: Attribution data for potential future use
Native Button Interactions (not from Recommendation Widgets)
Scenario C: Add to Cart from Product Page
- First: Trigger Click event when user clicks "Add to Cart" button on product page (generate
clickId
) - Use native button context for the Click event (contextType: NativeButton, actionType: AddProductToCart)
- Then: Trigger Add to Cart event using the Click event's data (including
clickId
) - Note: No routeId/widgetId needed for native button clicks
- Important: This Click event is NOT stored (native button clicks are not from recommendations)
Scenario D: View Products without Click
- First: Trigger View Products event (direct navigation) - with or without attribution
- Then: Trigger Add to Cart event when user adds product to cart
- Note: No
clickId
available - Add to Cart will fail validation - Important: For this scenario, you would look for stored attribution data from previous interactions with this product
6. Checkout Event
Reference: Checkout Event API
When to trigger: When a customer initiates checkout process
Required data:
- Customer ID and session ID
- Checkout details (prices, currency, delivery info)
- Product array with attribution data
- Optional
clickId
for attribution tracking
Attribution data per product:
- Include stored recommendation data for each product
- Prefer sponsored attribution; use organic data only when sponsored is unavailable
routeId
,widgetId
,recommenderId
,campaignId
,tacticId
- Retail Media fields if applicable (from sponsored click)
- Retailer Boost fields if applicable (from sponsored click)
7. Purchase Event
Reference: Purchase Event API
When to trigger: When a customer completes a purchase
Required data:
- Customer ID and session ID
- Order details (
orderId
, payment method, currency) - Product array with attribution data
- Optional
clickId
for attribution tracking
Attribution data per product:
- Include stored recommendation data for each product
- Prefer sponsored attribution; use organic data only when sponsored is unavailable
- All Retail Media fields (if applicable, from sponsored click)
- All Retailer Boost fields (if applicable, from sponsored click)
After submitting the Purchase event, remove the stored attribution data that was used (organic or sponsored) for the purchased products to prevent reuse beyond the attribution window.
Implementation Best Practices
1. Data Storage Strategy
Frontend Storage Options:
- Local Storage: Persistent across browser sessions
- Cookies: Can be set with expiration dates
Storage Key Structure:
// Recommended key format
const storageKey = `pa_recommendation_${customerId}_${productRefId}`;
// Store recommendation data persistently
function storeRecommendationData(customerId, productRefId, data) {
// For frontend implementation
const key = `pa_recommendation_${customerId}_${productRefId}`;
localStorage.setItem(key, JSON.stringify({
...data,
lastUpdated: new Date().toISOString()
}));
// For backend implementation
// Store in database with customerId + productRefId as key
}
// Retrieve stored data for events
function getStoredRecommendationData(customerId, productRefId) {
// For frontend implementation
const key = `pa_recommendation_${customerId}_${productRefId}`;
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : null;
// For backend implementation
// Retrieve from database
}
2. Click ID Management
The clickId
must be generated as a GUID format during the Click event. It is only stored for recommendation-based clicks (sponsored/organic) for later use in follow-up events. Native button clicks are not stored.
// Generate click ID when user clicks
function handleProductClick(productRefId, clickData) {
const clickId = generateGUID(); // Must be a GUID format
// Get existing stored data or create new
let storedData = getStoredRecommendationData(customerId, productRefId);
if (!storedData) {
storedData = {
refId: productRefId,
sponsored: null,
organic: null,
recommendationTime: new Date().toISOString()
};
}
// Determine if this is a sponsored or organic click
const isSponsored = clickData.adSetId && clickData.adSetId.length > 0;
// Store click data in appropriate slot (including the generated clickId)
// Only store recommendation-based clicks (sponsored/organic), not native button clicks
if (isSponsored) {
storedData.sponsored = {
clickId: clickId, // Store the generated clickId for later use
eventTime: new Date().toISOString(),
...clickData
};
} else if (clickData.routeId && clickData.widgetId) { // Only store organic clicks from recommendations
storedData.organic = {
clickId: clickId, // Store the generated clickId for later use
eventTime: new Date().toISOString(),
...clickData
};
}
// Native button clicks (contextType: NativeButton) are not stored
storedData.lastUpdated = new Date().toISOString();
storeRecommendationData(customerId, productRefId, storedData);
// Send click event
sendClickEvent({
clickId: clickId,
refId: productRefId,
...clickData
});
// Handle different click actions
if (clickData.actionType === 2) { // AddProductToCart
// Trigger Add to Cart event immediately
sendAddToCartEvent(productRefId, 1, clickData.price);
} else if (clickData.actionType === 10) { // ClickBuyNow
// Trigger Purchase event immediately
sendPurchaseEvent(productRefId, 1, clickData.price);
}
// For other action types (like OpenProductPage), let the user navigate naturally
}
3. Event Attribution
// Get the most recent valid click data for attribution
function getAttributionData(customerId, productRefId) {
const storedData = getStoredRecommendationData(customerId, productRefId);
if (!storedData) {
return null;
}
// Check if we have sponsored click data
if (storedData.sponsored && storedData.sponsored.clickId) {
return storedData.sponsored;
}
// Check if we have organic click data
if (storedData.organic && storedData.organic.clickId) {
return storedData.organic;
}
return null;
}
// Handle View Products event with optional attribution
function handleProductPageView(productRefId) {
const attributionData = getAttributionData(customerId, productRefId);
const eventData = {
refId: productRefId,
currentUrl: window.location.href,
eventTime: new Date().toISOString()
};
// Add attribution data if available (from Recommendations API)
if (attributionData) {
Object.assign(eventData, {
routeId: attributionData.routeId,
widgetId: attributionData.widgetId,
recommenderId: attributionData.recommenderId,
campaignId: attributionData.campaignId,
tacticId: attributionData.tacticId,
tacticLabel: attributionData.tacticLabel,
placementId: attributionData.placementId,
bannerId: attributionData.bannerId,
referralUrl: attributionData.referralUrl
});
}
// Always send View Products event, with or without attribution
sendViewProductsEvent(eventData);
}
// Use stored data for follow-up events
function sendAddToCartEvent(productRefId, quantity, price) {
const attributionData = getAttributionData(customerId, productRefId);
if (!attributionData || !attributionData.clickId) {
throw new Error('No click ID found - must have click event first');
}
const eventData = {
clickId: attributionData.clickId,
product: { refId: productRefId, quantity, price },
// Include all attribution fields (from Recommendations API)
routeId: attributionData.routeId,
widgetId: attributionData.widgetId,
recommenderId: attributionData.recommenderId,
campaignId: attributionData.campaignId,
tacticId: attributionData.tacticId,
tacticLabel: attributionData.tacticLabel,
placementId: attributionData.placementId,
bannerId: attributionData.bannerId
};
// Add Retail Media fields if this was a sponsored click
if (attributionData.adSetId) {
Object.assign(eventData, {
adSetId: attributionData.adSetId,
adSetVersion: attributionData.adSetVersion,
costPerClick: attributionData.costPerClick,
costPerAction: attributionData.costPerAction,
costPerMille: attributionData.costPerMille,
timeStamp: attributionData.timeStamp,
hmacSalt: attributionData.hmacSalt,
hmac: attributionData.hmac,
supplierId: attributionData.supplierId
});
}
// Add Retailer Boost fields if applicable
if (attributionData.retailBoostCollectionCampaignId) {
eventData.retailBoostCollectionCampaignId = attributionData.retailBoostCollectionCampaignId;
}
sendAddToCartEvent(eventData);
}
Common Pitfalls
1. Missing Click Events
- Problem: Trying to send Add to Cart without Click event
- Solution: Always generate click event first, store clickId (for both sponsored and organic recommendation clicks)
2. Session-Dependent Storage
- Problem: Storing recommendation data only for current session
- Solution: Use persistent storage by customer ID (localStorage or cookies)
3. Missing Attribution Fields
- Problem: Not including all required attribution fields
- Solution: Store and include all fields from recommendations API
4. Organic vs Sponsored Clicks
- Problem: Not understanding that both organic and sponsored clicks contribute to attribution
- Solution: Both organic and sponsored clicks contribute to attribution (different types of attribution)
5. Separate Sponsored and Organic Storage
- Problem: Overwriting sponsored clicks with organic clicks or vice versa
- Solution: Store sponsored and organic clicks in separate slots
- Benefit: Preserves both click types for proper attribution
Summary
- Store recommendation data persistently by customer ID using localStorage or cookies
- Always generate Click events before Add to Cart events (two-step process)
- Include all attribution fields in follow-up events (including all Retail Media fields)
- Both sponsored and organic clicks contribute to attribution (different types)
- Store sponsored and organic clicks separately - maintain both click types independently
- Use appropriate click data for attribution based on click type
- Send View Products events for ALL product views - with attribution when available, without attribution when not
- Maintain data consistency across all events in the customer journey
This ensures accurate attribution tracking and enables proper analytics and reporting for your recommendation campaigns.
Data Source Summary
For each event, use the appropriate data source:
Event | Data Source | When |
---|---|---|
Slot Impressions | Current slot's data | Always use the current slot's Recommendations API response |
Click Event | Current slot's data | Always use the current slot's Recommendations API response |
View Products | Current slot's data OR No attribution | Use current slot if navigating from slot, no attribution if not from slot |
Add to Cart | Click event data | Always generate Click event first, then use Click event's data for Add to Cart |
Checkout | Stored data | Always use stored attribution data |
Purchase | Stored data | Always use stored attribution data |