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