GA4 Event Tracking on Salesforce Commerce Cloud | Blue Frog Docs

GA4 Event Tracking on Salesforce Commerce Cloud

Implement custom event tracking for GA4 on SFCC with SFRA

GA4 Event Tracking on Salesforce Commerce Cloud

This guide covers implementing custom event tracking beyond basic page views on Salesforce Commerce Cloud.

SFCC Event Architecture

SFCC uses a combination of server-side and client-side event handling:

  • Server-side hooks - Pipeline and controller hooks for backend events
  • Client-side events - JavaScript events for user interactions
  • AJAX responses - Event data returned from controller calls

Standard Events Implementation

Product View

Track when users view product detail pages:

// In your PDP client-side JavaScript
(function() {
    var productData = {
        item_id: '${product.ID}',
        item_name: '${product.name}',
        item_category: '${product.primaryCategory.displayName}',
        item_brand: '${product.brand}',
        price: ${product.price.sales.value}
    };

    gtag('event', 'view_item', {
        currency: '${session.currency.currencyCode}',
        value: productData.price,
        items: [productData]
    });
})();

Add to Cart

Hook into the SFRA cart controller:

cartridges/app_custom/cartridge/controllers/Cart.js

'use strict';

var server = require('server');
var Cart = module.superModule;

server.extend(Cart);

server.append('AddProduct', function (req, res, next) {
    var viewData = res.getViewData();

    if (viewData.cart && !viewData.error) {
        var productLineItem = viewData.cart.items[viewData.cart.items.length - 1];

        viewData.ga4Event = {
            event: 'add_to_cart',
            currency: viewData.cart.totals.currencyCode,
            value: productLineItem.price.sales.value * productLineItem.quantity,
            items: [{
                item_id: productLineItem.id,
                item_name: productLineItem.productName,
                price: productLineItem.price.sales.value,
                quantity: productLineItem.quantity
            }]
        };
    }

    res.setViewData(viewData);
    return next();
});

module.exports = server.exports();

Client-side handler for AJAX cart response:

// Listen for cart updates
$(document).on('cart:add:success', function(e, data) {
    if (data.ga4Event) {
        gtag('event', data.ga4Event.event, {
            currency: data.ga4Event.currency,
            value: data.ga4Event.value,
            items: data.ga4Event.items
        });
    }
});

Remove from Cart

$(document).on('cart:remove:success', function(e, data) {
    if (data.removedItem) {
        gtag('event', 'remove_from_cart', {
            currency: data.currencyCode,
            value: data.removedItem.price * data.removedItem.quantity,
            items: [{
                item_id: data.removedItem.id,
                item_name: data.removedItem.name,
                price: data.removedItem.price,
                quantity: data.removedItem.quantity
            }]
        });
    }
});

Begin Checkout

Track when users start the checkout process:

// In checkout controller or client-side
function trackBeginCheckout(cartData) {
    gtag('event', 'begin_checkout', {
        currency: cartData.currencyCode,
        value: cartData.totalPrice,
        items: cartData.items.map(function(item) {
            return {
                item_id: item.id,
                item_name: item.productName,
                price: item.price.sales.value,
                quantity: item.quantity
            };
        })
    });
}

Add Shipping Info

// After shipping method selection
function trackAddShippingInfo(shippingData) {
    gtag('event', 'add_shipping_info', {
        currency: shippingData.currencyCode,
        value: shippingData.totalPrice,
        shipping_tier: shippingData.shippingMethod,
        items: shippingData.items
    });
}

Add Payment Info

// After payment method selection
function trackAddPaymentInfo(paymentData) {
    gtag('event', 'add_payment_info', {
        currency: paymentData.currencyCode,
        value: paymentData.totalPrice,
        payment_type: paymentData.paymentMethod,
        items: paymentData.items
    });
}

Custom Events

Product Quick View

$(document).on('quickview:show', function(e, data) {
    gtag('event', 'select_item', {
        item_list_name: 'Quick View',
        items: [{
            item_id: data.product.id,
            item_name: data.product.name
        }]
    });
});

Wishlist Actions

// Add to wishlist
$(document).on('wishlist:add', function(e, data) {
    gtag('event', 'add_to_wishlist', {
        currency: data.currencyCode,
        value: data.price,
        items: [{
            item_id: data.productId,
            item_name: data.productName,
            price: data.price
        }]
    });
});

Search Events

// Track search queries
$(document).on('search:submit', function(e, data) {
    gtag('event', 'search', {
        search_term: data.query
    });
});

// Track search results viewed
$(document).on('search:results:load', function(e, data) {
    gtag('event', 'view_search_results', {
        search_term: data.query,
        items: data.products.slice(0, 10).map(function(p, i) {
            return {
                item_id: p.id,
                item_name: p.name,
                index: i
            };
        })
    });
});

Event Parameters Reference

Required Parameters by Event

Event Required Parameters
view_item items, currency, value
add_to_cart items, currency, value
remove_from_cart items, currency, value
begin_checkout items, currency, value
add_shipping_info items, shipping_tier
add_payment_info items, payment_type
purchase transaction_id, items, value, currency

Product Parameters

Parameter Type Description
item_id string Product SKU
item_name string Product name
item_category string Primary category
item_brand string Brand name
price number Unit price
quantity number Quantity
discount number Discount amount

Debugging Tips

  1. Use GA4 DebugView for real-time validation
  2. Check browser console for JavaScript errors
  3. Monitor Network tab for gtag requests
  4. Validate data layer pushes before gtag calls

Next Steps

// SYS.FOOTER