Google Analytics 4 Event Tracking on Ecwid | OpsBlu Docs

Google Analytics 4 Event Tracking on Ecwid

Complete guide to tracking GA4 events on Ecwid including custom events, enhanced ecommerce, and the Ecwid JavaScript API.

Ecwid provides multiple ways to track user interactions beyond basic pageviews. This guide covers standard ecommerce events, custom events, and advanced tracking using the Ecwid JavaScript API.

Ecwid's Native Event Tracking

When using Ecwid's built-in GA4 integration or proper custom implementation, these events are tracked automatically.

Automatically Tracked Events

Event When It Fires Data Included
view_item Customer views product detail Product ID, name, price, category
view_item_list Customer views category/search Multiple products with positions
add_to_cart Item added to cart Product data, quantity, price
remove_from_cart Item removed from cart Product data, quantity
view_cart Customer opens cart Cart contents, total value
begin_checkout Checkout process starts Full cart data
add_shipping_info Shipping method selected Shipping cost, method
add_payment_info Payment method selected Payment method type
purchase Order completed Transaction ID, revenue, items, tax, shipping

Event Data Structure

All events follow GA4's recommended ecommerce event structure:

gtag('event', 'event_name', {
  currency: 'USD',
  value: 29.99,
  items: [{
    item_id: '123',
    item_name: 'Product Name',
    item_category: 'Category',
    price: 29.99,
    quantity: 1
  }]
});

Using Ecwid JavaScript API for Custom Tracking

The Ecwid JavaScript API provides hooks to track virtually any interaction. This is the most powerful method for custom event tracking.

API Initialization

Always wait for Ecwid to load before using the API:

<script>
// Wait for Ecwid API to load
Ecwid.OnAPILoaded.add(function() {
  console.log('Ecwid API ready');
  // Your tracking code here
});
</script>

Add this to Settings → General → Tracking & Analytics → Custom JavaScript Code.

Standard Ecommerce Events

1. Product View (view_item)

Fires when customer views a product detail page.

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    // Check if product page
    if (page.type === 'PRODUCT') {

      // Fetch full product details
      Ecwid.getProduct(page.productId, function(product) {

        // Get selected variant (if applicable)
        var selectedOptions = product.options || [];
        var selectedPrice = product.defaultDisplayedPrice;

        gtag('event', 'view_item', {
          currency: product.currency || 'USD',
          value: selectedPrice,
          items: [{
            item_id: product.id.toString(),
            item_name: product.name,
            item_brand: product.brand || '',
            item_category: getCategoryName(product.categoryIds[0]),
            item_variant: getVariantName(selectedOptions),
            price: selectedPrice,
            quantity: 1
          }]
        });
      });
    }
  });

  // Helper function to get category name
  function getCategoryName(categoryId) {
    if (!categoryId) return '';
    // Optionally fetch category details
    return 'Category ' + categoryId;
  }

  // Helper function to format variant
  function getVariantName(options) {
    if (!options || options.length === 0) return '';
    return options.map(opt => opt.value).join(' / ');
  }

});

2. Category View (view_item_list)

Fires when customer views a category or search results.

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'CATEGORY' || page.type === 'SEARCH') {

      var listName = page.type === 'CATEGORY' ?
        'Category: ' + page.categoryId :
        'Search: ' + page.keywords;

      // Get products in view
      Ecwid.getProducts({
        categoryId: page.categoryId,
        keyword: page.keywords,
        limit: 50
      }, function(products) {

        var items = products.items.map(function(product, index) {
          return {
            item_id: product.id.toString(),
            item_name: product.name,
            item_list_name: listName,
            item_list_id: page.categoryId ? page.categoryId.toString() : 'search',
            index: index,
            price: product.defaultDisplayedPrice,
            quantity: 1
          };
        });

        gtag('event', 'view_item_list', {
          item_list_name: listName,
          item_list_id: page.categoryId ? page.categoryId.toString() : 'search',
          items: items
        });
      });
    }
  });

});

3. Add to Cart (add_to_cart)

Fires when customer adds item to cart.

Ecwid.OnAPILoaded.add(function() {

  var previousCart = null;

  Ecwid.OnCartChanged.add(function(cart) {
    // Detect newly added items
    if (previousCart && cart.items.length > previousCart.items.length) {

      // Find the new item (last in array)
      var newItem = cart.items[cart.items.length - 1];

      gtag('event', 'add_to_cart', {
        currency: cart.currency || 'USD',
        value: newItem.price * newItem.quantity,
        items: [{
          item_id: newItem.product.id.toString(),
          item_name: newItem.product.name,
          price: newItem.price,
          quantity: newItem.quantity
        }]
      });
    }

    // Update previous cart reference
    previousCart = JSON.parse(JSON.stringify(cart));
  });

});

4. Remove from Cart (remove_from_cart)

