General Guide: See Global Events Not Firing Guide for universal concepts and fixes.
SAP Commerce-Specific Causes
1. SSR vs CSR Context Issues
Code running in wrong rendering context:
// Problem: Window not available during SSR
constructor() {
window.dataLayer.push({}); // Error on server!
}
2. Observable Subscription Issues
Events lost due to unsubscribed observables:
// Problem: Subscription completes before event fires
this.eventService.get('CartAddEntrySuccessEvent')
.pipe(take(1)) // Only captures first event!
.subscribe(event => this.track(event));
3. Spartacus Event Service Timing
Event service not initialized before subscription:
// Problem: Service not ready
ngOnInit() {
this.eventService.get('PageEvent').subscribe(); // May miss early events
}
4. Accelerator JSP Include Order
Tag libraries loaded after tracking code:
<!-- Problem: dataLayer used before GTM loads -->
<script>
dataLayer.push({'event': 'pageView'}); // dataLayer undefined!
</script>
<%@ taglib prefix="analytics" tagdir="/WEB-INF/tags/analytics" %>
<analytics:gtm containerId="${gtmId}"/>
SAP Commerce-Specific Fixes
Fix 1: Check Platform Before Browser APIs
Always verify platform context:
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { PLATFORM_ID, Inject } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class TrackingService {
constructor(
@Inject(PLATFORM_ID) private platformId: Object
) {}
track(event: any): void {
// Only execute in browser
if (isPlatformBrowser(this.platformId)) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push(event);
}
}
// For server-side tracking
trackServerSide(event: any): void {
if (isPlatformServer(this.platformId)) {
// Use Measurement Protocol or server-side logging
this.sendToMeasurementProtocol(event);
}
}
}
Fix 2: Properly Manage Subscriptions
Use proper subscription management:
import { Subject, takeUntil } from 'rxjs';
@Component({...})
export class TrackingComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
constructor(private eventService: EventService) {}
ngOnInit(): void {
// Subscribe with takeUntil for cleanup
this.eventService.get('CartAddEntrySuccessEvent')
.pipe(takeUntil(this.destroy$))
.subscribe(event => this.trackAddToCart(event));
this.eventService.get('OrderPlacedEvent')
.pipe(takeUntil(this.destroy$))
.subscribe(event => this.trackPurchase(event));
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
Fix 3: Initialize Tracking Early
Use APP_INITIALIZER for early setup:
// tracking.module.ts
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { TrackingService } from './tracking.service';
export function initializeTracking(trackingService: TrackingService) {
return () => {
trackingService.initialize();
return Promise.resolve();
};
}
@NgModule({
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeTracking,
deps: [TrackingService],
multi: true
}
]
})
export class TrackingModule {}
// tracking.service.ts
@Injectable({ providedIn: 'root' })
export class TrackingService {
private initialized = false;
constructor(
@Inject(PLATFORM_ID) private platformId: Object,
private eventService: EventService
) {}
initialize(): void {
if (this.initialized || !isPlatformBrowser(this.platformId)) {
return;
}
// Initialize dataLayer
window.dataLayer = window.dataLayer || [];
// Set up event listeners
this.setupEventListeners();
this.initialized = true;
}
private setupEventListeners(): void {
// All event subscriptions here
}
}
Fix 4: Fix Accelerator Include Order
Correct tag library order in JSP:
<%-- 1. First: Initialize dataLayer --%>
<script>
window.dataLayer = window.dataLayer || [];
</script>
<%-- 2. Then: Load GTM --%>
<%@ taglib prefix="analytics" tagdir="/WEB-INF/tags/analytics" %>
<analytics:gtm containerId="${gtmId}"/>
<%-- 3. Finally: Push page data --%>
<analytics:pageData pageType="${pageType}"/>
Fix 5: Handle Checkout Events
Spartacus checkout requires special handling:
@Injectable({ providedIn: 'root' })
export class CheckoutTrackingService {
constructor(
private eventService: EventService,
private trackingService: TrackingService
) {
this.setupCheckoutTracking();
}
private setupCheckoutTracking(): void {
// Begin checkout
this.eventService.get('CheckoutDeliveryAddressSetEvent')
.subscribe(() => this.trackBeginCheckout());
// Add shipping info
this.eventService.get('CheckoutDeliveryModeSetEvent')
.subscribe(event => this.trackAddShippingInfo(event));
// Add payment info
this.eventService.get('CheckoutPaymentDetailsSetEvent')
.subscribe(event => this.trackAddPaymentInfo(event));
// Purchase complete
this.eventService.get('OrderPlacedEvent')
.subscribe(event => this.trackPurchase(event));
}
private trackBeginCheckout(): void {
this.trackingService.track({
event: 'begin_checkout'
});
}
private trackAddShippingInfo(event: any): void {
this.trackingService.track({
event: 'add_shipping_info',
shipping_tier: event.deliveryMode?.code
});
}
private trackAddPaymentInfo(event: any): void {
this.trackingService.track({
event: 'add_payment_info',
payment_type: event.paymentDetails?.cardType?.name
});
}
private trackPurchase(event: any): void {
this.trackingService.track({
event: 'purchase',
transaction_id: event.order.code,
value: event.order.totalPrice?.value,
currency: event.order.totalPrice?.currencyIso
});
}
}
Debugging Checklist
Spartacus
// Debug utility
@Injectable({ providedIn: 'root' })
export class TrackingDebugService {
constructor(@Inject(PLATFORM_ID) private platformId: Object) {}
debug(): void {
if (!isPlatformBrowser(this.platformId)) {
console.log('Running on server - tracking disabled');
return;
}
console.log('GTM loaded:', typeof google_tag_manager !== 'undefined');
console.log('dataLayer:', window.dataLayer);
console.log('dataLayer length:', window.dataLayer?.length);
}
}
Accelerator
<%-- Debug mode --%>
<c:if test="${debugMode}">
<script>
console.log('GTM Container:', '${gtmContainerId}');
console.log('dataLayer:', JSON.stringify(dataLayer, null, 2));
</script>
</c:if>
Common Error Patterns
| Symptom | Cause | Solution |
|---|---|---|
| No events in SSR | Browser API in server context | Use isPlatformBrowser |
| Missing cart events | Subscription timing | Use APP_INITIALIZER |
| Duplicate events | Multiple subscriptions | Manage with takeUntil |
| Events on some pages | Inconsistent module import | Import TrackingModule globally |