Callbacks
Callbacks
Section titled “Callbacks”The Next Commerce SDK provides two callback systems for different purposes:
- Initialization Callbacks (
window.nextReady) - For code that needs to run after SDK loads - 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.
Basic Usage
Section titled “Basic Usage”// Queue a callback before SDK loadswindow.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
Section titled “Callback Patterns”The SDK supports two callback patterns:
Pattern 1: Without SDK Parameter (Recommended)
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']);});Pattern 2: With SDK Parameter
Section titled “Pattern 2: With SDK Parameter”window.nextReady.push(function(sdk) { // SDK passed as parameter sdk.addItem({ packageId: 123 }); sdk.trackViewItemList(['1', '2', '3']);});Multiple Callbacks
Section titled “Multiple Callbacks”You can queue multiple callbacks - they execute in order:
// First callback - initialize trackingwindow.nextReady.push(function() { next.trackViewItemList(['1', '2', '3']);});
// Second callback - set up event listenerswindow.nextReady.push(function() { next.on('cart:updated', function(data) { console.log('Cart updated:', data); });});
// Third callback - check for saved cartwindow.nextReady.push(function() { if (next.getCartCount() === 0) { console.log('Cart is empty'); }});Dynamic Callbacks
Section titled “Dynamic Callbacks”Once the SDK is loaded, window.nextReady becomes a direct executor:
// After SDK initialization, callbacks execute immediatelywindow.nextReady.push(function() { console.log('This runs immediately if SDK is already ready');});Error Handling
Section titled “Error Handling”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 }});Lifecycle Callbacks
Section titled “Lifecycle Callbacks”Register callbacks to hook into specific SDK operations and access detailed cart data.
Available Callback Types
Section titled “Available Callback Types”'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
Section titled “Registering 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 total:', data.cartTotals.total); });});Callback Data Structure
Section titled “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
Section titled “Unregistering Callbacks”// Store reference to callback functionconst myCallback = function(data) { console.log('Cart data:', data);};
// Register callbacknext.registerCallback('cartCleared', myCallback);
// Later, unregister itnext.unregisterCallback('cartCleared', myCallback);Practical Examples
Section titled “Practical Examples”Analytics Integration
Section titled “Analytics Integration”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 })) }); } });});Custom UI Updates
Section titled “Custom UI Updates”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); });});Feature Initialization
Section titled “Feature Initialization”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!' ] }); }});Dynamic Pricing Updates
Section titled “Dynamic Pricing Updates”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!'; }}Best Practices
Section titled “Best Practices”1. Always Initialize the Queue
Section titled “1. Always Initialize the Queue”// Ensure queue exists before pushingwindow.nextReady = window.nextReady || [];window.nextReady.push(function() { // Your code});2. Check SDK Availability
Section titled “2. Check SDK Availability”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 }); });}3. Prefer Events Over Lifecycle Callbacks
Section titled “3. Prefer Events Over Lifecycle Callbacks”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);});4. Clean Up Resources
Section titled “4. Clean Up Resources”// Store references for cleanupconst callbacks = { itemAdded: function(data) { updateCustomUI(data); }, cartCleared: function(data) { resetCustomState(); }};
// Register callbacksObject.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);});5. Handle Errors Gracefully
Section titled “5. Handle Errors Gracefully”window.nextReady.push(function() { try { // Primary functionality setupAdvancedFeatures(); } catch (error) { console.error('Advanced features failed:', error);
// Fallback to basic functionality setupBasicFeatures(); }});Common Patterns
Section titled “Common Patterns”Page-Specific Initialization
Section titled “Page-Specific Initialization”// Only initialize on specific pagesif (document.body.classList.contains('product-page')) { window.nextReady.push(function() { const productId = document.querySelector('[data-product-id]')?.dataset.productId; if (productId) { next.trackViewItem(productId); } });}Conditional Feature Loading
Section titled “Conditional Feature Loading”window.nextReady.push(function() { // Check configuration before enabling features if (next.config.get('exit_intent_enabled')) { setupExitIntent(); }
if (next.config.get('fomo_enabled')) { setupFomoNotifications(); }});Third-Party Integration
Section titled “Third-Party Integration”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'); }});Migration Guide
Section titled “Migration Guide”From Legacy Direct Access
Section titled “From Legacy Direct Access”// 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 });});From jQuery Ready
Section titled “From jQuery Ready”// Old pattern$(document).ready(function() { if (window.next) { next.addItem({ packageId: 123 }); }});
// New patternwindow.nextReady.push(function() { next.addItem({ packageId: 123 });});Related Documentation
Section titled “Related Documentation”- Events - For reactive event handling
- Methods - For available SDK methods
- Cart Methods - For cart-specific operations