Ecwid provides comprehensive ecommerce tracking capabilities for GA4, allowing you to track the complete customer journey from product discovery to purchase.
Ecommerce Tracking Overview
GA4's ecommerce tracking captures:
- Product Impressions: Which products customers see
- Product Interactions: Clicks, add to cart, remove from cart
- Checkout Process: Each step of the purchase funnel
- Transactions: Complete order details with revenue
- Refunds: Refunded transactions (manual implementation)
Implementation Methods
Method 1: Ecwid Built-in Integration
Best for: Quick setup, Venture plan or higher.
Enable in Ecwid Control Panel → Settings → General → Tracking & Analytics:
- Add GA4 Measurement ID
- Toggle Track ecommerce to ON
- Toggle Enhanced ecommerce to ON
- Save
What's tracked automatically:
- ✓ Product views
- ✓ Add to cart / remove from cart
- ✓ Checkout steps
- ✓ Purchases with full transaction data
- ✓ Product list impressions
Limitations:
- No customization of event parameters
- Cannot add custom dimensions
- Limited control over data structure
Method 2: Custom JavaScript Implementation
Best for: Full control, custom parameters, any Ecwid plan.
Implement using Ecwid JavaScript API in Settings → General → Tracking & Analytics → Custom JavaScript Code.
Method 3: Google Tag Manager
Best for: Enterprise setups, multiple tags, consent management.
Configure ecommerce events as GTM tags with Ecwid data layer variables.
See GTM Data Layer for implementation.
Complete Custom Implementation
This section provides complete code for custom GA4 ecommerce tracking.
Setup Base Configuration
Add to Ecwid's Custom JavaScript Code section:
<!-- Google Analytics 4 Ecommerce Tracking -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
// Configure GA4
gtag('config', 'G-XXXXXXXXXX', {
'send_page_view': true,
'currency': 'USD', // Set your default currency
'allow_google_signals': true
});
// Ecommerce tracking implementation
Ecwid.OnAPILoaded.add(function() {
console.log('Ecwid Ecommerce Tracking Initialized');
// Product Impressions (List Views)
trackProductImpressions();
// Product Detail Views
trackProductViews();
// Add to Cart
trackAddToCart();
// Remove from Cart
trackRemoveFromCart();
// Checkout Process
trackCheckoutProcess();
// Purchase
trackPurchase();
});
// Implementation functions below...
</script>
Replace G-XXXXXXXXXX with your GA4 Measurement ID.
Track Product Impressions
When customers view product lists (categories, search results):
function trackProductImpressions() {
Ecwid.OnPageLoad.add(function(page) {
if (page.type === 'CATEGORY' || page.type === 'SEARCH') {
var listName = page.type === 'CATEGORY' ?
'Category' : 'Search Results';
var listId = page.type === 'CATEGORY' ?
page.categoryId.toString() : 'search';
// Fetch products for current page
var params = {
limit: 100 // Adjust based on your pagination
};
if (page.type === 'CATEGORY') {
params.categoryId = page.categoryId;
} else if (page.type === 'SEARCH') {
params.keyword = page.keywords;
}
Ecwid.getProducts(params, function(searchResult) {
if (searchResult.items && searchResult.items.length > 0) {
var items = searchResult.items.map(function(product, index) {
return {
item_id: product.id.toString(),
item_name: product.name,
item_brand: product.brand || '',
item_category: getCategoryHierarchy(product.categoryIds),
item_list_name: listName,
item_list_id: listId,
price: product.defaultDisplayedPrice,
index: index,
quantity: 1
};
});
gtag('event', 'view_item_list', {
item_list_id: listId,
item_list_name: listName,
items: items
});
}
});
}
});
}
// Helper: Get category hierarchy
function getCategoryHierarchy(categoryIds) {
if (!categoryIds || categoryIds.length === 0) return '';
// For simplicity, return first category
// Optionally fetch full category path with Ecwid.getCategory()
return 'Category ' + categoryIds[0];
}
Track Product Views
When customers view individual product pages:
function trackProductViews() {
Ecwid.OnPageLoad.add(function(page) {
if (page.type === 'PRODUCT') {
Ecwid.getProduct(page.productId, function(product) {
// Get selected variant if applicable
var variant = getSelectedVariant(product);
var price = variant ? variant.price : product.defaultDisplayedPrice;
gtag('event', 'view_item', {
currency: product.currency || 'USD',
value: price,
items: [{
item_id: product.id.toString(),
item_name: product.name,
item_brand: product.brand || '',
item_category: getCategoryHierarchy(product.categoryIds),
item_category2: product.categoryIds[1] ? 'Category ' + product.categoryIds[1] : '',
item_variant: variant ? variant.sku : '',
price: price,
quantity: 1
}]
});
});
}
});
}
// Helper: Get selected product variant
function getSelectedVariant(product) {
if (!product.combinations || product.combinations.length === 0) {
return null;
}
// Return first available combination
// In practice, track actual user selection
return product.combinations[0];
}
Track Add to Cart
When customers add items to their cart:
function trackAddToCart() {
var previousCart = null;
Ecwid.OnCartChanged.add(function(cart) {
// Initialize on first load
if (previousCart === null) {
previousCart = JSON.parse(JSON.stringify(cart));
return;
}
// Detect item additions
if (cart.items.length > previousCart.items.length) {
// Find newly added item
var newItems = cart.items.filter(function(cartItem) {
return !previousCart.items.some(function(prevItem) {
return prevItem.id === cartItem.id;
});
});
newItems.forEach(function(item) {
gtag('event', 'add_to_cart', {
currency: cart.currency || 'USD',
value: item.price * item.quantity,
items: [{
item_id: item.product.id.toString(),
item_name: item.product.name,
item_brand: item.product.brand || '',
item_category: item.product.categoryIds ? 'Category ' + item.product.categoryIds[0] : '',
item_variant: formatVariant(item.selectedOptions),
price: item.price,
quantity: item.quantity
}]
});
});
}
// Detect quantity increases
if (cart.items.length === previousCart.items.length) {
cart.items.forEach(function(cartItem) {
var prevItem = previousCart.items.find(function(prev) {
return prev.id === cartItem.id;
});
if (prevItem && cartItem.quantity > prevItem.quantity) {
var qtyAdded = cartItem.quantity - prevItem.quantity;
gtag('event', 'add_to_cart', {
currency: cart.currency || 'USD',
value: cartItem.price * qtyAdded,
items: [{
item_id: cartItem.product.id.toString(),
item_name: cartItem.product.name,
price: cartItem.price,
quantity: qtyAdded
}]
});
}
});
}
// Update reference
previousCart = JSON.parse(JSON.stringify(cart));
});
}
// Helper: Format variant options
function formatVariant(selectedOptions) {
if (!selectedOptions || selectedOptions.length === 0) return '';
return selectedOptions.map(function(opt) {
return opt.name + ': ' + opt.value;
}).join(', ');
}
Track Remove from Cart
When customers remove items from cart:
function trackRemoveFromCart() {
var previousCart = null;
Ecwid.OnCartChanged.add(function(cart) {
if (previousCart === null) {
previousCart = JSON.parse(JSON.stringify(cart));
return;
}
// Detect item removals
if (cart.items.length < previousCart.items.length) {
// Find removed items
var removedItems = previousCart.items.filter(function(prevItem) {
return !cart.items.some(function(cartItem) {
return cartItem.id === prevItem.id;
});
});
removedItems.forEach(function(item) {
gtag('event', 'remove_from_cart', {
currency: cart.currency || 'USD',
value: item.price * item.quantity,
items: [{
item_id: item.product.id.toString(),
item_name: item.product.name,
price: item.price,
quantity: item.quantity
}]
});
});
}
// Detect quantity decreases
if (cart.items.length === previousCart.items.length) {
cart.items.forEach(function(cartItem) {
var prevItem = previousCart.items.find(function(prev) {
return prev.id === cartItem.id;
});
if (prevItem && cartItem.quantity < prevItem.quantity) {
var qtyRemoved = prevItem.quantity - cartItem.quantity;
gtag('event', 'remove_from_cart', {
currency: cart.currency || 'USD',
value: cartItem.price * qtyRemoved,
items: [{
item_id: cartItem.product.id.toString(),
item_name: cartItem.product.name,
price: cartItem.price,
quantity: qtyRemoved
}]
});
}
});
}
previousCart = JSON.parse(JSON.stringify(cart));
});
}
Track Checkout Process
Track each step of the checkout funnel:
function trackCheckoutProcess() {
var checkoutSteps = {
CHECKOUT_ADDRESS: { step: 1, name: 'Address Information' },
CHECKOUT_SHIPPING: { step: 2, name: 'Shipping Method' },
CHECKOUT_PAYMENT: { step: 3, name: 'Payment Information' }
};
var trackedSteps = {};
Ecwid.OnPageLoad.add(function(page) {
// Begin checkout (first step)
if (page.type === 'CHECKOUT_ADDRESS' && !trackedSteps['begin_checkout']) {
trackedSteps['begin_checkout'] = true;
Ecwid.Cart.get(function(cart) {
gtag('event', 'begin_checkout', {
currency: cart.currency || 'USD',
value: cart.total,
items: cart.items.map(function(item) {
return {
item_id: item.product.id.toString(),
item_name: item.product.name,
price: item.price,
quantity: item.quantity
};
})
});
});
}
// Shipping info added
if (page.type === 'CHECKOUT_PAYMENT' && !trackedSteps['add_shipping_info']) {
trackedSteps['add_shipping_info'] = true;
Ecwid.Cart.get(function(cart) {
var shippingOption = cart.shippingOption || {};
gtag('event', 'add_shipping_info', {
currency: cart.currency || 'USD',
value: cart.total,
shipping_tier: shippingOption.shippingMethodName || 'Standard',
items: cart.items.map(function(item) {
return {
item_id: item.product.id.toString(),
item_name: item.product.name,
price: item.price,
quantity: item.quantity
};
})
});
});
}
// Payment info (payment page reached)
if (page.type === 'CHECKOUT_PAYMENT' && !trackedSteps['add_payment_info']) {
trackedSteps['add_payment_info'] = true;
Ecwid.Cart.get(function(cart) {
gtag('event', 'add_payment_info', {
currency: cart.currency || 'USD',
value: cart.total,
payment_type: 'Unknown', // Ecwid API doesn't expose this
items: cart.items.map(function(item) {
return {
item_id: item.product.id.toString(),
item_name: item.product.name,
price: item.price,
quantity: item.quantity
};
})
});
});
}
// Reset when leaving checkout
if (!checkoutSteps[page.type]) {
trackedSteps = {};
}
});
}
Track Purchase
When order is successfully completed:
function trackPurchase() {
var purchaseTracked = false;
Ecwid.OnOrderPlaced.add(function(order) {
// Prevent duplicate tracking
if (purchaseTracked) return;
purchaseTracked = true;
gtag('event', 'purchase', {
transaction_id: order.vendorOrderNumber,
value: order.total,
tax: order.tax || 0,
shipping: order.shippingOption ? order.shippingOption.shippingRate : 0,
currency: order.currency || 'USD',
coupon: order.couponDiscount > 0 ? (order.couponName || 'Discount Applied') : '',
items: order.items.map(function(item, index) {
return {
item_id: item.product.id.toString(),
item_name: item.product.name,
item_brand: item.product.brand || '',
item_category: item.product.categoryIds ? 'Category ' + item.product.categoryIds[0] : '',
item_variant: formatVariant(item.selectedOptions),
price: item.price,
quantity: item.quantity,
index: index,
discount: item.discount || 0
};
})
});
// Reset flag after delay (in case customer views order confirmation multiple times)
setTimeout(function() {
purchaseTracked = false;
}, 5000);
});
}
Advanced Ecommerce Features
Product Affinity (Frequently Bought Together)
Track which products are purchased together:
Ecwid.OnOrderPlaced.add(function(order) {
if (order.items.length > 1) {
// Multiple items in order
var productIds = order.items.map(function(item) {
return item.product.id;
});
gtag('event', 'product_affinity', {
products: productIds.join(','),
order_value: order.total
});
}
});
Customer Lifetime Value (CLV)
Track returning customer orders:
Ecwid.OnAPILoaded.add(function() {
Ecwid.getCustomerInfo(function(customer) {
if (customer && customer.id) {
// Set user properties
gtag('set', 'user_properties', {
customer_lifetime_value: customer.totalSpent || 0,
customer_order_count: customer.orderCount || 0,
customer_type: customer.customerGroupId ? 'wholesale' : 'retail'
});
}
});
});
Abandoned Cart Recovery
Track potential abandoned carts:
var cartAbandonTimer = null;
Ecwid.OnCartChanged.add(function(cart) {
// Clear existing timer
if (cartAbandonTimer) {
clearTimeout(cartAbandonTimer);
}
// If cart has items, set abandon timer (e.g., 15 minutes)
if (cart.items.length > 0) {
cartAbandonTimer = setTimeout(function() {
gtag('event', 'cart_abandoned', {
currency: cart.currency || 'USD',
value: cart.total,
items_count: cart.items.length
});
}, 15 * 60 * 1000); // 15 minutes
}
});
// Clear timer if checkout started
Ecwid.OnPageLoad.add(function(page) {
if (page.type === 'CHECKOUT_ADDRESS') {
if (cartAbandonTimer) {
clearTimeout(cartAbandonTimer);
cartAbandonTimer = null;
}
}
});
Refund Tracking
Track refunds (requires manual trigger via Ecwid webhook):
// This must be triggered server-side via Ecwid webhook
// When refund is processed, send to GA4 Measurement Protocol
function trackRefund(transactionId, refundAmount, refundItems) {
gtag('event', 'refund', {
transaction_id: transactionId,
value: refundAmount,
currency: 'USD',
items: refundItems // Array of refunded items
});
}
// Example usage (from webhook handler):
// trackRefund('ORDER-123', 29.99, [{item_id: '456', quantity: 1}]);
Product-Level Custom Dimensions
Add custom product attributes:
// Extend product items with custom dimensions
function enhanceProductData(product) {
return {
item_id: product.id.toString(),
item_name: product.name,
item_brand: product.brand || '',
item_category: getCategoryHierarchy(product.categoryIds),
price: product.defaultDisplayedPrice,
// Custom dimensions
item_list_name: product.inStock ? 'In Stock' : 'Out of Stock',
item_custom_1: product.sku || '',
item_custom_2: product.weight ? product.weight.value + product.weight.unit : '',
item_custom_3: product.productClassId ? 'Class ' + product.productClassId : ''
};
}
Tracking Product Promotions
Track promotional products or sales:
Ecwid.OnAPILoaded.add(function() {
Ecwid.OnPageLoad.add(function(page) {
if (page.type === 'PRODUCT') {
Ecwid.getProduct(page.productId, function(product) {
// Check if product is on sale
if (product.compareToPrice && product.compareToPrice > product.defaultDisplayedPrice) {
var discount = product.compareToPrice - product.defaultDisplayedPrice;
var discountPercent = (discount / product.compareToPrice * 100).toFixed(0);
gtag('event', 'view_promotion', {
promotion_id: 'sale_' + product.id,
promotion_name: 'Product Sale',
creative_name: discountPercent + '% Off',
items: [{
item_id: product.id.toString(),
item_name: product.name,
discount: discount
}]
});
}
});
}
});
});
Multi-Currency Support
Handle multiple currencies:
Ecwid.OnAPILoaded.add(function() {
// Get store currency settings
Ecwid.getStorefrontInfo(function(info) {
var defaultCurrency = info.currency || 'USD';
// Use this in all events
gtag('config', 'G-XXXXXXXXXX', {
'currency': defaultCurrency
});
});
// For individual transactions, use order currency
Ecwid.OnOrderPlaced.add(function(order) {
gtag('event', 'purchase', {
transaction_id: order.vendorOrderNumber,
value: order.total,
currency: order.currency || 'USD', // Order-specific currency
// ... rest of purchase data
});
});
});
Testing & Validation
Use GA4 DebugView
- Enable debug mode:
gtag('config', 'G-XXXXXXXXXX', {
'debug_mode': true
});
In GA4, go to Admin → DebugView
Perform test transactions
Verify all events and parameters
Test Checklist
- Product impressions tracked on category pages
- Product views tracked on detail pages
- Add to cart fires with correct product and quantity
- Remove from cart detects removals
- Begin checkout fires once at checkout start
- Add shipping info fires when shipping selected
- Purchase fires with complete transaction data
- Transaction ID is unique and correct
- Revenue matches order total
- Tax and shipping values are accurate
- Product data includes all custom dimensions
- Currency is correct for all events
Console Debugging
// Monitor all events
window.dataLayer = window.dataLayer || [];
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
console.log('GA4 Event:', arguments[0]);
return originalPush.apply(window.dataLayer, arguments);
};
Common Issues
Duplicate Purchase Events
Cause: Order confirmation page reloaded or back button used.
Fix: Use flag to prevent duplicate tracking (shown in purchase function above).
Missing Product Data
Cause: API call not returning complete data.
Fix: Always use Ecwid.getProduct() for full details, not page context alone.
Currency Mismatch
Cause: Hard-coded currency doesn't match order currency.
Fix: Always use order.currency or cart.currency from Ecwid data.
Events Not Firing
See Events Not Firing Troubleshooting.
Reporting in GA4
Key Ecommerce Reports
Monetization Overview:
- Reports → Monetization → Overview
- Total revenue, transactions, average order value
Ecommerce Purchases:
- Reports → Monetization → Ecommerce purchases
- Transaction details, product performance
Item Performance:
- Reports → Monetization → Item-list name and Item-promotion name
- Which products drive revenue
Purchase Journey:
- Explore → Funnel Analysis
- Create funnel: view_item → add_to_cart → begin_checkout → purchase
Custom Reports
Create explorations for:
- Product affinity analysis
- Category performance
- Coupon effectiveness
- Shipping method preferences
Next Steps
- GA4 Event Tracking - Track custom events
- GTM Data Layer - Implement via Google Tag Manager
- Events Not Firing - Debug tracking issues
For general GA4 ecommerce concepts, see GA4 Ecommerce Guide.