Skip to main content

Product events

Product Events are a specialized class of contact interactions designed specifically for E-commerce and Catalog-based applications. They allow you to track the lifecycle of a product—from a "View" to an "Add to Cart"—to power recommendation engines and abandoned cart automations.

Introduction​

Unlike standard events which are static logs of behavior, Product Events serve a dual purpose:

  1. Event Logging: They record that a specific action occurred (e.g., "Contact X viewed Product Y").

  2. Product Indexing: They update the global profile of the product in your Positive User database.

Method signature​

To track these interactions, you use the standard userengage function with a reserved keyword.

userengage('product_event', productObject)
  • keyword (String): Must be strictly 'product_event'.
  • productObject (Object): A dictionary containing the product_id, event_type, and product attributes.

Capabilities & scope​

The "Product Profile" logic (Critical)​

It is vital to understand that Product Events overwrite product details.

  • Behavior: Every time you send a product_event, the system updates that product's global attributes (Name, Image URL, Category) with the latest values provided.
  • Consequence: You cannot store historical state in product attributes.
    • Example: If a contact adds a generic "T-Shirt" to the cart today for $20, and you change the name to "Vintage T-Shirt" and price to $30 tomorrow, the contact's past event history will reflect the current name and price ($30), not the value at the time of the event.

Warning: Do not use Product Attributes to track fixed transaction data (like transaction_value). Use Orders (Backend), Custom Event or custom_data for immutable records.

Supported event types​

The event_type field is strictly typed. You must use one of the following specific strings. Custom strings are not supported in this field.

Event TypeTypical Use Case
viewContact loads a product detail page (PDP).
add to cartContact adds an item to their basket.
removeContact removes an item from their basket.
purchase(SDK Not Recommended) Essential for recommendations, but best sent via Backend (Orders) to ensure data integrity.
likingContact "hearts" or likes an item.
add to observationContact adds item to a wishlist/watchlist.
clickContact clicks a product card on a listing page.
detailViewing specific technical details.
promo clickClicking a banner promoting the product.
return, refundPost-purchase logic.
checkout, checkout optionSteps within the funnel.

Implementation​

Required fields​

Every product event must include these two keys.

  1. product_id (String/Number): The unique identifier from your database (e.g., SKU or ID).
  2. event_type (String): One of the specific strings listed above.

Scenario 1: Single product view​

Use this on your Product Detail Page (PDP).

Best Practice: We generally do not recommend passing full product details (like Name, Price, or Description) from the frontend. Since these values update the global Product Profile, inconsistent data from different contacts/browsers can overwrite your catalog with incorrect values. Ideally, you should only pass the product_id, and let your backend integration or XML Product Feed handle the product data synchronization.

However, if you do need to update a product's details on the fly, you can include attributes like name or image_url alongside the ID.

// Recommended: Pass only ID and Type
userengage('product_event', {
product_id: 'SKU-12345',
event_type: 'view'
});

Scenario 2: Handling multiple items (The Cart Loop)​

The SDK does not support passing an array of products in a single call. If a contact performs an action on multiple items (e.g., "Checkout" or adding a bundle), you must iterate through them.

const cartItems = [
{ id: '101', price: 12.00 },
{ id: '205', price: 85.00 }
];

// CORRECT: Loop and fire individually
cartItems.forEach(item => {
userengage('product_event', {
product_id: item.id,
event_type: 'add to cart',
// Optional: Custom Data for context (see below)
custom_data: {
cart_session_id: 'sess_998877'
}
});
});

Scenario 3: Using custom_data for context​

Since product attributes can be overwritten, use the custom_data object to store permanent facts about the specific event.

  • Use Case: Recording the specific price at that moment or a coupon code used.
userengage('product_event', {
product_id: 'SKU-999',
event_type: 'add to cart',

// Permanent Event Data (Stored only with this specific event)
custom_data: {
price_at_moment: 150.00, // Safe historical record
discount_applied: 'WINTER_SALE_20',
size_selected: 'XL',
variant_id: 'v_999_XL' // Distinct from parent product_id
}
});

Verification​

To verify your Product Events are firing correctly:

  1. Network Tab: Open the developer tools and filter for requests containing /api/product_event/.
    • Status: 200 OK indicates the event was successfully sent.
    • Payload: Verify the JSON payload contains your product_id and event_type.
  2. Contact Timeline: Go to the specific contact's timeline in your workspace.
    • Success: You should see a timeline entry: "Product event occurrence".
    • Note: If the timeline shows the event but the product details (name, image) are missing, ensure the product_id matches a product already imported into your catalog. The recommended method for importing products is via the XML Product Feed (Settings > Workspace Settings > Products > Product feeds).