E-Commerce Tracking
The Joryio SDKs include built-in e-commerce tracking for product engagement, cart activity, and purchase transactions. The tracker works the same way across every platform: the same methods, the same standard event names, and the same property semantics - only the language syntax differs.
Pick your platform in any code example below; the choice syncs across the whole page. For installation and configuration, see the platform guides: Web SDK, iOS SDK, Android SDK, React Native SDK. Unity games use the iOS and Android SDKs underneath; see the Unity SDK guide.
ID Naming Convention
Joryio uses a clear naming convention for identifiers:
| Your ID | Description | Example |
|---|---|---|
productId | Your product identifier (SKU, product ID from your e-commerce platform) | "SKU-12345" |
orderId | Your order identifier (order number from your platform) | "ORD-2024-001" |
userId | Your user identifier (passed to identify()) | "user-123" |
Use your own identifiers naturally - no special prefixes needed.
Initialize the E-Commerce Tracker
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Get the e-commerce tracker from your SDK instance
// (joryio is the instance created with `new JoryioSDK({ sdkKey: ... })`)
const ecommerce = joryio.ecommerce({
currency: 'USD' // Default currency for all events
});
// Get the e-commerce tracker with default currency
let ecommerce = Joryio.shared.ecommerce(config: EcommerceConfig(currency: "USD"))
import io.joryio.sdk.ecommerce.*
// Get the e-commerce tracker with default currency
val ecommerce = Joryio.getInstance().ecommerce(EcommerceConfig(currency = "USD"))
// The React Native SDK has a typed e-commerce tracker, same as web, iOS and
// Android. Use it rather than Joryio.track() with hand-written names: it
// applies the platform's canonical event names and property keys for you, and
// a name that is close but not exact is stored verbatim and matches no report.
import Joryio from '@joryio/react-native-sdk';
const product = {
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99,
category: 'Clothing/T-Shirts',
brand: 'Acme Apparel',
imageUrl: 'https://example.com/images/blue-tshirt.jpg',
url: 'https://example.com/products/blue-tshirt',
};
Track Product Views & Search
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// When user views a product page
ecommerce.viewProduct({
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99,
category: 'Clothing/T-Shirts',
brand: 'Acme Apparel',
imageUrl: 'https://example.com/images/blue-tshirt.jpg',
url: 'https://example.com/products/blue-tshirt'
});
// When user views a category page
ecommerce.viewCategory('tshirts', 'T-Shirts');
// When user searches
ecommerce.search('blue shirts', 42); // query, result count
// Track product view
let product = EcommerceProduct(
productId: "SKU-12345",
name: "Classic Blue T-Shirt",
price: 29.99,
category: "Clothing",
brand: "Acme Apparel",
variant: "Size M",
sku: "BTS-001-M"
)
ecommerce.viewProduct(product)
// Track category view
ecommerce.viewCategory(categoryId: "cat_123", categoryName: "T-Shirts", properties: [
"sort_by": "popularity"
])
// Track product search
ecommerce.search(query: "blue shirts", resultCount: 42)
// Track product view
val product = EcommerceProduct(
productId = "SKU-12345",
name = "Classic Blue T-Shirt",
price = 29.99,
category = "Clothing",
brand = "Acme Apparel",
variant = "Size M",
sku = "BTS-001-M"
)
ecommerce.viewProduct(product)
// Track category view
ecommerce.viewCategory(
categoryId = "cat_123",
categoryName = "T-Shirts",
properties = mapOf("sort_by" to "popularity")
)
// Track product search
ecommerce.search(query = "blue shirts", resultCount = 42)
// When user views a product page
Joryio.ecommerce.viewProduct(product);
// When user views a category page
Joryio.ecommerce.viewCategory('tshirts', 'T-Shirts');
// When user searches
Joryio.ecommerce.search('blue shirts', 42);
Track Cart Activity
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Add item to cart
ecommerce.addToCart({
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99,
quantity: 1,
variantId: 'var-medium',
sku: 'BTS-001-M'
}, 59.98); // Optional: current cart value
// Remove item from cart
ecommerce.removeFromCart({
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99
}, 1); // quantity to remove
// Update entire cart
ecommerce.updateCart([
{ productId: 'SKU-12345', name: 'Blue T-Shirt', price: 29.99, quantity: 2 },
{ productId: 'SKU-67890', name: 'Black Jeans', price: 49.99, quantity: 1 }
], 109.97); // items array, total cart value
// Add item to cart
let cartItem = EcommerceCartItem(
productId: "SKU-12345",
name: "Classic Blue T-Shirt",
price: 29.99,
quantity: 2,
category: "Clothing"
)
ecommerce.addToCart(item: cartItem, cartValue: 59.98)
// Remove from cart
ecommerce.removeFromCart(product: product, quantity: 1)
// Update cart
ecommerce.updateCart(items: [cartItem1, cartItem2], cartValue: 89.97)
// Add item to cart
val cartItem = EcommerceCartItem(
productId = "SKU-12345",
name = "Classic Blue T-Shirt",
price = 29.99,
quantity = 2,
category = "Clothing"
)
ecommerce.addToCart(item = cartItem, cartValue = 59.98)
// Remove from cart
ecommerce.removeFromCart(product = product, quantity = 1)
// Update cart
ecommerce.updateCart(items = listOf(cartItem1, cartItem2), cartValue = 89.97)
// Add item to cart
Joryio.ecommerce.addToCart({...product, quantity: 2}, 59.98);
// Remove item from cart
Joryio.ecommerce.removeFromCart(product, 1);
// Cart contents changed
Joryio.ecommerce.updateCart([{...product, quantity: 2}], 59.98);
Track Checkout Flow
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// When user starts checkout
ecommerce.startCheckout([
{ productId: 'SKU-12345', name: 'Blue T-Shirt', price: 29.99, quantity: 2 },
{ productId: 'SKU-67890', name: 'Black Jeans', price: 49.99, quantity: 1 }
], 109.97); // items, cart value
// When user adds payment info
ecommerce.addPaymentInfo('credit_card');
// Start checkout
ecommerce.startCheckout(items: cartItems, cartValue: 59.98)
// Add payment info
ecommerce.addPaymentInfo(paymentMethod: "credit_card", properties: [
"card_type": "visa"
])
// Start checkout
ecommerce.startCheckout(items = cartItems, cartValue = 59.98)
// Add payment info
ecommerce.addPaymentInfo(paymentMethod = "credit_card", properties = mapOf(
"card_type" to "visa"
))
// When user starts checkout
Joryio.ecommerce.startCheckout([{...product, quantity: 2}], 65.97);
// When payment details are entered
Joryio.ecommerce.addPaymentInfo('credit_card');
Track Purchases
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// When order is completed
ecommerce.purchase({
orderId: 'ORD-2024-001',
items: [
{
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99,
quantity: 2,
category: 'Clothing',
brand: 'Acme'
},
{
productId: 'SKU-67890',
name: 'Black Jeans',
price: 49.99,
quantity: 1
}
],
value: 109.97,
currency: 'USD',
shipping: 5.99,
tax: 8.80,
discount: 10.00,
coupon: 'SAVE10'
});
// Complete purchase
let order = EcommerceOrder(
orderId: "ORD-2024-001",
items: cartItems,
value: 59.98,
currency: "USD",
shipping: 5.99,
tax: 4.80,
discount: 10.00,
coupon: "SAVE10"
)
ecommerce.purchase(order: order)
// Complete purchase
val order = EcommerceOrder(
orderId = "ORD-2024-001",
items = cartItems,
value = 59.98,
currency = "USD",
shipping = 5.99,
tax = 4.80,
discount = 10.00,
coupon = "SAVE10"
)
ecommerce.purchase(order)
// When order is completed.
//
// `value` here is the ORDER OBJECT's field name; the tracker sends it as the
// `total` property the revenue pipeline reads. Sending a raw event with
// `value` instead would record the order at $0 - there is deliberately no
// alias layer, so a near-miss is stored verbatim and read by nothing.
Joryio.ecommerce.purchase({
orderId: 'ORD-2024-001',
items: [
{productId: 'SKU-12345', name: 'Classic Blue T-Shirt', price: 29.99, quantity: 2},
{productId: 'SKU-67890', name: 'Black Jeans', price: 49.99, quantity: 1},
],
value: 109.97,
currency: 'USD',
shipping: 5.99,
tax: 8.8,
discount: 10.0,
coupon: 'SAVE10',
});
The purchase() method requires you to pass the order items explicitly. The SDK does not store cart state client-side and does not pull items from the tracked cart or the server automatically. This ensures accuracy, since the order confirmation page or screen knows the exact items that were purchased.
Track Order Status Changes
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Order shipped
ecommerce.orderFulfilled('ORD-2024-001', '1Z999AA10123456784', 'UPS');
// Order delivered
ecommerce.orderDelivered('ORD-2024-001');
// Order cancelled
ecommerce.orderCancelled('ORD-2024-001', 'Customer requested');
// Order refunded
ecommerce.orderRefunded('ORD-2024-001', 29.99, 'Product defective');
// Order fulfilled (shipped)
ecommerce.orderFulfilled(orderId: "ORD-2024-001", trackingNumber: "1Z999AA10123456784", carrier: "UPS")
// Order delivered
ecommerce.orderDelivered(orderId: "ORD-2024-001")
// Order cancelled
ecommerce.orderCancelled(orderId: "ORD-2024-001", reason: "Customer requested cancellation")
// Order refunded
ecommerce.orderRefunded(orderId: "ORD-2024-001", refundAmount: 29.99, reason: "Product defective")
// Order fulfilled (shipped)
ecommerce.orderFulfilled(orderId = "ORD-2024-001", trackingNumber = "1Z999AA10123456784", carrier = "UPS")
// Order delivered
ecommerce.orderDelivered(orderId = "ORD-2024-001")
// Order cancelled
ecommerce.orderCancelled(orderId = "ORD-2024-001", reason = "Customer requested cancellation")
// Order refunded
ecommerce.orderRefunded(orderId = "ORD-2024-001", refundAmount = 29.99, reason = "Product defective")
// Order shipped
Joryio.ecommerce.orderFulfilled('ORD-2024-001', '1Z999AA10123456784', 'UPS');
// Order delivered
Joryio.ecommerce.orderDelivered('ORD-2024-001');
// Order cancelled or refunded
Joryio.ecommerce.orderCancelled('ORD-2024-001', 'customer_request');
Joryio.ecommerce.orderRefunded('ORD-2024-001', 29.99, 'damaged');
Track Wishlist & Sharing
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Add to wishlist
ecommerce.addToWishlist({
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt',
price: 29.99
});
// Share product
ecommerce.shareProduct({
productId: 'SKU-12345',
name: 'Classic Blue T-Shirt'
}, 'facebook'); // share method
// Wishlist
ecommerce.addToWishlist(product: product)
ecommerce.removeFromWishlist(product: product)
// Share product
ecommerce.shareProduct(product: product, shareMethod: "twitter")
// Wishlist
ecommerce.addToWishlist(product)
ecommerce.removeFromWishlist(product)
// Share product
ecommerce.shareProduct(product, shareMethod = "twitter")
// Add to wishlist
Joryio.ecommerce.addToWishlist(product);
// Remove from wishlist
Joryio.ecommerce.removeFromWishlist(product);
// Share a product
Joryio.ecommerce.shareProduct(product, 'whatsapp');
Track Coupons
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Coupon applied
ecommerce.applyCoupon('SAVE10', 10.00, 'percentage');
// Coupon removed
ecommerce.removeCoupon('SAVE10');
// Coupon
ecommerce.applyCoupon(couponCode: "SAVE10", discountAmount: 10.00, discountType: "percentage")
ecommerce.removeCoupon(couponCode: "SAVE10")
// Coupon
ecommerce.applyCoupon(couponCode = "SAVE10", discountAmount = 10.00, discountType = "percentage")
ecommerce.removeCoupon(couponCode = "SAVE10")
// Coupon applied
Joryio.ecommerce.applyCoupon('SAVE10', 10.0, 'percentage');
// Coupon removed
Joryio.ecommerce.removeCoupon('SAVE10');
Track Reviews
- Web (JS)
- iOS (Swift)
- Android (Kotlin)
- React Native
// Product review submitted
ecommerce.submitReview('SKU-12345', 5, 'Great quality shirt!');
// Review
ecommerce.submitReview(productId: "SKU-12345", rating: 5, reviewText: "Great product!")
// Review
ecommerce.submitReview(productId = "SKU-12345", rating = 5, reviewText = "Great product!")
// Product review submitted
Joryio.ecommerce.submitReview('SKU-12345', 5, 'Great shirt, true to size.');
Standard E-Commerce Events
The e-commerce tracker sends the same standard events on every platform:
| Event Name | Description |
|---|---|
Product Viewed | User views a product page |
Product List Viewed | User views a category page |
Products Searched | User searches for products |
Product Added | Item added to cart |
Product Removed | Item removed from cart |
Cart Updated | Cart contents changed |
Checkout Started | User begins checkout |
Payment Info Entered | User adds payment method |
Order Completed | Order completed |
Order Fulfilled | Order shipped |
Order Delivered | Order delivered |
Order Cancelled | Order cancelled |
Order Refunded | Order refunded |
Product Added to Wishlist | Product added to wishlist |
Product Removed from Wishlist | Product removed from wishlist |
Product Shared | Product shared |
Coupon Applied | Coupon code applied |
Coupon Removed | Coupon code removed |
Product Reviewed | Product review submitted |
When a store (Shopify, WooCommerce, Magento) or the Orders API sends your orders, Joryio emits Order Refunded and Order Cancelled itself - do not also call orderRefunded / orderCancelled for those orders, or each refund is recorded twice. The server events use the same order_id, refund_amount and reason keys as the trackers, so one journey condition matches both. See Refund and cancellation events.
Required arguments
Every tracker refuses an incomplete call the same way, on every SDK: it logs a warning and sends nothing - never an event with an empty ID or a zero amount, which a revenue report would count as real. No call throws.
| Call | Required |
|---|---|
viewProduct, removeFromCart, addToWishlist, removeFromWishlist | A product with a productId and a finite price |
addToCart | An item with a productId and a finite price |
shareProduct | A product as above, and a shareMethod |
viewCategory | categoryId and categoryName |
search | query |
cartViewed, updateCart, startCheckout | An items array, each item with a productId and a finite price, and a finite cartValue |
addPaymentInfo | paymentMethod |
purchase | An orderId, an items array (it may be empty; each item as above) and a finite value |
orderFulfilled, orderDelivered, orderCancelled, orderRefunded | orderId |
applyCoupon, removeCoupon | couponCode |
submitReview | productId |
An ID or label that is empty or only spaces counts as missing. An optional amount - cartValue on addToCart, shipping, tax and discount on an order, refundAmount, discountAmount - can be left out, but one you pass must be a finite number: NaN or infinity refuses the whole call instead of sending it without that amount.
Any custom properties you pass alongside follow the general rule instead: a NaN or infinite value there is dropped with a warning and the call is sent without that key - see Properties and data types.
Unity uses PascalCase names (ViewProduct, ProductId); the rules are the same.
Why use the tracker rather than track()
Every SDK ships an e-commerce tracker, and it exists to stop you typing event names and property keys by hand.
There is deliberately no alias layer on the server. Added to Cart is not a
near-miss for Product Added - it is a different event, stored verbatim, which
matches no e-commerce report, no revenue attribution and no recommendation
feature. The same applies to properties: an order's revenue is read from
total, so an order sent with value records $0.
Neither failure produces an error. You get a plausible number, which is far harder to notice than an obviously broken one, and the tracker is how you avoid having to know any of this.
Next Steps
- Web SDK - Installation, configuration, and full API reference
- iOS SDK - Integrate the iOS SDK
- Android SDK - Integrate the Android SDK
- React Native SDK - Integrate the React Native SDK
- Unity SDK - Integrate the Unity SDK
- Custom Events - Track custom events
- E-Commerce API - Server-side e-commerce integration