@liquidcommerce/elements-sdk 2.3.0 → 2.4.1
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/README.md +25 -21
- package/dist/index.esm.js +8543 -8169
- package/dist/types/core/client/client-action.service.d.ts +2 -2
- package/dist/types/core/google-tag-manager.service.d.ts +1 -0
- package/dist/types/core/pubsub/interfaces/cart.interface.d.ts +1 -0
- package/dist/types/core/pubsub/interfaces/checkout.interface.d.ts +44 -6
- package/dist/types/core/pubsub/interfaces/product.interface.d.ts +43 -1
- package/dist/types/core/store/interfaces/cart.interface.d.ts +1 -0
- package/dist/types/core/store/interfaces/product.interface.d.ts +18 -6
- package/dist/types/interfaces/cloud/product.interface.d.ts +2 -0
- package/dist/types/modules/cart/components/cart-footer.component.d.ts +1 -0
- package/dist/types/modules/cart/components/cart-item.component.d.ts +1 -0
- package/dist/types/modules/checkout/components/checkout-summary-section.component.d.ts +2 -0
- package/dist/types/modules/checkout/components/summary/checkout-items.component.d.ts +1 -0
- package/dist/types/modules/ui-components/engraving/engraving-view.component.d.ts +1 -0
- package/docs/ACTIONS.md +1237 -0
- package/docs/BROWSER_SUPPORT.md +279 -0
- package/docs/CONFIGURATION.md +613 -0
- package/docs/DOCUMENTATION_INDEX.md +311 -0
- package/docs/EVENTS.md +765 -0
- package/docs/PROXY.md +228 -0
- package/docs/THEMING.md +592 -0
- package/docs/TROUBLESHOOTING.md +755 -0
- package/package.json +10 -7
- package/umd/elements.js +1 -1
package/docs/EVENTS.md
ADDED
|
@@ -0,0 +1,765 @@
|
|
|
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 data = event.detail.data;
|
|
25
|
+
|
|
26
|
+
// Maybe send them a discount popup
|
|
27
|
+
showDiscountPopup(data.identifier);
|
|
28
|
+
|
|
29
|
+
// Or track in your analytics
|
|
30
|
+
analytics.track('Product Added', {
|
|
31
|
+
identifier: data.identifier,
|
|
32
|
+
quantity: data.quantity,
|
|
33
|
+
upc: data.upc
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Implementation Guide
|
|
39
|
+
|
|
40
|
+
### Step 1: Choose Your Goal
|
|
41
|
+
What do you want to achieve? Pick one:
|
|
42
|
+
|
|
43
|
+
**🎯 Track Sales Performance**
|
|
44
|
+
```javascript
|
|
45
|
+
// Track when products are viewed and added to cart
|
|
46
|
+
window.addEventListener('lce:actions.product_loaded', function(event) {
|
|
47
|
+
// Product was viewed - track in your analytics
|
|
48
|
+
const product = event.detail.data;
|
|
49
|
+
console.log('Customer viewed:', product.name);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
53
|
+
// Product was added to cart - this is a conversion!
|
|
54
|
+
const data = event.detail.data;
|
|
55
|
+
console.log('SALE OPPORTUNITY:', data.identifier, 'qty:', data.quantity);
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**🛒 Recover Abandoned Carts**
|
|
60
|
+
```javascript
|
|
61
|
+
// Detect when someone opens cart but doesn't buy
|
|
62
|
+
window.addEventListener('lce:actions.cart_opened', function(event) {
|
|
63
|
+
// Start a timer - if they don't complete purchase in 10 minutes, send email
|
|
64
|
+
setTimeout(function() {
|
|
65
|
+
sendAbandonedCartEmail();
|
|
66
|
+
}, 10 * 60 * 1000); // 10 minutes
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
|
|
70
|
+
// They bought! Cancel the abandoned cart email
|
|
71
|
+
cancelAbandonedCartEmail();
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**💰 Maximize Revenue**
|
|
76
|
+
```javascript
|
|
77
|
+
// Offer upsells when they add expensive items
|
|
78
|
+
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
79
|
+
const data = event.detail.data;
|
|
80
|
+
|
|
81
|
+
// Trigger upsell based on product identifier
|
|
82
|
+
showUpsellPopup(data.identifier);
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Step 2: Complete Event List & What They Mean
|
|
87
|
+
|
|
88
|
+
### 🚀 SDK Lifecycle Events
|
|
89
|
+
```javascript
|
|
90
|
+
// When SDK is ready to use
|
|
91
|
+
'lce:actions.client_ready' // → "SDK is initialized and ready to use"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Example Usage:**
|
|
95
|
+
```javascript
|
|
96
|
+
window.addEventListener('lce:actions.client_ready', function(event) {
|
|
97
|
+
const { isReady, message, timestamp, version } = event.detail.data;
|
|
98
|
+
console.log('SDK Ready:', version);
|
|
99
|
+
// Now safe to call SDK methods
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 🛍️ Product Events (Track Customer Interest)
|
|
104
|
+
```javascript
|
|
105
|
+
// When a customer views a product
|
|
106
|
+
'lce:actions.product_loaded' // → "Customer is interested in this product"
|
|
107
|
+
|
|
108
|
+
// When they add to cart
|
|
109
|
+
'lce:actions.product_add_to_cart' // → "Hot lead! Customer wants to buy"
|
|
110
|
+
|
|
111
|
+
// When they change quantity
|
|
112
|
+
'lce:actions.product_quantity_increase' // → "Customer wants more"
|
|
113
|
+
'lce:actions.product_quantity_decrease' // → "Customer wants less"
|
|
114
|
+
|
|
115
|
+
// When they change options
|
|
116
|
+
'lce:actions.product_size_changed' // → "Customer has size preferences"
|
|
117
|
+
'lce:actions.product_fulfillment_type_changed' // → "Delivery preference changed"
|
|
118
|
+
'lce:actions.product_fulfillment_changed' // → "Customer selected specific retailer/fulfillment"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**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.
|
|
122
|
+
|
|
123
|
+
#### Product Details Event Data
|
|
124
|
+
When `lce:actions.product_loaded` fires, you get comprehensive product information:
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
window.addEventListener('lce:actions.product_loaded', function(event) {
|
|
128
|
+
const product = event.detail.data;
|
|
129
|
+
|
|
130
|
+
// Basic Information
|
|
131
|
+
console.log(product.id); // Product ID
|
|
132
|
+
console.log(product.name); // Product name
|
|
133
|
+
console.log(product.brand); // Brand name
|
|
134
|
+
console.log(product.category); // Category
|
|
135
|
+
console.log(product.catPath); // Category path
|
|
136
|
+
console.log(product.classification); // Product classification
|
|
137
|
+
console.log(product.type); // Product type
|
|
138
|
+
console.log(product.subType); // Product sub-type
|
|
139
|
+
console.log(product.salsifyGrouping); // Salsify grouping ID
|
|
140
|
+
|
|
141
|
+
// Visual Assets
|
|
142
|
+
console.log(product.mainImage); // Main product image URL
|
|
143
|
+
console.log(product.images); // Array of all product images
|
|
144
|
+
|
|
145
|
+
// Product Attributes
|
|
146
|
+
console.log(product.region); // Region (e.g., "Napa Valley")
|
|
147
|
+
console.log(product.country); // Country of origin
|
|
148
|
+
console.log(product.material); // Material type
|
|
149
|
+
console.log(product.abv); // Alcohol by volume
|
|
150
|
+
console.log(product.proof); // Proof
|
|
151
|
+
console.log(product.age); // Age statement
|
|
152
|
+
console.log(product.color); // Color description
|
|
153
|
+
console.log(product.flavor); // Flavor profile
|
|
154
|
+
console.log(product.variety); // Variety (e.g., "Cabernet Sauvignon")
|
|
155
|
+
console.log(product.appellation); // Appellation
|
|
156
|
+
console.log(product.vintage); // Vintage year
|
|
157
|
+
|
|
158
|
+
// Descriptions
|
|
159
|
+
console.log(product.description); // Plain text description
|
|
160
|
+
console.log(product.htmlDescription); // HTML formatted description
|
|
161
|
+
console.log(product.tastingNotes); // Tasting notes
|
|
162
|
+
|
|
163
|
+
// Pricing
|
|
164
|
+
console.log(product.priceInfo); // { min, max, avg } pricing across fulfillments
|
|
165
|
+
|
|
166
|
+
// Available Sizes & Fulfillments
|
|
167
|
+
console.log(product.sizes); // All available sizes with fulfillment options
|
|
168
|
+
console.log(product.selectedSizeId); // Currently selected size
|
|
169
|
+
console.log(product.selectedFulfillmentId); // Currently selected fulfillment
|
|
170
|
+
console.log(product.selectedFulfillmentType); // 'shipping' or 'onDemand'
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Use Cases:**
|
|
175
|
+
- **Rich Analytics**: Track which product attributes drive conversions
|
|
176
|
+
- **Personalized Recommendations**: Suggest similar products based on variety, region, or flavor
|
|
177
|
+
- **Content Display**: Show detailed product information on your custom UI
|
|
178
|
+
- **Search & Filtering**: Build custom search based on product attributes
|
|
179
|
+
|
|
180
|
+
### 🛒 Cart Events (Track Purchase Intent)
|
|
181
|
+
```javascript
|
|
182
|
+
// Cart lifecycle
|
|
183
|
+
'lce:actions.cart_loaded' // → "Cart data has been loaded and is ready"
|
|
184
|
+
'lce:actions.cart_opened' // → "Customer is reviewing their purchase"
|
|
185
|
+
'lce:actions.cart_closed' // → "Customer might be comparison shopping"
|
|
186
|
+
|
|
187
|
+
// Cart changes
|
|
188
|
+
'lce:actions.cart_updated' // → "Customer modified their order"
|
|
189
|
+
'lce:actions.cart_reset' // → "Customer cleared everything - intervention needed!"
|
|
190
|
+
'lce:actions.cart_failed' // → "Cart operation failed"
|
|
191
|
+
|
|
192
|
+
// Item management
|
|
193
|
+
'lce:actions.cart_item_added' // → "Customer committed to another product"
|
|
194
|
+
'lce:actions.cart_item_removed' // → "Customer changed their mind"
|
|
195
|
+
'lce:actions.cart_item_quantity_increase' // → "Customer added more of an item"
|
|
196
|
+
'lce:actions.cart_item_quantity_decrease' // → "Customer reduced item quantity"
|
|
197
|
+
'lce:actions.cart_item_engraving_updated' // → "Customer updated/removed item personalization"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Personalization Events:**
|
|
201
|
+
```javascript
|
|
202
|
+
// Track when customers add or modify personalization
|
|
203
|
+
window.addEventListener('lce:actions.cart_item_engraving_updated', function(event) {
|
|
204
|
+
const { identifier, engravingLines, hasEngraving } = event.detail.data;
|
|
205
|
+
|
|
206
|
+
if (hasEngraving && engravingLines.length > 0) {
|
|
207
|
+
console.log(`Personalization added/updated: ${engravingLines.join(', ')}`);
|
|
208
|
+
} else {
|
|
209
|
+
console.log('Personalization removed from item');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Cart Details Event Data
|
|
215
|
+
When `lce:actions.cart_loaded` or `lce:actions.cart_updated` fires, you get complete cart information:
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
window.addEventListener('lce:actions.cart_loaded', function(event) {
|
|
219
|
+
const cart = event.detail.data;
|
|
220
|
+
|
|
221
|
+
// Cart Identification
|
|
222
|
+
console.log(cart.id); // Cart ID
|
|
223
|
+
console.log(cart.promoCode); // Applied promo code (if any)
|
|
224
|
+
|
|
225
|
+
// Cart Items
|
|
226
|
+
console.log(cart.items); // Object with all cart items
|
|
227
|
+
console.log(cart.itemCount); // Total number of items in cart
|
|
228
|
+
|
|
229
|
+
// Each item contains:
|
|
230
|
+
Object.values(cart.items).forEach(item => {
|
|
231
|
+
console.log(item.id); // Cart item ID
|
|
232
|
+
console.log(item.name); // Product name
|
|
233
|
+
console.log(item.brand); // Brand
|
|
234
|
+
console.log(item.salsifyGrouping); // Salsify grouping ID
|
|
235
|
+
console.log(item.catPath); // Category path
|
|
236
|
+
console.log(item.size); // Size description
|
|
237
|
+
console.log(item.volume); // Volume
|
|
238
|
+
console.log(item.uom); // Unit of measure
|
|
239
|
+
console.log(item.pack); // Is pack (boolean)
|
|
240
|
+
console.log(item.packDesc); // Pack description
|
|
241
|
+
console.log(item.container); // Container type
|
|
242
|
+
console.log(item.containerType); // Container type classification
|
|
243
|
+
console.log(item.price); // Total price (unitPrice × quantity)
|
|
244
|
+
console.log(item.unitPrice); // Price per unit
|
|
245
|
+
console.log(item.quantity); // Quantity
|
|
246
|
+
console.log(item.maxQuantity); // Maximum allowed quantity
|
|
247
|
+
console.log(item.mainImage); // Product image URL
|
|
248
|
+
console.log(item.upc); // UPC code
|
|
249
|
+
console.log(item.sku); // SKU
|
|
250
|
+
console.log(item.partNumber); // Part number
|
|
251
|
+
console.log(item.retailerId); // Retailer ID
|
|
252
|
+
console.log(item.fulfillmentId); // Fulfillment ID
|
|
253
|
+
console.log(item.attributes); // Item attributes (engraving, etc.)
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Location Information
|
|
257
|
+
console.log(cart.location.placesId); // Google Places ID
|
|
258
|
+
console.log(cart.location.address); // Address object
|
|
259
|
+
console.log(cart.location.coordinates); // Lat/long coordinates
|
|
260
|
+
|
|
261
|
+
// Financial Breakdown
|
|
262
|
+
console.log(cart.amounts.subtotal); // Subtotal
|
|
263
|
+
console.log(cart.amounts.deliveryFee); // Delivery fee
|
|
264
|
+
console.log(cart.amounts.shippingFee); // Shipping fee
|
|
265
|
+
console.log(cart.amounts.platformFee); // Platform fee
|
|
266
|
+
console.log(cart.amounts.engravingFee); // Engraving/personalization fee
|
|
267
|
+
console.log(cart.amounts.discounts); // Total discounts
|
|
268
|
+
console.log(cart.amounts.giftCardTotal); // Gift card total applied
|
|
269
|
+
console.log(cart.amounts.total); // Final total
|
|
270
|
+
|
|
271
|
+
// Timestamps
|
|
272
|
+
console.log(cart.createdAt); // When cart was created
|
|
273
|
+
console.log(cart.updatedAt); // Last update timestamp
|
|
274
|
+
});
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Use Cases:**
|
|
278
|
+
- **Abandoned Cart Recovery**: Track cart value and items for targeted recovery campaigns
|
|
279
|
+
- **Revenue Analytics**: Monitor average cart value, most popular items, cart composition
|
|
280
|
+
- **Inventory Management**: Track which products are frequently added/removed
|
|
281
|
+
- **Pricing Analysis**: Analyze impact of fees, discounts, and gift cards on cart totals
|
|
282
|
+
|
|
283
|
+
### 💳 Checkout Events (Track Purchase Process)
|
|
284
|
+
```javascript
|
|
285
|
+
// Checkout lifecycle
|
|
286
|
+
'lce:actions.checkout_loaded' // → "Checkout data has been loaded and is ready"
|
|
287
|
+
'lce:actions.checkout_opened' // → "Customer is ready to buy!"
|
|
288
|
+
'lce:actions.checkout_closed' // → "Customer left checkout"
|
|
289
|
+
'lce:actions.checkout_failed' // → "Checkout operation failed"
|
|
290
|
+
|
|
291
|
+
// Checkout submission
|
|
292
|
+
'lce:actions.checkout_submit_started' // → "Payment processing..."
|
|
293
|
+
'lce:actions.checkout_submit_completed' // → "SALE COMPLETED! 🎉"
|
|
294
|
+
'lce:actions.checkout_submit_failed' // → "Sale lost - fix the issue!"
|
|
295
|
+
|
|
296
|
+
// Form updates
|
|
297
|
+
'lce:actions.checkout_customer_information_updated' // → "Customer filling out details"
|
|
298
|
+
'lce:actions.checkout_billing_information_updated' // → "Payment info being entered"
|
|
299
|
+
'lce:actions.checkout_gift_information_updated' // → "Gift recipient info updated"
|
|
300
|
+
|
|
301
|
+
// Checkout options
|
|
302
|
+
'lce:actions.checkout_is_gift_toggled' // → "Customer toggled gift option"
|
|
303
|
+
'lce:actions.checkout_billing_same_as_shipping_toggled' // → "Customer toggled billing address option"
|
|
304
|
+
'lce:actions.checkout_marketing_preferences_toggled' // → "Customer updated marketing preferences"
|
|
305
|
+
|
|
306
|
+
// Item management in checkout
|
|
307
|
+
'lce:actions.checkout_item_removed' // → "Customer removed item from checkout"
|
|
308
|
+
'lce:actions.checkout_item_quantity_increase' // → "Customer increased item quantity in checkout"
|
|
309
|
+
'lce:actions.checkout_item_quantity_decrease' // → "Customer decreased item quantity in checkout"
|
|
310
|
+
'lce:actions.checkout_item_engraving_updated' // → "Customer removed personalization in checkout"
|
|
311
|
+
|
|
312
|
+
// Tips (for on-demand delivery)
|
|
313
|
+
'lce:actions.checkout_tip_updated' // → "Customer updated delivery tip"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Important Note on Checkout Personalization:**
|
|
317
|
+
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.
|
|
318
|
+
|
|
319
|
+
#### Checkout Details Event Data
|
|
320
|
+
When you call `actions.checkout.getDetails()`, you get comprehensive checkout information:
|
|
321
|
+
|
|
322
|
+
**Note:** The `lce:actions.checkout_loaded` event only contains `{ cartId: string }`. To get full checkout details, use `actions.checkout.getDetails()`.
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
// Get full checkout details via action
|
|
326
|
+
const checkout = actions.checkout.getDetails();
|
|
327
|
+
|
|
328
|
+
// Checkout Identification
|
|
329
|
+
console.log(checkout.cartId); // Associated cart ID
|
|
330
|
+
|
|
331
|
+
// Checkout Status Flags
|
|
332
|
+
console.log(checkout.acceptedAccountCreation); // Customer accepted account creation
|
|
333
|
+
console.log(checkout.hasAgeVerify); // Age verification required
|
|
334
|
+
console.log(checkout.hasSubstitutionPolicy); // Substitution policy accepted
|
|
335
|
+
console.log(checkout.isGift); // Order is a gift
|
|
336
|
+
console.log(checkout.billingSameAsShipping); // Billing address same as shipping
|
|
337
|
+
console.log(checkout.hasPromoCode); // Promo code applied
|
|
338
|
+
console.log(checkout.hasGiftCards); // Gift cards applied
|
|
339
|
+
|
|
340
|
+
// Marketing Preferences
|
|
341
|
+
console.log(checkout.marketingPreferences.canEmail); // Email opt-in status
|
|
342
|
+
console.log(checkout.marketingPreferences.canSms); // SMS opt-in status
|
|
343
|
+
|
|
344
|
+
// Order Summary
|
|
345
|
+
console.log(checkout.itemCount); // Total items in checkout
|
|
346
|
+
|
|
347
|
+
// Financial Breakdown
|
|
348
|
+
console.log(checkout.amounts.subtotal); // Subtotal
|
|
349
|
+
console.log(checkout.amounts.deliveryFee); // Delivery fee
|
|
350
|
+
console.log(checkout.amounts.shippingFee); // Shipping fee
|
|
351
|
+
console.log(checkout.amounts.platformFee); // Platform fee
|
|
352
|
+
console.log(checkout.amounts.engravingFee); // Engraving/personalization fee
|
|
353
|
+
console.log(checkout.amounts.discounts); // Total discounts
|
|
354
|
+
console.log(checkout.amounts.giftCardTotal); // Gift card total applied
|
|
355
|
+
console.log(checkout.amounts.tax); // Tax amount
|
|
356
|
+
console.log(checkout.amounts.bottleDeposits); // Bottle deposit fees
|
|
357
|
+
console.log(checkout.amounts.total); // Final total
|
|
358
|
+
|
|
359
|
+
// Checkout Items (detailed product information)
|
|
360
|
+
console.log(checkout.items); // Object with all checkout items
|
|
361
|
+
|
|
362
|
+
// Each checkout item contains comprehensive details:
|
|
363
|
+
Object.values(checkout.items).forEach(item => {
|
|
364
|
+
console.log(item.cartItemId); // Cart item ID
|
|
365
|
+
console.log(item.liquidId); // Liquid ID
|
|
366
|
+
console.log(item.variantId); // Variant ID
|
|
367
|
+
console.log(item.name); // Product name
|
|
368
|
+
console.log(item.brand); // Brand
|
|
369
|
+
console.log(item.salsifyGrouping); // Salsify grouping ID
|
|
370
|
+
console.log(item.catPath); // Category path
|
|
371
|
+
|
|
372
|
+
// Size & Container Information
|
|
373
|
+
console.log(item.size); // Size description
|
|
374
|
+
console.log(item.volume); // Volume
|
|
375
|
+
console.log(item.uom); // Unit of measure
|
|
376
|
+
console.log(item.pack); // Is pack (boolean)
|
|
377
|
+
console.log(item.packDesc); // Pack description
|
|
378
|
+
console.log(item.container); // Container type
|
|
379
|
+
console.log(item.containerType); // Container type classification
|
|
380
|
+
|
|
381
|
+
// Product Attributes
|
|
382
|
+
console.log(item.proof); // Proof
|
|
383
|
+
console.log(item.abv); // Alcohol by volume
|
|
384
|
+
|
|
385
|
+
// Pricing
|
|
386
|
+
console.log(item.price); // Total price (unitPrice × quantity)
|
|
387
|
+
console.log(item.unitPrice); // Price per unit
|
|
388
|
+
console.log(item.unitTax); // Tax per unit
|
|
389
|
+
console.log(item.bottleDeposits); // Bottle deposit fees
|
|
390
|
+
console.log(item.quantity); // Quantity
|
|
391
|
+
|
|
392
|
+
// Identifiers
|
|
393
|
+
console.log(item.upc); // UPC code
|
|
394
|
+
console.log(item.sku); // SKU
|
|
395
|
+
console.log(item.partNumber); // Part number
|
|
396
|
+
|
|
397
|
+
// Fulfillment Information
|
|
398
|
+
console.log(item.retailerId); // Retailer ID
|
|
399
|
+
console.log(item.retailerName); // Retailer name
|
|
400
|
+
console.log(item.fulfillmentId); // Fulfillment ID
|
|
401
|
+
console.log(item.expectationDetail); // Delivery expectation details
|
|
402
|
+
|
|
403
|
+
// Visual Assets
|
|
404
|
+
console.log(item.mainImage); // Product image URL
|
|
405
|
+
|
|
406
|
+
// Item Attributes (engraving, etc.)
|
|
407
|
+
console.log(item.attributes); // Item attributes object
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Use Cases:**
|
|
412
|
+
- **Order Analytics**: Track checkout completion rates, average order values, popular items
|
|
413
|
+
- **Marketing Optimization**: Analyze opt-in rates, gift order patterns, promo code effectiveness
|
|
414
|
+
- **Revenue Tracking**: Monitor tax collection, fees, discounts, and gift card usage
|
|
415
|
+
- **Customer Insights**: Understand purchasing patterns, preferred retailers, delivery preferences
|
|
416
|
+
- **Compliance**: Track age verification requirements, substitution policy acceptance
|
|
417
|
+
|
|
418
|
+
### 📍 Address Events (Track Shipping Preferences)
|
|
419
|
+
```javascript
|
|
420
|
+
'lce:actions.address_updated' // → "Customer entered shipping address"
|
|
421
|
+
'lce:actions.address_cleared' // → "Customer removed address"
|
|
422
|
+
'lce:actions.address_failed' // → "Address validation failed"
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### 🔔 **NEW: Action Feedback Events** (Track Action Success/Failure)
|
|
426
|
+
|
|
427
|
+
These events fire when programmatic actions succeed or fail, giving you complete control over user feedback:
|
|
428
|
+
|
|
429
|
+
#### 🛒 **Cart Action Feedback**
|
|
430
|
+
```javascript
|
|
431
|
+
// Product addition feedback
|
|
432
|
+
'lce:actions.cart_product_add_success' // → "Products successfully added to cart"
|
|
433
|
+
// Data: { itemsAdded: number, identifiers: string[] }
|
|
434
|
+
|
|
435
|
+
'lce:actions.cart_product_add_failed' // → "Products could not be added to cart"
|
|
436
|
+
// Data: { identifiers: string[], error: string }
|
|
437
|
+
|
|
438
|
+
// Promo code feedback
|
|
439
|
+
'lce:actions.cart_promo_code_applied' // → "Promo code worked - show success!"
|
|
440
|
+
// Data: { applied: true, discountAmount?: number, newTotal?: number }
|
|
441
|
+
|
|
442
|
+
'lce:actions.cart_promo_code_removed' // → "Promo code removed successfully"
|
|
443
|
+
// Data: { applied: false }
|
|
444
|
+
|
|
445
|
+
'lce:actions.cart_promo_code_failed' // → "Promo code didn't work - show error"
|
|
446
|
+
// Data: { attempted: true, error: string }
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### 💳 **Checkout Action Feedback**
|
|
450
|
+
```javascript
|
|
451
|
+
// Product addition feedback
|
|
452
|
+
'lce:actions.checkout_product_add_success' // → "Products added to checkout successfully"
|
|
453
|
+
// Data: { itemsAdded: number, identifiers: string[] }
|
|
454
|
+
|
|
455
|
+
'lce:actions.checkout_product_add_failed' // → "Could not add products to checkout"
|
|
456
|
+
// Data: { identifiers: string[], error: string }
|
|
457
|
+
|
|
458
|
+
// Promo code feedback
|
|
459
|
+
'lce:actions.checkout_promo_code_applied' // → "Checkout discount applied!"
|
|
460
|
+
// Data: { applied: true, discountAmount?: number, newTotal?: number }
|
|
461
|
+
|
|
462
|
+
'lce:actions.checkout_promo_code_removed' // → "Checkout discount removed"
|
|
463
|
+
// Data: { applied: false }
|
|
464
|
+
|
|
465
|
+
'lce:actions.checkout_promo_code_failed' // → "Checkout discount failed"
|
|
466
|
+
// Data: { attempted: true, error: string }
|
|
467
|
+
|
|
468
|
+
// Gift card feedback
|
|
469
|
+
'lce:actions.checkout_gift_card_applied' // → "Gift card applied successfully!"
|
|
470
|
+
// Data: { applied: true, newTotal?: number }
|
|
471
|
+
|
|
472
|
+
'lce:actions.checkout_gift_card_removed' // → "Gift card removed"
|
|
473
|
+
// Data: { applied: false }
|
|
474
|
+
|
|
475
|
+
'lce:actions.checkout_gift_card_failed' // → "Gift card could not be applied"
|
|
476
|
+
// Data: { attempted: true, error: string }
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
#### 🔒 **Security Note**
|
|
480
|
+
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.
|
|
481
|
+
|
|
482
|
+
**Example: Secure Action Feedback**
|
|
483
|
+
```javascript
|
|
484
|
+
// Fire the action (simple)
|
|
485
|
+
await actions.cart.applyPromoCode('SECRET20');
|
|
486
|
+
|
|
487
|
+
// Get feedback (secure)
|
|
488
|
+
window.addEventListener('lce:actions.cart_promo_code_applied', function(event) {
|
|
489
|
+
const { applied, discountAmount, newTotal } = event.detail.data;
|
|
490
|
+
// ✅ You get: success status, discount amount, new total
|
|
491
|
+
// 🚫 You DON'T get: 'SECRET20' (secure!)
|
|
492
|
+
|
|
493
|
+
showSuccessMessage(`🎉 Discount applied! You saved $${discountAmount}!`);
|
|
494
|
+
updateCartTotal(newTotal);
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Step 3: Real-World Implementation Examples
|
|
499
|
+
|
|
500
|
+
### 🔔 **NEW Example: Smart Action Feedback with Perfect UX**
|
|
501
|
+
```javascript
|
|
502
|
+
// Perfect promo code experience with action feedback
|
|
503
|
+
async function applyPromoCodeWithFeedback(code) {
|
|
504
|
+
// Show loading state
|
|
505
|
+
showLoadingMessage('Applying promo code...');
|
|
506
|
+
|
|
507
|
+
// Set up event listeners BEFORE firing action
|
|
508
|
+
const successHandler = (event) => {
|
|
509
|
+
const { applied, discountAmount, newTotal } = event.detail.data;
|
|
510
|
+
hideLoadingMessage();
|
|
511
|
+
showSuccessMessage(`🎉 Success! You saved $${discountAmount}!`);
|
|
512
|
+
updatePriceDisplay(newTotal);
|
|
513
|
+
|
|
514
|
+
// Track successful promo usage
|
|
515
|
+
analytics.track('Promo Applied', {
|
|
516
|
+
discount: discountAmount,
|
|
517
|
+
newTotal: newTotal
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// Clean up
|
|
521
|
+
cleanup();
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
const failureHandler = (event) => {
|
|
525
|
+
const { attempted, error } = event.detail.data;
|
|
526
|
+
hideLoadingMessage();
|
|
527
|
+
showErrorMessage('Promo code could not be applied. Please try again.');
|
|
528
|
+
|
|
529
|
+
// Track failed attempts (for optimization)
|
|
530
|
+
analytics.track('Promo Failed', { error: error });
|
|
531
|
+
|
|
532
|
+
// Maybe suggest alternatives
|
|
533
|
+
suggestAlternativePromos();
|
|
534
|
+
|
|
535
|
+
// Clean up
|
|
536
|
+
cleanup();
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const cleanup = () => {
|
|
540
|
+
window.removeEventListener('lce:actions.cart_promo_code_applied', successHandler);
|
|
541
|
+
window.removeEventListener('lce:actions.cart_promo_code_failed', failureHandler);
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Attach listeners
|
|
545
|
+
window.addEventListener('lce:actions.cart_promo_code_applied', successHandler);
|
|
546
|
+
window.addEventListener('lce:actions.cart_promo_code_failed', failureHandler);
|
|
547
|
+
|
|
548
|
+
// Fire the action
|
|
549
|
+
await actions.cart.applyPromoCode(code);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Usage: Perfect UX every time!
|
|
553
|
+
applyPromoCodeWithFeedback('SAVE20');
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### 🎯 Example 1: Boost Your Sales with Smart Promotions
|
|
557
|
+
```javascript
|
|
558
|
+
// Automatically offer discounts for high-value carts
|
|
559
|
+
window.addEventListener('lce:actions.cart_updated', function(event) {
|
|
560
|
+
const cart = event.detail.data.current;
|
|
561
|
+
|
|
562
|
+
if (cart.amounts.total > 200 && !cart.promoCode) {
|
|
563
|
+
// Show them a 10% off popup
|
|
564
|
+
showPopup("Get 10% off orders over $200! Use code: SAVE10");
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// Track which products make people abandon checkout
|
|
569
|
+
window.addEventListener('lce:actions.checkout_opened', function(event) {
|
|
570
|
+
window.checkoutStartTime = new Date();
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
window.addEventListener('lce:actions.checkout_closed', function(event) {
|
|
574
|
+
// If they close checkout without buying, they abandoned
|
|
575
|
+
if (window.checkoutStartTime) {
|
|
576
|
+
const timeSpent = new Date() - window.checkoutStartTime;
|
|
577
|
+
console.log('Checkout abandoned after', timeSpent/1000, 'seconds');
|
|
578
|
+
// Send this data to your analytics to find problem products
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### 📧 Example 2: Automated Email Marketing
|
|
584
|
+
```javascript
|
|
585
|
+
// Build an email list from cart abandoners
|
|
586
|
+
window.addEventListener('lce:actions.cart_opened', function(event) {
|
|
587
|
+
// Customer opened cart - start tracking
|
|
588
|
+
window.cartOpenTime = new Date();
|
|
589
|
+
window.cartItems = event.detail.data.items;
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
|
|
593
|
+
// They bought! No need for abandonment email
|
|
594
|
+
window.cartOpenTime = null;
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
// Check every 5 minutes if cart was abandoned
|
|
598
|
+
setInterval(function() {
|
|
599
|
+
if (window.cartOpenTime) {
|
|
600
|
+
const timeSinceOpen = new Date() - window.cartOpenTime;
|
|
601
|
+
if (timeSinceOpen > 15 * 60 * 1000) { // 15 minutes
|
|
602
|
+
// Send abandonment email with cart items
|
|
603
|
+
sendAbandonmentEmail(window.cartItems);
|
|
604
|
+
window.cartOpenTime = null; // Don't send again
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}, 5 * 60 * 1000);
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### 📊 Example 3: Track Your Best-Performing Products
|
|
611
|
+
```javascript
|
|
612
|
+
// Keep a running tally of product performance
|
|
613
|
+
let productStats = {};
|
|
614
|
+
|
|
615
|
+
window.addEventListener('lce:actions.product_loaded', function(event) {
|
|
616
|
+
const product = event.detail.data;
|
|
617
|
+
|
|
618
|
+
// Initialize stats if first time seeing this product
|
|
619
|
+
if (!productStats[product.id]) {
|
|
620
|
+
productStats[product.id] = {
|
|
621
|
+
name: product.name,
|
|
622
|
+
views: 0,
|
|
623
|
+
addedToCarts: 0,
|
|
624
|
+
conversions: 0
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
productStats[product.id].views++;
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
632
|
+
const data = event.detail.data;
|
|
633
|
+
// Note: product_add_to_cart only has identifier, not full product details
|
|
634
|
+
if (productStats[data.identifier]) {
|
|
635
|
+
productStats[data.identifier].addedToCarts++;
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
window.addEventListener('lce:actions.checkout_submit_completed', function(event) {
|
|
640
|
+
const order = event.detail.data;
|
|
641
|
+
console.log('Order completed:', order.orderNumber, 'Total:', order.orderTotal);
|
|
642
|
+
|
|
643
|
+
// Send stats to your analytics dashboard
|
|
644
|
+
console.log('Product Performance:', productStats);
|
|
645
|
+
|
|
646
|
+
// Track conversion in analytics
|
|
647
|
+
analytics.track('Purchase', {
|
|
648
|
+
orderNumber: order.orderNumber,
|
|
649
|
+
total: order.orderTotal
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### 🔥 Example 4: Create Urgency with Live Updates
|
|
655
|
+
```javascript
|
|
656
|
+
// Show live activity to create FOMO (Fear of Missing Out)
|
|
657
|
+
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
658
|
+
const data = event.detail.data;
|
|
659
|
+
|
|
660
|
+
// Show notification to other visitors
|
|
661
|
+
showNotification(`Someone just bought product ${data.identifier}! Only 3 left!`);
|
|
662
|
+
|
|
663
|
+
// Update inventory count on the page
|
|
664
|
+
updateInventoryDisplay(data.identifier, -1);
|
|
665
|
+
});
|
|
666
|
+
|
|
667
|
+
window.addEventListener('lce:actions.cart_opened', function(event) {
|
|
668
|
+
// Show how many people are currently viewing this product
|
|
669
|
+
showViewerCount("👀 5 people are looking at this right now");
|
|
670
|
+
});
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
## Common Use Cases & How to Implement
|
|
674
|
+
|
|
675
|
+
### 🛒 **Cart Abandonment Recovery**
|
|
676
|
+
**The Problem**: 70% of carts are abandoned
|
|
677
|
+
**The Solution**: Automatic follow-up based on events
|
|
678
|
+
|
|
679
|
+
```javascript
|
|
680
|
+
// Set up cart abandonment tracking
|
|
681
|
+
let abandonmentTimer;
|
|
682
|
+
|
|
683
|
+
window.addEventListener('lce:actions.cart_opened', function() {
|
|
684
|
+
// Reset timer each time they open cart
|
|
685
|
+
clearTimeout(abandonmentTimer);
|
|
686
|
+
|
|
687
|
+
abandonmentTimer = setTimeout(function() {
|
|
688
|
+
// After 30 minutes of inactivity, trigger recovery
|
|
689
|
+
triggerCartRecovery();
|
|
690
|
+
}, 30 * 60 * 1000);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
window.addEventListener('lce:actions.checkout_submit_completed', function() {
|
|
694
|
+
// They completed purchase - cancel recovery
|
|
695
|
+
clearTimeout(abandonmentTimer);
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
function triggerCartRecovery() {
|
|
699
|
+
// Send email, show popup, etc.
|
|
700
|
+
console.log("Time to recover this cart!");
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### 📈 **Revenue Optimization**
|
|
705
|
+
**The Goal**: Increase average order value
|
|
706
|
+
**The Method**: Smart upselling based on behavior
|
|
707
|
+
|
|
708
|
+
```javascript
|
|
709
|
+
window.addEventListener('lce:actions.product_add_to_cart', function(event) {
|
|
710
|
+
const data = event.detail.data;
|
|
711
|
+
|
|
712
|
+
// Offer upsells based on product identifier
|
|
713
|
+
const upsellMap = {
|
|
714
|
+
'phone-001': 'phone-cases',
|
|
715
|
+
'laptop-001': 'laptop-accessories'
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
if (upsellMap[data.identifier]) {
|
|
719
|
+
showUpsell(upsellMap[data.identifier]);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Check if cart is close to free shipping threshold
|
|
723
|
+
const cart = actions.cart.getDetails();
|
|
724
|
+
if (cart.amounts.total > 45 && cart.amounts.total < 50) {
|
|
725
|
+
showMessage("Add $" + (50 - cart.amounts.total) + " more for FREE shipping!");
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
### 🎯 **Conversion Tracking**
|
|
731
|
+
**The Need**: Measure what's working
|
|
732
|
+
**The Implementation**: Track the entire funnel
|
|
733
|
+
|
|
734
|
+
```javascript
|
|
735
|
+
// Track the complete conversion funnel
|
|
736
|
+
const funnelSteps = {
|
|
737
|
+
productView: 0,
|
|
738
|
+
addToCart: 0,
|
|
739
|
+
cartView: 0,
|
|
740
|
+
checkoutStart: 0,
|
|
741
|
+
purchase: 0
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
window.addEventListener('lce:actions.product_loaded', () => funnelSteps.productView++);
|
|
745
|
+
window.addEventListener('lce:actions.product_add_to_cart', () => funnelSteps.addToCart++);
|
|
746
|
+
window.addEventListener('lce:actions.cart_opened', () => funnelSteps.cartView++);
|
|
747
|
+
window.addEventListener('lce:actions.checkout_opened', () => funnelSteps.checkoutStart++);
|
|
748
|
+
window.addEventListener('lce:actions.checkout_submit_completed', () => funnelSteps.purchase++);
|
|
749
|
+
|
|
750
|
+
// Send to your analytics every 10 minutes
|
|
751
|
+
setInterval(() => {
|
|
752
|
+
console.log('Conversion Funnel:', funnelSteps);
|
|
753
|
+
// Send to your dashboard/analytics
|
|
754
|
+
}, 10 * 60 * 1000);
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
## Getting Started in 5 Minutes
|
|
758
|
+
|
|
759
|
+
1. **Pick one goal** from the examples above
|
|
760
|
+
2. **Copy the code** into your website
|
|
761
|
+
3. **Replace the console.log** with your actual actions (send email, show popup, etc.)
|
|
762
|
+
4. **Test it** by going through the flow yourself
|
|
763
|
+
5. **Monitor the results** and adjust as needed
|
|
764
|
+
|
|
765
|
+
**Need help?** The events automatically work once LiquidCommerce Elements are on your page. Just add the JavaScript code and you're ready to go!
|