Skip to content

Callbacks

The Next Commerce SDK provides two callback systems for different purposes:

  1. Initialization Callbacks (window.nextReady) - For code that needs to run after SDK loads
  2. Lifecycle Callbacks (next.registerCallback) - For hooking into SDK operations

Initialization Callbacks (window.nextReady)

Section titled “Initialization Callbacks (window.nextReady)”

The window.nextReady queue ensures your code runs after the SDK is fully initialized and the global next object is available.

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

The SDK supports two callback patterns:

Section titled “Pattern 1: Without SDK Parameter (Recommended)”
window.nextReady.push(function() {
// Access SDK via global window.next
next.addItem({ packageId: 123 });
next.trackViewItemList(['1', '2', '3']);
});
window.nextReady.push(function(sdk) {
// SDK passed as parameter
sdk.addItem({ packageId: 123 });
sdk.trackViewItemList(['1', '2', '3']);
});

You can queue multiple callbacks - they execute in order:

// First callback - initialize tracking
window.nextReady.push(function() {
next.trackViewItemList(['1', '2', '3']);
});
// Second callback - set up event listeners
window.nextReady.push(function() {
next.on('cart:updated', function(data) {
console.log('Cart updated:', data);
});
});
// Third callback - check for saved cart
window.nextReady.push(function() {
if (next.getCartCount() === 0) {
console.log('Cart is empty');
}
});

Once the SDK is loaded, window.nextReady becomes a direct executor:

// After SDK initialization, callbacks execute immediately
window.nextReady.push(function() {
console.log('This runs immediately if SDK is already ready');
});

Callbacks are wrapped in try-catch to prevent failures from affecting other callbacks:

window.nextReady.push(function() {
try {
// Your integration code
customAnalyticsSetup();
thirdPartyIntegration();
} catch (error) {
console.error('Integration failed:', error);
// Fallback behavior
}
});

Register callbacks to hook into specific SDK operations and access detailed cart data.

'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 cleared
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 total:', data.cartTotals.total);
});
});

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

Track e-commerce events with Google Analytics:

window.nextReady.push(function() {
// Track add to cart events
next.registerCallback('itemAdded', function(data) {
if (window.gtag) {
const lastItem = data.cartLines[data.cartLines.length - 1];
gtag('event', 'add_to_cart', {
currency: 'USD',
value: lastItem.price.value,
items: [{
item_id: lastItem.packageId.toString(),
item_name: lastItem.name,
price: lastItem.price.value,
quantity: lastItem.quantity
}]
});
}
});
// Track checkout initiation
next.registerCallback('beforeCheckout', function(data) {
if (window.gtag) {
gtag('event', 'begin_checkout', {
currency: 'USD',
value: data.cartTotals.total.value,
items: data.cartLines.map(item => ({
item_id: item.packageId.toString(),
item_name: item.name,
price: item.price.value,
quantity: item.quantity
}))
});
}
});
});

Update custom elements when cart changes:

window.nextReady.push(function() {
// Update custom cart icon
next.registerCallback('itemAdded', function(data) {
const cartIcon = document.querySelector('.custom-cart-icon');
if (cartIcon) {
cartIcon.textContent = data.cartLines.length;
cartIcon.classList.add('bounce');
setTimeout(() => cartIcon.classList.remove('bounce'), 300);
}
});
// Show custom success message
next.registerCallback('afterCheckout', function(data) {
showCustomSuccessMessage(data.cartTotals.total.formatted);
});
});

Set up optional features when SDK is ready:

window.nextReady.push(function() {
// Initialize exit-intent popup
if (next.exitIntent) {
next.exitIntent({
image: '/images/special-offer.jpg',
couponCode: 'EXIT20',
action: function() {
next.applyCoupon('EXIT20');
}
});
}
// Initialize FOMO notifications
if (next.fomo) {
next.fomo({
displayDuration: 5000,
messages: [
'Someone in New York just purchased this!',
'Only 3 left in stock!'
]
});
}
});

React to cart changes for custom pricing displays:

window.nextReady.push(function() {
next.registerCallback('itemAdded', function(data) {
updateShippingEstimate(data.cartTotals);
updateBulkDiscountMessage(data.cartLines.length);
});
next.registerCallback('itemRemoved', function(data) {
if (data.cartLines.length === 0) {
showEmptyCartMessage();
} else {
updateShippingEstimate(data.cartTotals);
}
});
});
function updateShippingEstimate(totals) {
const threshold = 100;
const remaining = threshold - totals.subtotal.value;
if (remaining > 0) {
document.querySelector('.shipping-message').innerHTML =
`Add $${remaining.toFixed(2)} more for FREE shipping!`;
} else {
document.querySelector('.shipping-message').innerHTML =
'✅ You qualify for FREE shipping!';
}
}
// Ensure queue exists before pushing
window.nextReady = window.nextReady || [];
window.nextReady.push(function() {
// Your code
});
if (window.next) {
// SDK already loaded, use directly
next.addItem({ packageId: 123 });
} else {
// Queue for later execution
window.nextReady = window.nextReady || [];
window.nextReady.push(function() {
next.addItem({ packageId: 123 });
});
}

For most use cases, SDK events are more flexible:

// Preferred: Use events (more specific)
next.on('cart:item-added', function(data) {
console.log('Item added:', data);
});
// Legacy: Lifecycle callbacks (broader scope)
next.registerCallback('itemAdded', function(data) {
console.log('Item added:', data);
});
// Store references for cleanup
const callbacks = {
itemAdded: function(data) { updateCustomUI(data); },
cartCleared: function(data) { resetCustomState(); }
};
// Register callbacks
Object.entries(callbacks).forEach(([type, callback]) => {
next.registerCallback(type, callback);
});
// Later, clean up (e.g., when page unloads)
Object.entries(callbacks).forEach(([type, callback]) => {
next.unregisterCallback(type, callback);
});
window.nextReady.push(function() {
try {
// Primary functionality
setupAdvancedFeatures();
} catch (error) {
console.error('Advanced features failed:', error);
// Fallback to basic functionality
setupBasicFeatures();
}
});
// Only initialize on specific pages
if (document.body.classList.contains('product-page')) {
window.nextReady.push(function() {
const productId = document.querySelector('[data-product-id]')?.dataset.productId;
if (productId) {
next.trackViewItem(productId);
}
});
}
window.nextReady.push(function() {
// Check configuration before enabling features
if (next.config.get('exit_intent_enabled')) {
setupExitIntent();
}
if (next.config.get('fomo_enabled')) {
setupFomoNotifications();
}
});
window.nextReady.push(function() {
// Wait for both SDK and third-party library
if (window.Klaviyo) {
next.registerCallback('itemAdded', function(data) {
Klaviyo.track('Added to Cart', {
ProductName: data.cartLines[data.cartLines.length - 1].name,
Value: data.cartTotals.total.value
});
});
} else {
console.warn('Klaviyo not loaded, skipping integration');
}
});
// Old pattern (risky - SDK might not be loaded)
if (window.MySDK) {
MySDK.addToCart(123);
}
// New pattern (safe - waits for SDK)
window.nextReady.push(function() {
next.addItem({ packageId: 123 });
});
// Old pattern
$(document).ready(function() {
if (window.next) {
next.addItem({ packageId: 123 });
}
});
// New pattern
window.nextReady.push(function() {
next.addItem({ packageId: 123 });
});