BigCommerce GA4 Ecommerce Tracking | Blue Frog Docs

BigCommerce GA4 Ecommerce Tracking

Complete guide to implementing GA4 enhanced ecommerce tracking on BigCommerce with Stencil data integration.

BigCommerce GA4 Ecommerce Tracking

Implement comprehensive ecommerce tracking for your BigCommerce store using Google Analytics 4. This guide covers the complete customer journey from product discovery to purchase.

GA4 Ecommerce Events Overview

GA4 tracks the ecommerce funnel using these recommended events:

Event Description When to Trigger
view_item_list User views product list Category pages, search results
select_item User clicks product from list Product card clicks
view_item User views product details Product page load
add_to_cart Product added to cart Add to cart button click
remove_from_cart Product removed from cart Remove from cart action
view_cart User views shopping cart Cart page load
begin_checkout User starts checkout Checkout initiation
add_payment_info Payment method selected Payment step in checkout
add_shipping_info Shipping method selected Shipping step in checkout
purchase Transaction completed Order confirmation page

Implementation Prerequisites

Before implementing ecommerce tracking:

  1. GA4 base tracking installed (see GA4 Setup)
  2. Stencil theme access (recommended) or Script Manager access
  3. Store admin access to configure checkout scripts
  4. BigCommerce plan that supports checkout script injection (Plus, Pro, or Enterprise)

This method provides full access to BigCommerce context data for accurate ecommerce tracking.

Step 1: Track Product Impressions (view_item_list)

File: templates/pages/category.html or templates/pages/search.html