Fires when customer removes item from cart.

Ecwid.OnAPILoaded.add(function() {

  var previousCart = null;

  Ecwid.OnCartChanged.add(function(cart) {
    // Detect removed items
    if (previousCart && cart.items.length < previousCart.items.length) {

      // Find removed item by comparing arrays
      var removedItem = previousCart.items.find(function(prevItem) {
        return !cart.items.some(function(currItem) {
          return currItem.id === prevItem.id;
        });
      });

      if (removedItem) {
        gtag('event', 'remove_from_cart', {
          currency: cart.currency || 'USD',
          value: removedItem.price * removedItem.quantity,
          items: [{
            item_id: removedItem.product.id.toString(),
            item_name: removedItem.product.name,
            price: removedItem.price,
            quantity: removedItem.quantity
          }]
        });
      }
    }

    previousCart = JSON.parse(JSON.stringify(cart));
  });

});

5. Begin Checkout (begin_checkout)

Fires when customer starts checkout process.

Ecwid.OnAPILoaded.add(function() {

  var checkoutStarted = false;

  Ecwid.OnPageLoad.add(function(page) {
    // Checkout starts at address entry step
    if (page.type === 'CHECKOUT_ADDRESS' && !checkoutStarted) {
      checkoutStarted = 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
            };
          })
        });
      });
    }

    // Reset flag when leaving checkout
    if (page.type !== 'CHECKOUT_ADDRESS' && page.type !== 'CHECKOUT_SHIPPING' && page.type !== 'CHECKOUT_PAYMENT') {
      checkoutStarted = false;
    }
  });

});

6. Add Shipping Info (add_shipping_info)

Fires when customer selects shipping method.

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'CHECKOUT_PAYMENT') {
      // Customer moved to payment, shipping selected

      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 || 'Unknown',
          items: cart.items.map(function(item) {
            return {
              item_id: item.product.id.toString(),
              item_name: item.product.name,
              price: item.price,
              quantity: item.quantity
            };
          })
        });
      });
    }
  });

});

7. Add Payment Info (add_payment_info)

Fires when customer selects payment method.

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'CHECKOUT_PAYMENT') {
      // Payment page loaded

      // Note: Ecwid API doesn't expose selected payment method
      // Track that payment step was reached
      Ecwid.Cart.get(function(cart) {
        gtag('event', 'add_payment_info', {
          currency: cart.currency || 'USD',
          value: cart.total,
          payment_type: 'Unknown', // Ecwid doesn't provide 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
            };
          })
        });
      });
    }
  });

});

8. Purchase (purchase)

Fires when order is completed successfully.

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnOrderPlaced.add(function(order) {

    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 : '',
      items: order.items.map(function(item) {
        return {
          item_id: item.product.id.toString(),
          item_name: item.product.name,
          price: item.price,
          quantity: item.quantity,
          discount: item.discount || 0
        };
      })
    });
  });

});

Custom Event Tracking

Track custom interactions specific to your store.

Newsletter Signup

// Assuming newsletter form on host page
document.getElementById('newsletter-form').addEventListener('submit', function(e) {
  gtag('event', 'newsletter_signup', {
    method: 'Footer Form'
  });
});

Track when customers use Ecwid's search:

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'SEARCH' && page.keywords) {
      gtag('event', 'search', {
        search_term: page.keywords
      });
    }
  });

});

Filter Usage

Track when customers use category filters:

Ecwid.OnAPILoaded.add(function() {

  // Listen to filter changes
  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'CATEGORY') {
      // Track category view with filters
      gtag('event', 'filter_applied', {
        filter_type: 'category',
        category_id: page.categoryId
      });
    }
  });

});

Product Wishlist (if implemented)

// Custom wishlist implementation
function addToWishlist(productId, productName) {
  gtag('event', 'add_to_wishlist', {
    currency: 'USD',
    value: 0, // Or product price if available
    items: [{
      item_id: productId.toString(),
      item_name: productName
    }]
  });
}

Social Share

Track when customers share products:

// Social share buttons
document.querySelectorAll('.social-share').forEach(function(btn) {
  btn.addEventListener('click', function() {
    var network = this.dataset.network; // facebook, twitter, etc.
    var productId = this.dataset.productId;

    gtag('event', 'share', {
      method: network,
      content_type: 'product',
      content_id: productId
    });
  });
});

Advanced Tracking Patterns

User Authentication

Track when customers log in or create accounts:

Ecwid.OnAPILoaded.add(function() {

  // Track login
  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'ACCOUNT_SETTINGS') {
      // Customer logged in and viewing account

      Ecwid.getCustomerInfo(function(customer) {
        if (customer && customer.id) {
          gtag('event', 'login', {
            method: 'Ecwid Account'
          });

          // Set user ID for cross-session tracking
          gtag('config', 'G-XXXXXXXXXX', {
            'user_id': customer.id.toString()
          });
        }
      });
    }
  });

});

