Install Google Analytics 4 on SAP Commerce Cloud | OpsBlu Docs

Install Google Analytics 4 on SAP Commerce Cloud

Step-by-step GA4 installation and configuration guide for SAP Commerce Cloud (Hybris).

This guide covers implementing GA4 on SAP Commerce Cloud for both Spartacus (headless) and Accelerator (traditional) storefronts.

Method Comparison

Method Storefront Difficulty Customization
Spartacus Module Spartacus Medium High
Accelerator Extension Accelerator Medium Medium
Google Tag Manager Both Medium Highest

Spartacus Implementation

Step 1: Create Analytics Module

Generate a dedicated analytics module:

ng generate module analytics --routing=false

Step 2: Create Analytics Service

src/app/analytics/analytics.service.ts

import { Injectable } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { EventService } from '@spartacus/core';
import { filter } from 'rxjs/operators';

declare global {
  interface Window {
    dataLayer: any[];
    gtag: (...args: any[]) => void;
  }
}

@Injectable({ providedIn: 'root' })
export class AnalyticsService {
  private measurementId: string;

  constructor(
    private router: Router,
    private eventService: EventService
  ) {}

  initialize(measurementId: string): void {
    this.measurementId = measurementId;
    this.loadGtag();
    this.setupPageTracking();
    this.setupEventTracking();
  }

  private loadGtag(): void {
    const script = document.createElement('script');
    script.src = `https://www.googletagmanager.com/gtag/js?id=${this.measurementId}`;
    script.async = true;
    document.head.appendChild(script);

    window.dataLayer = window.dataLayer || [];
    window.gtag = function() {
      window.dataLayer.push(arguments);
    };

    window.gtag('js', new Date());
    window.gtag('config', this.measurementId, {
      send_page_view: false
    });
  }

  private setupPageTracking(): void {
    this.router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe((event: NavigationEnd) => {
        this.trackPageView(event.urlAfterRedirects);
      });
  }

  private setupEventTracking(): void {
    // Subscribe to Spartacus events
    this.eventService.get('CartAddEntrySuccessEvent').subscribe(event => {
      this.trackAddToCart(event);
    });

    this.eventService.get('OrderPlacedEvent').subscribe(event => {
      this.trackPurchase(event);
    });
  }

  trackPageView(url: string): void {
    window.gtag('event', 'page_view', {
      page_path: url,
      page_title: document.title
    });
  }

  trackAddToCart(event: any): void {
    window.gtag('event', 'add_to_cart', {
      currency: event.currency,
      value: event.entry.totalPrice.value,
      items: [{
        item_id: event.entry.product.code,
        item_name: event.entry.product.name,
        price: event.entry.basePrice.value,
        quantity: event.entry.quantity
      }]
    });
  }

  trackPurchase(event: any): void {
    window.gtag('event', 'purchase', {
      transaction_id: event.order.code,
      value: event.order.totalPrice.value,
      currency: event.order.totalPrice.currencyIso,
      tax: event.order.totalTax?.value || 0,
      shipping: event.order.deliveryCost?.value || 0,
      items: event.order.entries.map(entry => ({
        item_id: entry.product.code,
        item_name: entry.product.name,
        price: entry.basePrice.value,
        quantity: entry.quantity
      }))
    });
  }
}

Step 3: Initialize in App Module

src/app/app.module.ts

import { APP_INITIALIZER, NgModule } from '@angular/core';
import { AnalyticsService } from './analytics/analytics.service';

function initializeAnalytics(analyticsService: AnalyticsService) {
  return () => {
    analyticsService.initialize('G-XXXXXXXXXX');
  };
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initializeAnalytics,
      deps: [AnalyticsService],
      multi: true
    }
  ]
})
export class AppModule {}

Accelerator Implementation

Step 1: Create Analytics Extension

Create a new extension for analytics:

ant extgen -Dinput.template=yempty -Dinput.name=myanalytics

Step 2: Add GTM Tag Library

myanalytics/web/webroot/WEB-INF/tags/analytics/gtm.tag

<%@ tag body-content="empty" %>
<%@ attribute name="measurementId" required="true" type="java.lang.String" %>

<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=${measurementId}"></script>
<script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', '${measurementId}', {
        send_page_view: false
    });
</script>

Step 3: Include in Master Template

storefront/web/webroot/WEB-INF/views/responsive/pages/layout/landingLayoutPage.jsp

<%@ taglib prefix="analytics" tagdir="/WEB-INF/tags/analytics" %>

<head>
    <analytics:gtm measurementId="${googleAnalyticsMeasurementId}"/>
</head>

Step 4: Configure Properties

myanalytics/project.properties

google.analytics.measurement.id=G-XXXXXXXXXX
google.analytics.enabled=true

Server-Side Tracking

For enhanced ecommerce, implement server-side tracking:

AnalyticsFacade.java

@Service
public class DefaultAnalyticsFacade implements AnalyticsFacade {

    @Value("${google.analytics.measurement.id}")
    private String measurementId;

    @Value("${google.analytics.api.secret}")
    private String apiSecret;

    @Override
    public void trackPurchase(OrderModel order) {
        Map<String, Object> event = new HashMap<>();
        event.put("name", "purchase");

        Map<String, Object> params = new HashMap<>();
        params.put("transaction_id", order.getCode());
        params.put("value", order.getTotalPrice());
        params.put("currency", order.getCurrency().getIsocode());

        List<Map<String, Object>> items = new ArrayList<>();
        for (AbstractOrderEntryModel entry : order.getEntries()) {
            Map<String, Object> item = new HashMap<>();
            item.put("item_id", entry.getProduct().getCode());
            item.put("item_name", entry.getProduct().getName());
            item.put("price", entry.getBasePrice());
            item.put("quantity", entry.getQuantity());
            items.add(item);
        }
        params.put("items", items);

        event.put("params", params);

        sendToMeasurementProtocol(event);
    }

    private void sendToMeasurementProtocol(Map<String, Object> event) {
        String url = String.format(
            "https://www.google-analytics.com/mp/collect?measurement_id=%s&api_secret=%s",
            measurementId, apiSecret
        );

        // Send HTTP POST request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .POST(HttpRequest.BodyPublishers.ofString(toJson(event)))
            .header("Content-Type", "application/json")
            .build();

        client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
    }
}

Verification

Spartacus Debugging

// Enable debug mode in development
if (!environment.production) {
  window.gtag('config', 'G-XXXXXXXXXX', {
    debug_mode: true
  });
}

Accelerator Debugging

Enable logging in HAC:

Logging > Set log level > de.hybris.analytics=DEBUG

Next Steps