Skip to content

Events

The Next Commerce JS SDK emits 34 internal events that you can listen to for tracking and custom functionality.

  • 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

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
});

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);
});

Fired when item is added to cart:

next.on('cart:item-added', (data) => {
console.log('Item added:', data);
// data includes: packageId, quantity, item details
});

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
});

Fired when item quantity is updated:

next.on('cart:quantity-changed', (data) => {
console.log('Quantity changed:', data);
// data includes: packageId, oldQuantity, newQuantity
});

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
});

Fired when checkout process begins:

next.on('checkout:started', (data) => {
console.log('Checkout started:', data);
// data includes: cart items, totals
});

Fired when checkout form is ready:

next.on('checkout:form-initialized', () => {
console.log('Checkout form ready');
// Form is now initialized and ready for input
});

Fired when order is successfully completed:

next.on('order:completed', (order) => {
console.log('Order completed:', order);
// order includes: ref_id, total, lines, customer info
});

Fired when payment is successfully tokenized:

next.on('payment:tokenized', (data) => {
console.log('Payment tokenized:', data);
// data includes: token info, payment method
});

Fired when payment processing fails:

next.on('payment:error', (error) => {
console.error('Payment failed:', error);
// error includes: message, code, details
});

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)
});

Fired when campaign data is loaded:

next.on('campaign:loaded', (campaign) => {
console.log('Campaign loaded:', campaign);
// campaign includes: packages, settings, currency, etc.
});

Fired when SDK configuration changes:

next.on('config:updated', (config) => {
console.log('Config updated:', config);
// config includes: all SDK settings
});

Fired when coupon is successfully applied:

next.on('coupon:applied', (coupon) => {
console.log('Coupon applied:', coupon);
// coupon includes: code, discount amount, type
});

Fired when coupon is removed:

next.on('coupon:removed', (code) => {
console.log('Coupon removed:', code);
// code is the removed coupon code string
});

Fired when upsell offer is displayed:

next.on('upsell:viewed', (data) => {
console.log('Upsell viewed:', data);
// data includes: packageId, offer details
});

Fired when user accepts an upsell:

next.on('upsell:accepted', (data) => {
console.log('Upsell accepted:', data);
// data includes: packageId, quantity, value
});

Fired when upsell is successfully added to order:

next.on('upsell:added', (data) => {
console.log('Upsell added:', data);
// data includes: packageId, order, value
});

Fired when user skips/declines an upsell:

next.on('upsell:skipped', (data) => {
console.log('Upsell skipped:', data);
// data includes: packageId, reason
});

Fired when user logs in:

next.on('user:logged-in', (data) => {
console.log('User logged in:', data);
// data includes: user info, email
});

Fired when user logs out:

next.on('user:logged-out', (data) => {
console.log('User logged out:', data);
});

Fired when FOMO notification appears:

next.on('fomo:shown', (data) => {
console.log('FOMO shown:', data);
// data includes: customer name, product, location
});

Fired when user clicks on exit intent popup:

next.on('exit-intent:clicked', (data) => {
console.log('Exit intent clicked:', data);
// data includes: imageUrl, template
});

Fired when exit intent popup is dismissed:

next.on('exit-intent:dismissed', (data) => {
console.log('Exit intent dismissed:', data);
// data includes: imageUrl, template
});

Fired when exit intent popup is closed:

next.on('exit-intent:closed', (data) => {
console.log('Exit intent closed:', data);
// data includes: imageUrl, template
});

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
});

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
});

Fired when profile changes are reverted:

next.on('profile:reverted', (data) => {
console.log('Profile reverted:', data);
// data includes: previousProfileId, itemsRestored
});

Fired when switching between profiles:

next.on('profile:switched', (data) => {
console.log('Profile switched:', data);
// data includes: fromProfileId, toProfileId, itemsAffected
});

Fired when a new profile is registered:

next.on('profile:registered', (data) => {
console.log('Profile registered:', data);
// data includes: profileId, mappingsCount
});

Fired when SDK detects route/page change:

next.on('route:changed', (route) => {
console.log('Route changed:', route);
// route includes: path, params
});

Fired when SDK route context is invalidated:

next.on('sdk:route-invalidated', (data) => {
console.log('Route invalidated:', data);
});

Fired when page view is tracked:

next.on('page:viewed', (data) => {
console.log('Page viewed:', data);
// data includes: page info, timestamp
});

Fired when SDK encounters an error:

