Events
The Next Commerce JS SDK emits events that you can listen to for tracking and custom functionality. The SDK has 34 internal events that can be listened to via next.on().
Event Categories
- Cart Events - Track cart state changes
- Checkout Events - Monitor checkout process
- Payment Events - Handle payment states
- Order Events - Track order completion
- Campaign Events - Campaign data loading
- Coupon Events - Discount code usage
- Upsell Events - Post-purchase upsell tracking
- User Events - User authentication
- Behavioral Events - FOMO, exit intent
- Profile Events - Profile management and switching
- System Events - SDK state, errors, routing
SDK Initialization
Initialization Callbacks (window.nextReady)
The window.nextReady queue ensures your code runs after the SDK is fully initialized.
// Queue a callback before SDK loads
window.nextReady = window.nextReady || [];
window.nextReady.push(function() {
// SDK is ready - window.next is available
console.log('Cart count:', next.getCartCount());
next.addItem({ packageId: 123 });
});Callback Patterns:
// Pattern 1: Without SDK Parameter (Recommended)
window.nextReady.push(function() {
// Access SDK via global window.next
next.addItem({ packageId: 123 });
});
// Pattern 2: With SDK Parameter
window.nextReady.push(function(sdk) {
// SDK passed as parameter
sdk.addItem({ packageId: 123 });
});Multiple Callbacks:
// Queue multiple callbacks
window.nextReady.push(function() {
next.trackViewItemList(['1', '2', '3']);
});
window.nextReady.push(function() {
next.on('cart:updated', function(data) {
console.log('Cart updated:', data);
});
});next:initialized (DOM Event)
Fired when SDK is fully loaded and ready (DOM event):
// Listen on document for initialization
document.addEventListener('next:initialized', function(event) {
console.log('SDK is ready at:', event.detail.timestamp);
console.log('Version:', event.detail.version);
// Safe to use SDK methods here
});Cart Events
cart:updated
Fired whenever cart contents change (most common event):
next.on('cart:updated', (cartState) => {
console.log('Cart updated:', cartState);
// cartState includes: items, totals, enrichedItems, etc.
console.log('Total items:', cartState.totalQuantity);
console.log('Cart total:', cartState.totals.total.formatted);
});cart:item-added
Fired when item is added to cart:
next.on('cart:item-added', (data) => {
console.log('Item added:', data);
// data includes: packageId, quantity, item details
});cart:item-removed
Fired when item is removed from cart:
next.on('cart:item-removed', (data) => {
console.log('Item removed:', data);
// data includes: packageId, item details that were removed
});cart:quantity-changed
Fired when item quantity is updated:
next.on('cart:quantity-changed', (data) => {
console.log('Quantity changed:', data);
// data includes: packageId, oldQuantity, newQuantity
});cart:package-swapped
Fired when a package is swapped for another:
next.on('cart:package-swapped', (data) => {
console.log('Package swapped:', data);
// data includes: previousPackageId, newPackageId, previousItem, newItem, priceDifference, source
});Checkout & Order Events
checkout:started
Fired when checkout process begins:
next.on('checkout:started', (data) => {
console.log('Checkout started:', data);
// data includes: cart items, totals
});checkout:form-initialized
Fired when checkout form is ready:
next.on('checkout:form-initialized', () => {
console.log('Checkout form ready');
// Form is now initialized and ready for input
});order:completed
Fired when order is successfully completed:
next.on('order:completed', (order) => {
console.log('Order completed:', order);
// order includes: ref_id, total, lines, customer info
});Payment Events
payment:tokenized
Fired when payment is successfully tokenized:
next.on('payment:tokenized', (data) => {
console.log('Payment tokenized:', data);
// data includes: token info, payment method
});payment:error
Fired when payment processing fails:
next.on('payment:error', (error) => {
console.error('Payment failed:', error);
// error includes: message, code, details
});express-checkout:started
Fired when express checkout (PayPal, Apple Pay, etc.) begins:
next.on('express-checkout:started', (data) => {
console.log('Express checkout started:', data);
// data includes: method type (paypal, apple, google)
});Campaign & Configuration Events
campaign:loaded
Fired when campaign data is loaded:
next.on('campaign:loaded', (campaign) => {
console.log('Campaign loaded:', campaign);
// campaign includes: packages, settings, currency, etc.
});config:updated
Fired when SDK configuration changes:
next.on('config:updated', (config) => {
console.log('Config updated:', config);
// config includes: all SDK settings
});Coupon Events
coupon:applied
Fired when coupon is successfully applied:
next.on('coupon:applied', (coupon) => {
console.log('Coupon applied:', coupon);
// coupon includes: code, discount amount, type
});coupon:removed
Fired when coupon is removed:
next.on('coupon:removed', (code) => {
console.log('Coupon removed:', code);
// code is the removed coupon code string
});Upsell Events
upsell:viewed
Fired when upsell offer is displayed:
next.on('upsell:viewed', (data) => {
console.log('Upsell viewed:', data);
// data includes: packageId, offer details
});upsell:accepted
Fired when user accepts an upsell:
next.on('upsell:accepted', (data) => {
console.log('Upsell accepted:', data);
// data includes: packageId, quantity, value
});upsell:added
Fired when upsell is successfully added to order:
next.on('upsell:added', (data) => {
console.log('Upsell added:', data);
// data includes: packageId, order, value
});upsell:skipped
Fired when user skips/declines an upsell:
next.on('upsell:skipped', (data) => {
console.log('Upsell skipped:', data);
// data includes: packageId, reason
});User Events
user:logged-in
Fired when user logs in:
next.on('user:logged-in', (data) => {
console.log('User logged in:', data);
// data includes: user info, email
});user:logged-out
Fired when user logs out:
next.on('user:logged-out', (data) => {
console.log('User logged out:', data);
});Behavioral Events
fomo:shown
Fired when FOMO notification appears:
next.on('fomo:shown', (data) => {
console.log('FOMO shown:', data);
// data includes: customer name, product, location
});exit-intent:clicked
Fired when user clicks on exit intent popup:
next.on('exit-intent:clicked', (data) => {
console.log('Exit intent clicked:', data);
// data includes: imageUrl, template
});exit-intent:dismissed
Fired when exit intent popup is dismissed:
next.on('exit-intent:dismissed', (data) => {
console.log('Exit intent dismissed:', data);
// data includes: imageUrl, template
});exit-intent:closed
Fired when exit intent popup is closed:
next.on('exit-intent:closed', (data) => {
console.log('Exit intent closed:', data);
// data includes: imageUrl, template
});exit-intent:action
Fired when user takes an action on exit intent popup:
next.on('exit-intent:action', (data) => {
console.log('Exit intent action:', data);
// data includes: action, couponCode
});Profile Events
profile:applied
Fired when a profile is applied to the cart:
next.on('profile:applied', (data) => {
console.log('Profile applied:', data);
// data includes: profileId, previousProfileId, itemsSwapped, originalItems, cleared, profile
});profile:reverted
Fired when profile changes are reverted:
next.on('profile:reverted', (data) => {
console.log('Profile reverted:', data);
// data includes: previousProfileId, itemsRestored
});profile:switched
Fired when switching between profiles:
next.on('profile:switched', (data) => {
console.log('Profile switched:', data);
// data includes: fromProfileId, toProfileId, itemsAffected
});profile:registered
Fired when a new profile is registered:
next.on('profile:registered', (data) => {
console.log('Profile registered:', data);
// data includes: profileId, mappingsCount
});System Events
route:changed
Fired when SDK detects route/page change:
next.on('route:changed', (route) => {
console.log('Route changed:', route);
// route includes: path, params
});sdk:route-invalidated
Fired when SDK route context is invalidated:
next.on('sdk:route-invalidated', (data) => {
console.log('Route invalidated:', data);
});page:viewed
Fired when page view is tracked:
next.on('page:viewed', (data) => {
console.log('Page viewed:', data);
// data includes: page info, timestamp
});error:occurred
Fired when SDK encounters an error:
next.on('error:occurred', (error) => {
console.error('SDK error:', error);
// error includes: message, stack, context
});Complete Event List
Here are all 34 available events organized by category:
Cart (5 events)
cart:updated- Cart state changedcart:item-added- Item added to cartcart:item-removed- Item removed from cartcart:quantity-changed- Item quantity changedcart:package-swapped- Package swapped for another
Checkout & Order (3 events)
checkout:started- Checkout process begancheckout:form-initialized- Checkout form readyorder:completed- Order successfully completed
Payment (3 events)
payment:tokenized- Payment token createdpayment:error- Payment processing failedexpress-checkout:started- Express checkout initiated
Campaign & Config (2 events)
campaign:loaded- Campaign data loadedconfig:updated- Configuration changed
Coupons (2 events)
coupon:applied- Discount code appliedcoupon:removed- Discount code removed
Upsells (4 events)
upsell:viewed- Upsell offer shownupsell:accepted- Upsell accepted by userupsell:added- Upsell added to orderupsell:skipped- Upsell declined/skipped
User (2 events)
user:logged-in- User authenticateduser:logged-out- User logged out
Behavioral (5 events)
fomo:shown- FOMO popup displayedexit-intent:clicked- Exit intent popup clickedexit-intent:dismissed- Exit intent popup dismissedexit-intent:closed- Exit intent popup closedexit-intent:action- Exit intent action taken
Profile (4 events)
profile:applied- Profile applied to cartprofile:reverted- Profile changes revertedprofile:switched- Switched between profilesprofile:registered- New profile registered
System (5 events)
route:changed- Page/route changedsdk:route-invalidated- Route context resetpage:viewed- Page view trackederror:occurred- Error encountered
Event Handling Patterns
Basic Event Listening
// Subscribe to events
next.on('cart:updated', (data) => {
console.log('Cart updated:', data);
});
// Multiple events
['cart:item-added', 'cart:item-removed'].forEach(event => {
next.on(event, (data) => {
console.log(`Event ${event}:`, data);
});
});Removing Listeners
const handler = (data) => console.log(data);
// Add listener
next.on('cart:updated', handler);
// Remove listener
next.off('cart:updated', handler);Error Handling in Events
next.on('cart:updated', (data) => {
try {
// Your code here
updateUI(data);
} catch (error) {
console.error('Error in event handler:', error);
}
});DOM Events vs SDK Events
// DOM events (for SDK lifecycle)
document.addEventListener('next:initialized', (event) => {
console.log('SDK ready via DOM event');
});
// SDK events (for cart, checkout, etc.)
next.on('cart:updated', (data) => {
console.log('Cart updated via SDK event');
});Custom Event Integration
Google Analytics
next.on('cart:item-added', (data) => {
if (typeof gtag !== 'undefined') {
gtag('event', 'add_to_cart', {
value: data.item.price,
currency: 'USD',
items: [data.item]
});
}
});Custom Analytics
// Track all cart changes
next.on('cart:updated', (data) => {
fetch('/api/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
event: 'cart_updated',
properties: data
})
});
});Best Practices
- Always check data: Validate event data before using
- Handle errors: Wrap handlers in try-catch
- Clean up: Remove listeners when no longer needed
- Don't block: Keep handlers fast and async
- Test events: Verify events fire as expected
Debugging Events
List All Available Events
// Get all registered events from the EventBus
if (window.next && window.next.eventBus) {
const listeners = window.next.eventBus.listeners;
const events = Array.from(listeners.keys()).sort();
console.log('Available events:', events.length);
events.forEach((event, i) => {
const count = listeners.get(event).size;
console.log(`${i + 1}. ${event} (${count} listeners)`);
});
}Monitor All Events
// Log all events for debugging
if (window.location.search.includes('debug=true')) {
const allEvents = [
// Cart
'cart:updated', 'cart:item-added', 'cart:item-removed', 'cart:quantity-changed', 'cart:package-swapped',
// Checkout & Order
'checkout:started', 'checkout:form-initialized', 'order:completed',
// Payment
'payment:tokenized', 'payment:error', 'express-checkout:started',
// Campaign & Config
'campaign:loaded', 'config:updated',
// Coupons
'coupon:applied', 'coupon:removed',
// Upsells
'upsell:viewed', 'upsell:accepted', 'upsell:added', 'upsell:skipped',
// User
'user:logged-in', 'user:logged-out',
// Behavioral
'fomo:shown', 'exit-intent:clicked', 'exit-intent:dismissed', 'exit-intent:closed', 'exit-intent:action',
// Profile
'profile:applied', 'profile:reverted', 'profile:switched', 'profile:registered',
// System
'route:changed', 'sdk:route-invalidated', 'page:viewed', 'error:occurred'
];
allEvents.forEach(event => {
next.on(event, (data) => {
console.log(`[Event] ${event}:`, data);
});
});
}Legacy Lifecycle Callbacks
Legacy Feature
Lifecycle callbacks (next.registerCallback) are a legacy feature primarily for backwards compatibility. For new code, use the event system instead.
The SDK supports lifecycle callbacks for specific operations. These are less flexible than events but may be needed for legacy integrations.
Available Callback Types
// CallbackType values:
'beforeRender' // Before cart UI renders
'afterRender' // After cart UI renders
'beforeCheckout' // Before checkout starts
'afterCheckout' // After checkout completes
'beforeRedirect' // Before order redirect
'itemAdded' // After item added to cart
'itemRemoved' // After item removed from cart
'cartCleared' // After cart clearedRegistering Callbacks
window.nextReady.push(function() {
// Register a callback
next.registerCallback('itemAdded', function(data) {
console.log('Item added to cart:', data);
// data contains: cartLines, cartTotals, campaignData, appliedCoupons
});
// Register multiple callbacks
next.registerCallback('beforeCheckout', function(data) {
console.log('Checkout starting with:', data.cartTotals);
});
});Callback Data Structure
All lifecycle callbacks receive a CallbackData object:
{
cartLines: EnrichedCartLine[]; // Cart items with full details
cartTotals: CartTotals; // Pricing information
campaignData: Campaign | null; // Campaign configuration
appliedCoupons: AppliedCoupon[]; // Active discounts
}Unregistering Callbacks
// Store reference to callback function
const myCallback = function(data) {
console.log('Cart data:', data);
};
// Register callback
next.registerCallback('cartCleared', myCallback);
// Later, unregister it
next.unregisterCallback('cartCleared', myCallback);Migration to Events
For new code, prefer events over lifecycle callbacks:
// Preferred: Use events
next.on('cart:item-added', function(data) {
console.log('Item added:', data);
});
// Legacy: Lifecycle callbacks
next.registerCallback('itemAdded', function(data) {
console.log('Item added:', data);
});