@liquidcommerce/elements-sdk 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/EVENTS.md ADDED
@@ -0,0 +1,532 @@
1
+ # Elements SDK Events - Partner Implementation Guide
2
+
3
+ > **Browser Support**: This SDK supports 2018+ browsers (Chrome 66+, Firefox 60+, Safari 12+) with comprehensive polyfills. See `docs/BROWSER_SUPPORT.md` for details.
4
+
5
+ ## What Are Events and Why Use Them?
6
+
7
+ Events are real-time notifications that tell you exactly what your customers are doing on your site. Think of them as your digital sales assistant that whispers in your ear every time a customer looks at a product, adds something to cart, or starts checkout.
8
+
9
+ **Business Benefits:**
10
+ - **Track Revenue Impact**: See which products drive the most sales
11
+ - **Optimize Conversion**: Identify where customers drop off
12
+ - **Personalize Experience**: Trigger custom actions based on customer behavior
13
+ - **Measure Performance**: Get real metrics on your e-commerce funnel
14
+ - **Automate Marketing**: Send targeted emails/SMS based on customer actions
15
+
16
+ ## How It Works
17
+
18
+ When customers interact with your LiquidCommerce elements, events automatically fire. You simply "listen" for these events and take action:
19
+
20
+ ```javascript
21
+ // Example: When someone adds to cart, send them a discount code
22
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
23
+ // Customer just added a product to cart!
24
+ const product = event.detail.data;
25
+
26
+ // Maybe send them a discount popup
27
+ showDiscountPopup(product.productName);
28
+
29
+ // Or track in your analytics
30
+ analytics.track('Product Added', {
31
+ product: product.productName,
32
+ price: product.price
33
+ });
34
+ });
35
+ ```
36
+
37
+ ## Quick Implementation Guide
38
+
39
+ ### Step 1: Choose Your Goal
40
+ What do you want to achieve? Pick one:
41
+
42
+ **🎯 Track Sales Performance**
43
+ ```javascript
44
+ // Track when products are viewed and added to cart
45
+ window.addEventListener('lce:actions.product_loaded', function(event) {
46
+ // Product was viewed - track in your analytics
47
+ const product = event.detail.data;
48
+ console.log('Customer viewed:', product.productName);
49
+ });
50
+
51
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
52
+ // Product was added to cart - this is a conversion!
53
+ const product = event.detail.data;
54
+ console.log('SALE OPPORTUNITY:', product.productName, '$' + product.price);
55
+ });
56
+ ```
57
+
58
+ **🛒 Recover Abandoned Carts**
59
+ ```javascript
60
+ // Detect when someone opens cart but doesn't buy
61
+ window.addEventListener('lce:actions.cart_opened', function(event) {
62
+ // Start a timer - if they don't complete purchase in 10 minutes, send email
63
+ setTimeout(function() {
64
+ sendAbandonedCartEmail();
65
+ }, 10 * 60 * 1000); // 10 minutes
66
+ });
67
+
68
+ window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
69
+ // They bought! Cancel the abandoned cart email
70
+ cancelAbandonedCartEmail();
71
+ });
72
+ ```
73
+
74
+ **💰 Maximize Revenue**
75
+ ```javascript
76
+ // Offer upsells when they add expensive items
77
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
78
+ const product = event.detail.data;
79
+
80
+ if (product.price > 100) {
81
+ // Show them complementary products
82
+ showUpsellPopup(product.productId);
83
+ }
84
+ });
85
+ ```
86
+
87
+ ## Step 2: Complete Event List & What They Mean
88
+
89
+ ### 🚀 SDK Lifecycle Events
90
+ ```javascript
91
+ // When SDK is ready to use
92
+ 'lce:actions.client_ready' // → "SDK is initialized and ready to use"
93
+ ```
94
+
95
+ **Example Usage:**
96
+ ```javascript
97
+ window.addEventListener('lce:actions.client_ready', function(event) {
98
+ const { isReady, message, timestamp, version } = event.detail.data;
99
+ console.log('SDK Ready:', version);
100
+ // Now safe to call SDK methods
101
+ });
102
+ ```
103
+
104
+ ### 🛍️ Product Events (Track Customer Interest)
105
+ ```javascript
106
+ // When a customer views a product
107
+ 'lce:actions.product_loaded' // → "Customer is interested in this product"
108
+
109
+ // When they add to cart
110
+ 'lce:actions.product_add_to_cart' // → "Hot lead! Customer wants to buy"
111
+
112
+ // When they change quantity
113
+ 'lce:actions.product_quantity_increase' // → "Customer wants more"
114
+ 'lce:actions.product_quantity_decrease' // → "Customer wants less"
115
+
116
+ // When they change options
117
+ 'lce:actions.product_size_changed' // → "Customer has size preferences"
118
+ 'lce:actions.product_fulfillment_type_changed' // → "Delivery preference changed"
119
+ 'lce:actions.product_fulfillment_changed' // → "Customer selected specific retailer/fulfillment"
120
+ ```
121
+
122
+ **Note on Personalization:** Product personalization (engraving) is added during the add-to-cart action. The personalization is included in the `product_add_to_cart` event data. Once in cart, use `cart_item_engraving_updated` to track changes.
123
+
124
+ ### 🛒 Cart Events (Track Purchase Intent)
125
+ ```javascript
126
+ // Cart lifecycle
127
+ 'lce:actions.cart_loaded' // → "Cart data has been loaded and is ready"
128
+ 'lce:actions.cart_opened' // → "Customer is reviewing their purchase"
129
+ 'lce:actions.cart_closed' // → "Customer might be comparison shopping"
130
+
131
+ // Cart changes
132
+ 'lce:actions.cart_updated' // → "Customer modified their order"
133
+ 'lce:actions.cart_reset' // → "Customer cleared everything - intervention needed!"
134
+ 'lce:actions.cart_failed' // → "Cart operation failed"
135
+
136
+ // Item management
137
+ 'lce:actions.cart_item_added' // → "Customer committed to another product"
138
+ 'lce:actions.cart_item_removed' // → "Customer changed their mind"
139
+ 'lce:actions.cart_item_quantity_increase' // → "Customer added more of an item"
140
+ 'lce:actions.cart_item_quantity_decrease' // → "Customer reduced item quantity"
141
+ 'lce:actions.cart_item_engraving_updated' // → "Customer updated/removed item personalization"
142
+ ```
143
+
144
+ **Personalization Events:**
145
+ ```javascript
146
+ // Track when customers add or modify personalization
147
+ window.addEventListener('lce:actions.cart_item_engraving_updated', function(event) {
148
+ const { identifier, engravingLines, hasEngraving } = event.detail.data;
149
+
150
+ if (hasEngraving && engravingLines.length > 0) {
151
+ console.log(`Personalization added/updated: ${engravingLines.join(', ')}`);
152
+ } else {
153
+ console.log('Personalization removed from item');
154
+ }
155
+ });
156
+ ```
157
+
158
+ ### 💳 Checkout Events (Track Purchase Process)
159
+ ```javascript
160
+ // Checkout lifecycle
161
+ 'lce:actions.checkout_loaded' // → "Checkout data has been loaded and is ready"
162
+ 'lce:actions.checkout_opened' // → "Customer is ready to buy!"
163
+ 'lce:actions.checkout_closed' // → "Customer left checkout"
164
+ 'lce:actions.checkout_failed' // → "Checkout operation failed"
165
+
166
+ // Checkout submission
167
+ 'lce:actions.checkout_submit_started' // → "Payment processing..."
168
+ 'lce:actions.checkout_submit_completed' // → "SALE COMPLETED! 🎉"
169
+ 'lce:actions.checkout_submit_failed' // → "Sale lost - fix the issue!"
170
+
171
+ // Form updates
172
+ 'lce:actions.checkout_customer_information_updated' // → "Customer filling out details"
173
+ 'lce:actions.checkout_billing_information_updated' // → "Payment info being entered"
174
+ 'lce:actions.checkout_gift_information_updated' // → "Gift recipient info updated"
175
+
176
+ // Checkout options
177
+ 'lce:actions.checkout_is_gift_toggled' // → "Customer toggled gift option"
178
+ 'lce:actions.checkout_billing_same_as_shipping_toggled' // → "Customer toggled billing address option"
179
+ 'lce:actions.checkout_marketing_preferences_toggled' // → "Customer updated marketing preferences"
180
+
181
+ // Item management in checkout
182
+ 'lce:actions.checkout_item_removed' // → "Customer removed item from checkout"
183
+ 'lce:actions.checkout_item_quantity_increase' // → "Customer increased item quantity in checkout"
184
+ 'lce:actions.checkout_item_quantity_decrease' // → "Customer decreased item quantity in checkout"
185
+ 'lce:actions.checkout_item_engraving_updated' // → "Customer removed personalization in checkout"
186
+
187
+ // Tips (for on-demand delivery)
188
+ 'lce:actions.checkout_tip_updated' // → "Customer updated delivery tip"
189
+ ```
190
+
191
+ **Important Note on Checkout Personalization:**
192
+ Personalization cannot be edited during checkout - only removed. This is by design to prevent order processing complications. If a customer wants to modify personalization, they must return to the cart. The checkout only displays personalization details and provides a remove option.
193
+
194
+ ### 📍 Address Events (Track Shipping Preferences)
195
+ ```javascript
196
+ 'lce:actions.address_updated' // → "Customer entered shipping address"
197
+ 'lce:actions.address_cleared' // → "Customer removed address"
198
+ 'lce:actions.address_failed' // → "Address validation failed"
199
+ ```
200
+
201
+ ### 🔔 **NEW: Action Feedback Events** (Track Action Success/Failure)
202
+
203
+ These events fire when programmatic actions succeed or fail, giving you complete control over user feedback:
204
+
205
+ #### 🛒 **Cart Action Feedback**
206
+ ```javascript
207
+ // Product addition feedback
208
+ 'lce:actions.cart_product_add_success' // → "Products successfully added to cart"
209
+ // Data: { itemsAdded: number, identifiers: string[] }
210
+
211
+ 'lce:actions.cart_product_add_failed' // → "Products could not be added to cart"
212
+ // Data: { identifiers: string[], error: string }
213
+
214
+ // Promo code feedback
215
+ 'lce:actions.cart_promo_code_applied' // → "Promo code worked - show success!"
216
+ // Data: { applied: true, discountAmount?: number, newTotal?: number }
217
+
218
+ 'lce:actions.cart_promo_code_removed' // → "Promo code removed successfully"
219
+ // Data: { applied: false }
220
+
221
+ 'lce:actions.cart_promo_code_failed' // → "Promo code didn't work - show error"
222
+ // Data: { attempted: true, error: string }
223
+ ```
224
+
225
+ #### 💳 **Checkout Action Feedback**
226
+ ```javascript
227
+ // Product addition feedback
228
+ 'lce:actions.checkout_product_add_success' // → "Products added to checkout successfully"
229
+ // Data: { itemsAdded: number, identifiers: string[] }
230
+
231
+ 'lce:actions.checkout_product_add_failed' // → "Could not add products to checkout"
232
+ // Data: { identifiers: string[], error: string }
233
+
234
+ // Promo code feedback
235
+ 'lce:actions.checkout_promo_code_applied' // → "Checkout discount applied!"
236
+ // Data: { applied: true, discountAmount?: number, newTotal?: number }
237
+
238
+ 'lce:actions.checkout_promo_code_removed' // → "Checkout discount removed"
239
+ // Data: { applied: false }
240
+
241
+ 'lce:actions.checkout_promo_code_failed' // → "Checkout discount failed"
242
+ // Data: { attempted: true, error: string }
243
+
244
+ // Gift card feedback
245
+ 'lce:actions.checkout_gift_card_applied' // → "Gift card applied successfully!"
246
+ // Data: { applied: true, newTotal?: number }
247
+
248
+ 'lce:actions.checkout_gift_card_removed' // → "Gift card removed"
249
+ // Data: { applied: false }
250
+
251
+ 'lce:actions.checkout_gift_card_failed' // → "Gift card could not be applied"
252
+ // Data: { attempted: true, error: string }
253
+ ```
254
+
255
+ #### 🔒 **Security Note**
256
+ Action feedback events **never expose sensitive information** like promo codes or gift card codes. This prevents malicious scripts from stealing sensitive data while still providing rich feedback for legitimate developers.
257
+
258
+ **Example: Secure Action Feedback**
259
+ ```javascript
260
+ // Fire the action (simple)
261
+ await actions.cart.applyPromoCode('SECRET20');
262
+
263
+ // Get feedback (secure)
264
+ window.addEventListener('lce:actions.cart_promo_code_applied', function(event) {
265
+ const { applied, discountAmount, newTotal } = event.detail.data;
266
+ // ✅ You get: success status, discount amount, new total
267
+ // 🚫 You DON'T get: 'SECRET20' (secure!)
268
+
269
+ showSuccessMessage(`🎉 Discount applied! You saved $${discountAmount}!`);
270
+ updateCartTotal(newTotal);
271
+ });
272
+ ```
273
+
274
+ ## Step 3: Real-World Implementation Examples
275
+
276
+ ### 🔔 **NEW Example: Smart Action Feedback with Perfect UX**
277
+ ```javascript
278
+ // Perfect promo code experience with action feedback
279
+ async function applyPromoCodeWithFeedback(code) {
280
+ // Show loading state
281
+ showLoadingMessage('Applying promo code...');
282
+
283
+ // Set up event listeners BEFORE firing action
284
+ const successHandler = (event) => {
285
+ const { applied, discountAmount, newTotal } = event.detail.data;
286
+ hideLoadingMessage();
287
+ showSuccessMessage(`🎉 Success! You saved $${discountAmount}!`);
288
+ updatePriceDisplay(newTotal);
289
+
290
+ // Track successful promo usage
291
+ analytics.track('Promo Applied', {
292
+ discount: discountAmount,
293
+ newTotal: newTotal
294
+ });
295
+
296
+ // Clean up
297
+ cleanup();
298
+ };
299
+
300
+ const failureHandler = (event) => {
301
+ const { attempted, error } = event.detail.data;
302
+ hideLoadingMessage();
303
+ showErrorMessage('Promo code could not be applied. Please try again.');
304
+
305
+ // Track failed attempts (for optimization)
306
+ analytics.track('Promo Failed', { error: error });
307
+
308
+ // Maybe suggest alternatives
309
+ suggestAlternativePromos();
310
+
311
+ // Clean up
312
+ cleanup();
313
+ };
314
+
315
+ const cleanup = () => {
316
+ window.removeEventListener('lce:actions.cart_promo_code_applied', successHandler);
317
+ window.removeEventListener('lce:actions.cart_promo_code_failed', failureHandler);
318
+ };
319
+
320
+ // Attach listeners
321
+ window.addEventListener('lce:actions.cart_promo_code_applied', successHandler);
322
+ window.addEventListener('lce:actions.cart_promo_code_failed', failureHandler);
323
+
324
+ // Fire the action
325
+ await actions.cart.applyPromoCode(code);
326
+ }
327
+
328
+ // Usage: Perfect UX every time!
329
+ applyPromoCodeWithFeedback('SAVE20');
330
+ ```
331
+
332
+ ### 🎯 Example 1: Boost Your Sales with Smart Promotions
333
+ ```javascript
334
+ // Automatically offer discounts for high-value carts
335
+ window.addEventListener('lce:actions.cart_updated', function(event) {
336
+ const cart = event.detail.data;
337
+
338
+ if (cart.total > 200 && !cart.hasPromoCode) {
339
+ // Show them a 10% off popup
340
+ showPopup("Get 10% off orders over $200! Use code: SAVE10");
341
+ }
342
+ });
343
+
344
+ // Track which products make people abandon checkout
345
+ window.addEventListener('lce:actions.checkout_opened', function(event) {
346
+ window.checkoutStartTime = new Date();
347
+ });
348
+
349
+ window.addEventListener('lce:actions.checkout_closed', function(event) {
350
+ // If they close checkout without buying, they abandoned
351
+ if (window.checkoutStartTime) {
352
+ const timeSpent = new Date() - window.checkoutStartTime;
353
+ console.log('Checkout abandoned after', timeSpent/1000, 'seconds');
354
+ // Send this data to your analytics to find problem products
355
+ }
356
+ });
357
+ ```
358
+
359
+ ### 📧 Example 2: Automated Email Marketing
360
+ ```javascript
361
+ // Build an email list from cart abandoners
362
+ window.addEventListener('lce:actions.cart_opened', function(event) {
363
+ // Customer opened cart - start tracking
364
+ window.cartOpenTime = new Date();
365
+ window.cartItems = event.detail.data.items;
366
+ });
367
+
368
+ window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
369
+ // They bought! No need for abandonment email
370
+ window.cartOpenTime = null;
371
+ });
372
+
373
+ // Check every 5 minutes if cart was abandoned
374
+ setInterval(function() {
375
+ if (window.cartOpenTime) {
376
+ const timeSinceOpen = new Date() - window.cartOpenTime;
377
+ if (timeSinceOpen > 15 * 60 * 1000) { // 15 minutes
378
+ // Send abandonment email with cart items
379
+ sendAbandonmentEmail(window.cartItems);
380
+ window.cartOpenTime = null; // Don't send again
381
+ }
382
+ }
383
+ }, 5 * 60 * 1000);
384
+ ```
385
+
386
+ ### 📊 Example 3: Track Your Best-Performing Products
387
+ ```javascript
388
+ // Keep a running tally of product performance
389
+ let productStats = {};
390
+
391
+ window.addEventListener('lce:actions.product_loaded', function(event) {
392
+ const product = event.detail.data;
393
+
394
+ // Initialize stats if first time seeing this product
395
+ if (!productStats[product.productId]) {
396
+ productStats[product.productId] = {
397
+ name: product.productName,
398
+ views: 0,
399
+ addedToCarts: 0,
400
+ conversions: 0
401
+ };
402
+ }
403
+
404
+ productStats[product.productId].views++;
405
+ });
406
+
407
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
408
+ const product = event.detail.data;
409
+ productStats[product.productId].addedToCarts++;
410
+ });
411
+
412
+ window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
413
+ const order = event.detail.data;
414
+
415
+ // Mark all purchased products as conversions
416
+ order.items.forEach(function(item) {
417
+ if (productStats[item.productId]) {
418
+ productStats[item.productId].conversions++;
419
+ }
420
+ });
421
+
422
+ // Send stats to your analytics dashboard
423
+ console.log('Product Performance:', productStats);
424
+ });
425
+ ```
426
+
427
+ ### 🔥 Example 4: Create Urgency with Live Updates
428
+ ```javascript
429
+ // Show live activity to create FOMO (Fear of Missing Out)
430
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
431
+ const product = event.detail.data;
432
+
433
+ // Show notification to other visitors
434
+ showNotification(`Someone just bought ${product.productName}! Only 3 left!`);
435
+
436
+ // Update inventory count on the page
437
+ updateInventoryDisplay(product.productId, -1);
438
+ });
439
+
440
+ window.addEventListener('lce:actions.cart_opened', function(event) {
441
+ // Show how many people are currently viewing this product
442
+ showViewerCount("👀 5 people are looking at this right now");
443
+ });
444
+ ```
445
+
446
+ ## Common Use Cases & How to Implement
447
+
448
+ ### 🛒 **Cart Abandonment Recovery**
449
+ **The Problem**: 70% of carts are abandoned
450
+ **The Solution**: Automatic follow-up based on events
451
+
452
+ ```javascript
453
+ // Set up cart abandonment tracking
454
+ let abandonmentTimer;
455
+
456
+ window.addEventListener('lce:actions.cart_opened', function() {
457
+ // Reset timer each time they open cart
458
+ clearTimeout(abandonmentTimer);
459
+
460
+ abandonmentTimer = setTimeout(function() {
461
+ // After 30 minutes of inactivity, trigger recovery
462
+ triggerCartRecovery();
463
+ }, 30 * 60 * 1000);
464
+ });
465
+
466
+ window.addEventListener('lce:actions.checkout_submit_completed', function() {
467
+ // They completed purchase - cancel recovery
468
+ clearTimeout(abandonmentTimer);
469
+ });
470
+
471
+ function triggerCartRecovery() {
472
+ // Send email, show popup, etc.
473
+ console.log("Time to recover this cart!");
474
+ }
475
+ ```
476
+
477
+ ### 📈 **Revenue Optimization**
478
+ **The Goal**: Increase average order value
479
+ **The Method**: Smart upselling based on behavior
480
+
481
+ ```javascript
482
+ window.addEventListener('lce:actions.product_add_to_cart', function(event) {
483
+ const product = event.detail.data;
484
+
485
+ // If they added a phone, suggest a case
486
+ if (product.category === 'phones') {
487
+ showUpsell('phone-cases');
488
+ }
489
+
490
+ // If cart total is close to free shipping, tell them
491
+ if (cart.total > 45 && cart.total < 50) {
492
+ showMessage("Add $" + (50 - cart.total) + " more for FREE shipping!");
493
+ }
494
+ });
495
+ ```
496
+
497
+ ### 🎯 **Conversion Tracking**
498
+ **The Need**: Measure what's working
499
+ **The Implementation**: Track the entire funnel
500
+
501
+ ```javascript
502
+ // Track the complete conversion funnel
503
+ const funnelSteps = {
504
+ productView: 0,
505
+ addToCart: 0,
506
+ cartView: 0,
507
+ checkoutStart: 0,
508
+ purchase: 0
509
+ };
510
+
511
+ window.addEventListener('lce:actions.product_loaded', () => funnelSteps.productView++);
512
+ window.addEventListener('lce:actions.product_add_to_cart', () => funnelSteps.addToCart++);
513
+ window.addEventListener('lce:actions.cart_opened', () => funnelSteps.cartView++);
514
+ window.addEventListener('lce:actions.checkout_opened', () => funnelSteps.checkoutStart++);
515
+ window.addEventListener('lce:actions.checkout_submit_completed', () => funnelSteps.purchase++);
516
+
517
+ // Send to your analytics every 10 minutes
518
+ setInterval(() => {
519
+ console.log('Conversion Funnel:', funnelSteps);
520
+ // Send to your dashboard/analytics
521
+ }, 10 * 60 * 1000);
522
+ ```
523
+
524
+ ## Getting Started in 5 Minutes
525
+
526
+ 1. **Pick one goal** from the examples above
527
+ 2. **Copy the code** into your website
528
+ 3. **Replace the console.log** with your actual actions (send email, show popup, etc.)
529
+ 4. **Test it** by going through the flow yourself
530
+ 5. **Monitor the results** and adjust as needed
531
+
532
+ **Need help?** The events automatically work once LiquidCommerce Elements are on your page. Just add the JavaScript code and you're ready to go!