Promotion Clicks

Track when customers click promotional banners:

// For custom promo banners on host page
document.querySelectorAll('.promo-banner').forEach(function(banner) {
  banner.addEventListener('click', function() {
    gtag('event', 'select_promotion', {
      promotion_id: this.dataset.promoId,
      promotion_name: this.dataset.promoName,
      creative_name: this.dataset.creativeName,
      creative_slot: this.dataset.slot
    });
  });
});

Product Variant Selection

Track when customers select product options:

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    if (page.type === 'PRODUCT') {

      // Note: Ecwid doesn't provide direct variant change event
      // Alternative: Track after option selection leads to add to cart
      Ecwid.OnCartChanged.add(function(cart) {
        var lastItem = cart.items[cart.items.length - 1];
        if (lastItem && lastItem.selectedOptions) {

          gtag('event', 'variant_selected', {
            item_id: lastItem.product.id.toString(),
            item_name: lastItem.product.name,
            variant: lastItem.selectedOptions.map(opt => opt.value).join(' / ')
          });
        }
      });
    }
  });

});

Enhanced Ecommerce with User Properties

Set custom user properties for better segmentation:

Ecwid.OnAPILoaded.add(function() {

  Ecwid.getCustomerInfo(function(customer) {
    if (customer && customer.id) {

      // Set user properties
      gtag('set', 'user_properties', {
        customer_id: customer.id.toString(),
        customer_type: customer.customerGroupId ? 'wholesale' : 'retail',
        lifetime_orders: customer.orderCount || 0,
        lifetime_value: customer.totalSpent || 0
      });
    }
  });

});

Implement GDPR/CCPA compliant tracking:

// Set default consent before GA4 loads
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}

gtag('consent', 'default', {
  'analytics_storage': 'denied',
  'ad_storage': 'denied',
  'ad_user_data': 'denied',
  'ad_personalization': 'denied',
  'wait_for_update': 500
});

// Initialize GA4
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
// When user accepts cookies
function acceptCookies() {
  gtag('consent', 'update', {
    'analytics_storage': 'granted',
    'ad_storage': 'granted',
    'ad_user_data': 'granted',
    'ad_personalization': 'granted'
  });
}

// When user rejects
function rejectCookies() {
  gtag('consent', 'update', {
    'analytics_storage': 'denied',
    'ad_storage': 'denied',
    'ad_user_data': 'denied',
    'ad_personalization': 'denied'
  });
}

Debugging Events

Enable Debug Mode

gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});

Console Logging

Add logging to track what fires:

Ecwid.OnAPILoaded.add(function() {

  Ecwid.OnPageLoad.add(function(page) {
    console.log('Ecwid Page Loaded:', page.type);
  });

  Ecwid.OnCartChanged.add(function(cart) {
    console.log('Cart Changed:', cart);
  });

  Ecwid.OnOrderPlaced.add(function(order) {
    console.log('Order Placed:', order);
  });

});

Check Data Layer

// View all data layer events
console.table(window.dataLayer);

// Filter specific events
console.log(
  window.dataLayer.filter(item => item.event === 'purchase')
);

Testing Checklist

  • Product view - view_item fires with correct product data
  • Category view - view_item_list includes multiple products
  • Add to cart - add_to_cart fires with quantity
  • Remove from cart - remove_from_cart detects removals
  • Begin checkout - begin_checkout fires on first checkout step
  • Purchase - purchase fires with transaction ID and revenue
  • Custom events - All custom events fire as expected
  • User properties - Set correctly for logged-in users
  • No duplicates - Events don't fire multiple times
  • Consent respected - Tracking honors consent choices

Common Issues

Events Fire Multiple Times

Cause: Event listeners attached multiple times.

Fix: Use flags to prevent duplicate tracking:

var eventFired = false;

Ecwid.OnOrderPlaced.add(function(order) {
  if (eventFired) return;
  eventFired = true;

  // Track purchase
  gtag('event', 'purchase', {...});
});

Ecwid API Not Available

Cause: Code runs before Ecwid loads.

Fix: Always wrap in Ecwid.OnAPILoaded.add():

// Wrong
Ecwid.OnCartChanged.add(function(cart) {
  // Won't work if Ecwid not loaded yet
});

// Correct
Ecwid.OnAPILoaded.add(function() {
  Ecwid.OnCartChanged.add(function(cart) {
    // Guaranteed to work
  });
});

Missing Product Data

Cause: API not returning full product details.

Fix: Use Ecwid.getProduct() to fetch complete data:

// Instead of relying on page data
Ecwid.getProduct(productId, function(product) {
  // Full product details available here
});

Next Steps

For general GA4 event concepts, see GA4 Event Tracking Guide.