Skip to main content

Sending analytics to Google Analytics (GA4)

Atomic provides a webhook subscriptions capability for sending analytic events in near real-time to external cloud services and applications.

This tutorial is written specifically for setting up webhooks for Google Analytics. It describes how to set up a webhook subscription configuration that sends Atomic analytics to the Google Measurement Protocol API to populate a GA4 profile. The script provided is intended as a starting point; your implementation should be thoroughly tested to ensure it meets your specific requirements.

Using a webhook subscription is not the only way to send Atomic analytics events into GA. You may prefer to extract Atomic analytics from our API using our real-time analytics or batch analytics endpoints and load these into your GA property. This approach is recommended if you have an existing ETL/IPaaS platform, custom data pipeline, existing internal tools, or capability. If you have more complex data-flow requirements and you want to enrich Atomic events before sending them to GA, using the Analytics API would also be a more appropriate pattern to implement. You can read more about both batched data and real-time data analytics in the Analytics guide.


To follow the steps in this tutorial, you will need:

  • Edit level permissions to the webhook resource in your Atomic environment, so that you can configure the outgoing webhook subscription.
  • A Google Analytics GA4 account with at least 1 GA4 property that you can configure to receive analytic events from Atomic.
  • Suitable admin permission to the Google Analytics GA4 account.
  • The 'Measurement ID' for the GA Property you will send Atomic events to (you can locate this by navigating in the Google Analytics UI to: Admin > Data Streams > Choose your stream).
  • An API Secret for the GA Property you will send Atomic events to. To view API secrets, navigate in the Google Analytics UI to: Admin > Data Streams > Choose your stream > Measurement Protocol API Secrets. You can also create a new secret in this screen if needed.
  • A list of the specific analytics event names that you plan to send from Atomic to Google Analytics. A complete overview of Atomic analytic events can be found in the Analytics reference guide. This includes custom events that are sent to the Atomic platform via SDK or API.

Configure your GA4 property to expect Atomic Events

In this step, you will define a Custom Event for each Atomic Event you want to receive in GA.

Create a Custom Event

Refer to the official documentation provided by Google ( if you have any issues setting up GA properties and/or custom events.

  1. Navigate in the Google Analytics UI to: Admin > Data Streams > Create custom events.
  2. Click the Create button.
  3. The custom event name can be anything that is meaningful for you.
  4. The value of the event_name parameter should match the name of the Atomic analytics event.
    If the event name in Atomic has hyphens, you will need to replace those with underscores. (e.g. card-completed becomes card_completed for GA4).

The screenshot below shows how to create a GA custom event for a card-completed Atomic analytic event.

Screenshot of configuring a Custom Event in the GA admin area
Create a custom event in Google Analytics

You can repeat these steps for all Atomic analytics events and/or custom events you want to stream to Google Analytics. Some of your analytics may contain Personally Identifiable Information (PII) - you may want to avoid sending these to Google.

Learn more

Read more about modifying and creating events in Google Analytics:

Configure Atomic to send analytics to GA using webhooks

  1. From the Config section of the Atomic Workbench, navigate to the webhook subscriptions area.
  2. Create a new subscription by clicking the New subscription button.
  3. Select all cards, give your webhook a meaningful name, and select all of the events you created a custom event for in the previous step (see screenshot below).
Screenshot of configuring a Webhook subscription in the Atomic Workbench
Add a Webhook subscription to send events to GA
  1. Select POST as request method.
  2. In the URL field, paste the following URL (updated with the specific values for your GA property API secret and measurement id - read the prerequisites section again if you have problems locating these in the GA dashboard).
  1. You do not need to provide headers or a credential (since they're already part of the URL above), you can leave these fields blank.
  2. Click save to create your webhook subscription. In the webhook subscriptions overview, find your newly created subscription, and click on the 3 dots on the right to open the overflow menu. Select edit mapping.
  3. Copy paste the script below into the script mapping field in the upper left hand corner. You can leave the comments in the script.
  4. After pasting in the script, scroll down and click the save changes button.
// Setup

// Can be optionally added to later
const userProps = {};

// Assists in converting ISO timestamp to GA's required Unix microseconds
const date = new Date(data.timestamp);

// If you definitely don't want certain event properties to pass through,
// edit this list to add the event property names. It is not recommended
// to pass 'values' through to GA given they may contain PII, but you can
// extend/customize this to suit your use case.
// A list of Atomic properties is available at
const propertiesToExclude = ['values','resolvedVariables'];

// Generates a filtered set of event properties to pass through to GA
// NB: not all Atomic events will have properties, so this may return empty
const filteredProps = Object.keys(
.filter((key) => !propertiesToExclude.includes(key))
.reduce((obj, key) => {
return Object.assign(obj, {

// Required: GA expects a property for engagement time -
// this script hardcodes engagement time to 100 milliseconds
// Note: Atomic does not have sessions, so there is no simple session value
// to map here, although you can make one of your own if you wish
filteredProps["engagement_time_msec"] = "100";

// you might also want to map other properties from the atomic event
// into your GA event params. Simple examples:
filteredProps["atomicSdkPlatform"] = data.sdkContext.platform;
filteredProps["atomicCardTemplate_id"] = data.cardContext.cardTemplateId;
filteredProps["atomicCardTemplate_name"] = data.cardContext.cardTemplateName;
filteredProps["atomicCardTemplate_version"] = data.cardContext.cardTemplateVersion;

// Optional: map values from the Atomic analytics payload to any
// custom user properties you have configured (note: in your
// implementation, you may need to handle value not-found scenarios
// more robustly than in this simple example)
userProps['timezone'] = data.sdkContext.sdkTimezone;

// This part of the script determines the final webhook payload body shape
// It can be extended or modified to fit Google's full guidelines and parameters
// GA4 documentation can be located here:
// Limitations are described here:

"client_id": data.endUserId,
"user_id": data.endUserId,
"timestamp_micros": date.getTime() * 1000,
"user_properties": userProps,
"events": [{
"name": data.eventName.replace('-', '_'),
"params": filteredProps

Optional: Using the Client ID created by Google

Using the code above, you will be setting the Client Id and the User Id value to the Atomic Id. If it is important to your tracking that you have Atomic pass the real CLient Id from your user's cookie set by Google, then you will need to do the following:

  • Get the Client Id value from the GA cookie using JavaScript on your front-end
  • Pass that to Atomic. We would suggest adding the Client Id as a JWT claim, the mapping that value into a Custom Field, which can then be accessed in the Webhook mapping.
  • Updating the above mapping script to set the value of client_id from the custom profile field.


Before connecting the webhook subscriptions to Google Analytics, you can use a website such as to test whether:

  • requests are made when you expect (when certain analytic events occur)
  • the data shape of the POST request payload matches what Google Analytics expects