Skip to main content
While Ollie Shop automatically tracks standard e-commerce events, you may want to track additional user interactions specific to your business. Custom events allow you to measure engagement with promotional banners, loyalty programs, form interactions, and any other checkout elements you’ve built.

Real-World Example: VIP Enrollment

Imagine you’ve added a VIP program enrollment option to your checkout. When customers opt-in, you want to track this decision in your analytics to measure program adoption and correlate it with purchase behavior. Here’s how a custom component can send a vip_enrollment event when a customer joins:
VipEnrollmentButton.tsx
'use client'

import React from 'react';
import styles from './styles.module.css';

export default function VipEnrollmentButton() {
  const handleEnrollment = () => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'vip_enrollment',
      enrollment_source: 'checkout'
    });
  };

  return (
    <button onClick={handleEnrollment} className={styles.button}>
      Join VIP Program
    </button>
  );
}
When a customer clicks the button, the vip_enrollment event is pushed to the dataLayer, where GTM captures it and forwards it to GA4 or any other analytics platform you’ve configured.
You can enrich this event with session data using GTM Custom HTML tags—for example, adding customer segment or cart value context.

How It Works

Custom events are sent to Google Tag Manager via the dataLayer object—a JavaScript array that GTM uses as a communication layer between your website and tags.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  event: 'your_event_name',
  // ... additional parameters
});
Learn more about the dataLayer in the GTM dataLayer documentation.

Prerequisites

Implementation Details

Add this type declaration at the top of your custom component to get type safety and IDE autocompletion for the dataLayer:
declare global {
  interface Window {
    dataLayer?: Record<string, unknown>[];
  }
}
VipEnrollmentButton.tsx
'use client'

import React from 'react';
import styles from './styles.module.css';

declare global {
  interface Window {
    dataLayer?: Record<string, unknown>[];
  }
}

export default function VipEnrollmentButton() {
  const handleEnrollment = () => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'vip_enrollment',
      enrollment_source: 'checkout'
    });
  };

  return (
    <button onClick={handleEnrollment} className={styles.button}>
      Join VIP Program
    </button>
  );
}

Event Naming Best Practices

Follow these conventions to keep your analytics data clean and actionable:
ConventionExampleDescription
Use snake_casevip_enrollmentConsistent with GA4 standard events
Be descriptiveshipping_method_selectedMakes reports easier to understand
Include contextcheckout_promo_appliedHelps segment by checkout stage
Avoid generic namesbutton_clickToo vague for meaningful analysis
Event names in GA4 are case-sensitive and limited to 40 characters. Avoid spaces and special characters. See GA4 event naming rules.

Configuring GTM to Capture Custom Events

After pushing events to the dataLayer, configure GTM to capture and forward them:
  1. Create a Custom Event Trigger in GTM matching your event name (e.g., vip_enrollment)
  2. Create a GA4 Event Tag that fires on this trigger
  3. Map any custom parameters to GA4 event parameters
  4. Test using GTM’s Preview mode before publishing
Use GTM’s Preview mode to verify events are being captured correctly before publishing your container.

Further Reading