next.on('error:occurred', (error) => {
console.error('SDK error:', error);
// error includes: message, stack, context
});

All 34 available events organized by category:

  • cart:updated - Cart state changed
  • cart:item-added - Item added to cart
  • cart:item-removed - Item removed from cart
  • cart:quantity-changed - Item quantity changed
  • cart:package-swapped - Package swapped for another
  • checkout:started - Checkout process began
  • checkout:form-initialized - Checkout form ready
  • order:completed - Order successfully completed
  • payment:tokenized - Payment token created
  • payment:error - Payment processing failed
  • express-checkout:started - Express checkout initiated
  • campaign:loaded - Campaign data loaded
  • config:updated - Configuration changed
  • coupon:applied - Discount code applied
  • coupon:removed - Discount code removed
  • upsell:viewed - Upsell offer shown
  • upsell:accepted - Upsell accepted by user
  • upsell:added - Upsell added to order
  • upsell:skipped - Upsell declined/skipped
  • user:logged-in - User authenticated
  • user:logged-out - User logged out
  • fomo:shown - FOMO popup displayed
  • exit-intent:clicked - Exit intent popup clicked
  • exit-intent:dismissed - Exit intent popup dismissed
  • exit-intent:closed - Exit intent popup closed
  • exit-intent:action - Exit intent action taken
  • profile:applied - Profile applied to cart
  • profile:reverted - Profile changes reverted
  • profile:switched - Switched between profiles
  • profile:registered - New profile registered
  • route:changed - Page/route changed
  • sdk:route-invalidated - Route context reset
  • page:viewed - Page view tracked
  • error:occurred - Error encountered
// 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);
});
});
const handler = (data) => console.log(data);
// Add listener
next.on('cart:updated', handler);
// Remove listener
next.off('cart:updated', handler);
next.on('cart:updated', (data) => {
try {
// Your code here
updateUI(data);
} catch (error) {
console.error('Error in event handler:', error);
}
});
// 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');
});
next.on('cart:item-added', (data) => {
if (typeof gtag !== 'undefined') {
gtag('event', 'add_to_cart', {
value: data.item.price,
currency: 'USD',
items: [data.item]
});
}
});
next.on('order:completed', (order) => {
if (typeof gtag !== 'undefined') {
gtag('event', 'purchase', {
transaction_id: order.ref_id,
value: order.total,
currency: order.currency,
items: order.lines
});
}
});
next.on('cart:item-added', (data) => {
if (typeof fbq !== 'undefined') {
fbq('track', 'AddToCart', {
content_ids: [data.packageId],
content_type: 'product',
value: data.item.price,
currency: 'USD'
});
}
});
next.on('checkout:started', (data) => {
if (typeof fbq !== 'undefined') {
fbq('track', 'InitiateCheckout', {
value: data.total,
currency: 'USD',
num_items: data.itemCount
});
}
});
// 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
})
});
});
// Track conversions
next.on('order:completed', async (order) => {
await fetch('/api/conversions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(order)
});
});
// 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)`);
});
}
// 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);
});
});
}
  1. Always check data: Validate event data before using
  2. Handle errors: Wrap handlers in try-catch
  3. Clean up: Remove listeners when no longer needed
  4. Don’t block: Keep handlers fast and async
  5. Test events: Verify events fire as expected
  6. Batch operations: Group related operations for performance
  7. Use appropriate events: Choose the most specific event for your use case
let cartTimer;
const ABANDONMENT_DELAY = 30 * 60 * 1000; // 30 minutes
next.on('cart:updated', (data) => {
clearTimeout(cartTimer);
if (data.totalQuantity > 0) {
cartTimer = setTimeout(() => {
// Track abandonment
fetch('/api/cart-abandoned', {
method: 'POST',
body: JSON.stringify(data)
});
}, ABANDONMENT_DELAY);
}
});
next.on('order:completed', () => {
clearTimeout(cartTimer);
});
// Update cart count in header
next.on('cart:updated', (data) => {
const badge = document.querySelector('.cart-badge');
if (badge) {
badge.textContent = data.totalQuantity || '';
badge.style.display = data.totalQuantity > 0 ? 'block' : 'none';
}
});
// Show success notifications
next.on('cart:item-added', (data) => {
showNotification(`${data.item.name} added to cart!`, 'success');
});
// Update checkout button state
next.on('cart:updated', (data) => {
const checkoutBtn = document.querySelector('.checkout-button');
if (checkoutBtn) {
checkoutBtn.disabled = data.totalQuantity === 0;
}
});