{{#if products}}
<script>
(function() {
  // Wait for gtag to be available
  if (typeof gtag === 'undefined') return;

  // Build items array from BigCommerce product data
  var items = [
    {{#each products}}
    {
      item_id: '{{id}}',
      item_name: '{{name}}',
      item_brand: '{{brand.name}}',
      item_category: '{{category}}',
      price: {{price.without_tax.value}},
      currency: '{{../currency.code}}',
      index: {{@index}}
    }{{#unless @last}},{{/unless}}
    {{/each}}
  ];

  // Send view_item_list event
  gtag('event', 'view_item_list', {
    item_list_id: '{{category.id}}',
    item_list_name: '{{category.name}}',
    items: items
  });
})();
</script>
{{/if}}

Step 2: Track Product Clicks (select_item)

File: templates/components/products/card.html

<article class="card"
         data-product-id="{{id}}"
         data-event-type="product-click">
  <a href="{{url}}"
     data-product-name="{{name}}"
     data-product-price="{{price.without_tax.value}}"
     data-product-brand="{{brand.name}}"
     data-product-category="{{category}}"
     onclick="trackProductClick(this)">
    {{!-- Product card content --}}
  </a>
</article>

<script>
function trackProductClick(element) {
  if (typeof gtag === 'undefined') return;

  var productData = {
    item_id: element.closest('[data-product-id]').getAttribute('data-product-id'),
    item_name: element.getAttribute('data-product-name'),
    item_brand: element.getAttribute('data-product-brand'),
    item_category: element.getAttribute('data-product-category'),
    price: parseFloat(element.getAttribute('data-product-price')) || 0
  };

  gtag('event', 'select_item', {
    item_list_id: 'product_list',
    item_list_name: 'Product List',
    items: [productData]
  });
}
</script>

Step 3: Track Product Views (view_item)

File: templates/pages/product.html

{{#with product}}
<script>
(function() {
  if (typeof gtag === 'undefined') return;

  // Extract product data from BigCommerce context
  var product = {
    item_id: '{{id}}',
    item_name: '{{title}}',
    item_brand: '{{brand.name}}',
    {{#if category}}
    item_category: '{{category}}',
    {{/if}}
    price: {{price.without_tax.value}},
    currency: '{{../currency.code}}'
  };

  // Send view_item event
  gtag('event', 'view_item', {
    currency: '{{../currency.code}}',
    value: {{price.without_tax.value}},
    items: [product]
  });
})();
</script>
{{/with}}

Step 4: Track Add to Cart (add_to_cart)

File: assets/js/theme/common/cart-item-details.js or add inline to product page

import $ from 'jquery';

export default function trackAddToCart(productId, quantity = 1) {
  // Fetch product details from BigCommerce Storefront API
  fetch(`/api/storefront/products/${productId}`)
    .then(response => response.json())
    .then(product => {
      if (typeof gtag !== 'undefined') {
        gtag('event', 'add_to_cart', {
          currency: product.currency || 'USD',
          value: product.price.without_tax.value * quantity,
          items: [{
            item_id: product.id.toString(),
            item_name: product.name,
            item_brand: product.brand?.name || '',
            item_category: product.categories?.[0]?.name || '',
            price: product.price.without_tax.value,
            quantity: quantity
          }]
        });
      }
    })
    .catch(error => console.error('Error tracking add to cart:', error));
}

// Hook into BigCommerce add to cart event
$('body').on('cart-item-add', function(event, productId, quantity) {
  trackAddToCart(productId, quantity);
});

Step 5: Track Remove from Cart (remove_from_cart)

File: templates/components/cart/content.html or cart JavaScript

// Track remove from cart
document.addEventListener('click', function(e) {
  const removeButton = e.target.closest('[data-cart-remove]');

  if (removeButton) {
    const cartItem = removeButton.closest('[data-cart-item]');
    const itemId = cartItem?.getAttribute('data-item-id');
    const itemName = cartItem?.getAttribute('data-item-name');
    const itemPrice = parseFloat(cartItem?.getAttribute('data-item-price')) || 0;
    const itemQuantity = parseInt(cartItem?.getAttribute('data-item-quantity')) || 1;

    if (typeof gtag !== 'undefined' && itemId) {
      gtag('event', 'remove_from_cart', {
        currency: 'USD', // Or pull from context
        value: itemPrice * itemQuantity,
        items: [{
          item_id: itemId,
          item_name: itemName,
          price: itemPrice,
          quantity: itemQuantity
        }]
      });
    }
  }
});

Step 6: Track View Cart (view_cart)

File: templates/pages/cart.html

{{#if cart.items}}
<script>
(function() {
  if (typeof gtag === 'undefined') return;

  var cartItems = [
    {{#each cart.items}}
    {
      item_id: '{{id}}',
      item_name: '{{name}}',
      item_brand: '{{brand}}',
      price: {{price}},
      quantity: {{quantity}}
    }{{#unless @last}},{{/unless}}
    {{/each}}
  ];

  gtag('event', 'view_cart', {
    currency: '{{cart.currency.code}}',
    value: {{cart.grand_total}},
    items: cartItems
  });
})();
</script>
{{/if}}

Step 7: Track Checkout Initiation (begin_checkout)

For Optimized One-Page Checkout (Plus, Pro, Enterprise):

Go to Settings > Checkout, add to Header Scripts:

<script>
(function() {
  // Only fire on checkout page, not confirmation
  if (window.location.pathname.includes('/checkout') &&
      !window.location.pathname.includes('/order-confirmation')) {

    // Poll for checkout data to become available
    var checkoutDataInterval = setInterval(function() {
      // BigCommerce exposes checkout data in window object
      if (typeof BCData !== 'undefined' && BCData.checkout) {
        clearInterval(checkoutDataInterval);

        var checkout = BCData.checkout;
        var items = checkout.cart.lineItems.physicalItems.map(function(item) {
          return {
            item_id: item.productId.toString(),
            item_name: item.name,
            price: item.salePrice,
            quantity: item.quantity
          };
        });

        if (typeof gtag !== 'undefined') {
          gtag('event', 'begin_checkout', {
            currency: checkout.cart.currency.code,
            value: checkout.cart.baseAmount,
            items: items
          });
        }
      }
    }, 500);

    // Stop checking after 10 seconds
    setTimeout(function() {
      clearInterval(checkoutDataInterval);
    }, 10000);
  }
})();
</script>

Step 8: Track Purchase (purchase)

File: templates/pages/order-confirmation.html

{{#if order}}
<script>
(function() {
  if (typeof gtag === 'undefined') return;

  // Build transaction items array
  var items = [
    {{#each order.items}}
    {
      item_id: '{{product_id}}',
      item_name: '{{name}}',
      price: {{price}},
      quantity: {{quantity}}
    }{{#unless @last}},{{/unless}}
    {{/each}}
  ];

  // Send purchase event
  gtag('event', 'purchase', {
    transaction_id: '{{order.id}}',
    value: {{order.total}},
    tax: {{order.tax_total}},
    shipping: {{order.shipping_cost}},
    currency: '{{order.currency.code}}',
    coupon: '{{#if order.coupon_code}}{{order.coupon_code}}{{/if}}',
    items: items
  });
})();
</script>
{{/if}}

Alternative: Use Conversion Tracking Script (All Plans):

In Settings > Analytics, add to Conversion Tracking Code:

<script>
if (typeof gtag !== 'undefined') {
  gtag('event', 'purchase', {
    transaction_id: '%%ORDER_ID%%',
    value: %%ORDER_AMOUNT%%,
    tax: %%ORDER_TAX%%,
    shipping: %%ORDER_SHIPPING%%,
    currency: '%%GLOBAL_CurrencyCode%%',
    items: [
      %%GLOBAL_ProductCartItems%%
    ]
  });
}
</script>

Note: BigCommerce's %%GLOBAL_*%% variables are limited. For full purchase tracking, use order confirmation page template or upgrade to a plan with checkout script access.

Method 2: Script Manager Implementation (Limited)

For stores without Stencil access, you can implement basic ecommerce tracking via Script Manager, but with limitations.

Track Add to Cart via Script Manager

<script>
(function() {
  document.addEventListener('DOMContentLoaded', function() {
    // Listen for BigCommerce cart events
    document.addEventListener('click', function(e) {
      const addToCartBtn = e.target.closest('[data-button-type="add-cart"]') ||
                          e.target.closest('.button--add-to-cart');

      if (addToCartBtn) {
        // Limited data available without Stencil context
        // You would need to scrape product details from DOM
        const productCard = addToCartBtn.closest('[data-product-id]');

        if (productCard && typeof gtag !== 'undefined') {
          const productId = productCard.getAttribute('data-product-id');

          gtag('event', 'add_to_cart', {
            items: [{
              item_id: productId,
              item_name: 'Product ' + productId // Limited info
            }]
          });
        }
      }
    });
  });
})();
</script>

Limitations:

  • Cannot easily access structured product data
  • Requires DOM scraping which is fragile
  • Stencil theme method is strongly recommended

Tracking with BigCommerce Apps

Using Native BigCommerce Google Analytics App

The official app provides automatic ecommerce tracking but with limitations:

What's Tracked:

  • Product impressions (limited data)
  • Add to cart
  • Checkout steps
  • Purchases

Limitations:

  • Cannot customize event structure
  • Limited access to custom parameters
  • No control over data layer
  • Basic implementation only

When to Use:

  • Quick setup for basic stores
  • No development resources available
  • Standard tracking requirements

When to Avoid:

  • Need custom ecommerce events
  • Advanced tracking requirements
  • Custom dimensions or parameters
  • Integration with GTM data layer

Enhanced Ecommerce Best Practices

1. Include Product Variants

When tracking variants, include variant information:

gtag('event', 'add_to_cart', {
  items: [{
    item_id: '{{product.id}}',
    item_name: '{{product.name}}',
    item_variant: '{{selectedVariant.name}}', // e.g., "Red / Large"
    price: {{selectedVariant.price}},
    quantity: quantity
  }]
});

2. Track Product Categories Hierarchically

Use category hierarchy for better reporting:

{
  item_id: '{{product.id}}',
  item_name: '{{product.name}}',
  item_category: 'Apparel',        // Level 1
  item_category2: 'Men',            // Level 2
  item_category3: 'T-Shirts',       // Level 3
  item_category4: 'Graphic Tees'    // Level 4
}

3. Use Consistent Currency

Always include currency in ecommerce events:

gtag('event', 'purchase', {
  currency: '{{currency.code}}', // USD, EUR, GBP, etc.
  value: {{order.total}},
  // ... other parameters
});

4. Include Promotion Tracking

Track promotional banners and special offers:

// View promotion
gtag('event', 'view_promotion', {
  creative_name: 'Summer Sale Banner',
  creative_slot: 'homepage_hero',
  promotion_id: 'SUMMER2024',
  promotion_name: 'Summer Sale',
  items: [/* products in promotion */]
});

// Select promotion
gtag('event', 'select_promotion', {
  creative_name: 'Summer Sale Banner',
  creative_slot: 'homepage_hero',
  promotion_id: 'SUMMER2024',
  promotion_name: 'Summer Sale'
});

Testing Ecommerce Tracking

1. Use GA4 DebugView

Enable debug mode:

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

Then go to Admin > DebugView in GA4 to see events in real-time with full parameters.

2. Test Complete Funnel

Walk through the entire customer journey:

  1. View category page → Check view_item_list
  2. Click product → Check select_item
  3. View product page → Check view_item
  4. Add to cart → Check add_to_cart
  5. View cart → Check view_cart
  6. Start checkout → Check begin_checkout
  7. Complete purchase → Check purchase

3. Verify in E-commerce Reports

After 24-48 hours, check:

  • Reports > Monetization > Ecommerce purchases
  • Reports > Monetization > Purchase journey
  • Explorations > Funnel exploration (create custom funnel)

4. Validate Transaction IDs

Ensure transaction_id in purchase events matches actual order IDs from BigCommerce:

  1. Complete test order
  2. Note order number from BigCommerce admin
  3. Check GA4 DebugView or Realtime report
  4. Verify transaction_id matches order number

Troubleshooting

Purchase Events Firing Twice

Cause: Purchase tracking implemented in multiple places (theme + Script Manager + app)

Solution:

  • Remove duplicate implementations
  • Choose ONE method: theme template OR conversion tracking script OR native app
  • Clear cache and test again

Missing Product Data in Events

Cause: Incorrect context access or timing issues

Solution:

  • Verify \{\{product\}\} context is available in template
  • Use browser console to inspect BCData object
  • Ensure events fire after product data loads
  • Use Storefront API to fetch missing data

Ecommerce Events Not in GA4

Cause: Events sent but not recognized as ecommerce

Solution:

  • Verify event names match GA4 recommended events exactly (purchase, not Purchase or completed_purchase)
  • Include required parameters (items array, currency, value)
  • Check item objects have required fields (item_id, item_name)

Checkout Tracking Not Working

Cause: BigCommerce plan limitations or script placement

Solution:

  • Verify you're on Plus, Pro, or Enterprise plan
  • Check Scripts are in Settings > Checkout > Header Scripts
  • Ensure scripts load before checkout page renders
  • Test in incognito mode to avoid caching issues

Advanced: Server-Side Tracking

For more accurate tracking that bypasses ad blockers:

Using BigCommerce Webhooks

  1. Set up webhook in BigCommerce:

    • Go to Settings > API > Webhooks
    • Create webhook for store/order/created
  2. Send to GA4 Measurement Protocol:

// Your webhook endpoint (Node.js example)
app.post('/webhooks/order-created', async (req, res) => {
  const order = req.body.data;

  // Send to GA4 Measurement Protocol
  await fetch(`https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=YOUR_API_SECRET`, {
    method: 'POST',
    body: JSON.stringify({
      client_id: order.customer_id.toString(),
      events: [{
        name: 'purchase',
        params: {
          transaction_id: order.id.toString(),
          value: order.total,
          currency: order.currency_code,
          tax: order.tax_total,
          shipping: order.shipping_cost,
          items: order.products.map(item => ({
            item_id: item.product_id.toString(),
            item_name: item.name,
            price: item.price,
            quantity: item.quantity
          }))
        }
      }]
    })
  });

  res.status(200).send('OK');
});

Next Steps

Additional Resources

// SYS.FOOTER