---
title: Configure Google Analytics 4 (GA4)
slug: feature-experimentation/docs/set-up-google-analytics-4-ga4
createdAt: 2026-08-05T20:39:58.000Z
---

:::hint{type="info"}
This is a third-party integration and is not an Optimizely subprocessor. See Optimizely's [Third-Party Add-Ons & Platform Integration Terms](https://www.optimizely.com/legal/third-party-add-ons-platform-integration-terms/).
:::

If you use Google Analytics to monitor your project’s traffic, you can view the results of your Optimizely experiments alongside the rest of the data that [Google Analytics](https://marketingplatform.google.com/about/analytics/) collects.

## Configure GA4 in Feature Experimentation

You can use a custom notification listener to configure GA4 in Optimizely Feature Experimentation. [Notification listeners](docId\:glBZD5gxka3gXu5_wyqHQ) let you programmatically observe and act on various events within the SDKs.

For information on how to configure a notification listener, select the corresponding SDK to view the developer documentation:

- [Android SDK](docId\:WHVC51tkUBxkQzO2LlnCY)
- [C# SDK](docId:1zV5jD23yJJWN9CEn8bj2)
- [Flutter SDK](docId\:l89LraHEHF2xZkaRp0HgK)
- [Go SDK](docId\:i8bJSjrFr0cJTTFq1VLdG)
- [Java SDK](docId\:C7k9iepPvnyura0fyEybL)
- [JavaScript SDK v6+](docId\:xp8vrQDVr0etJDPff8dcy)
- [JavaScript (Browser) SDK](docId\:psi8x-C4gE2jlMJC5_br8) – SDK versions 5.3.5 and below
- [JavaScript (Node) SDK](docId\:O0AMG145kpYCYrGH2G0uC) – SDK versions 5.3.5 and below
- [PHP SDK](docId\:ybbL9rcpc5tcdsMnLU_IE)
- [React SDK](docId\:zY6lbESn6QUIqvUQ_0iXH)
- [React Native SDK](docId\:nwjuvsZ672FYetF9VAh6l)
- [Ruby SDK](docId:_M5DJWsJq7Vtcj2qXQOb-)
- [Python SDK](docId\:r7E_NMjIGXHg7E5xFqVSW)
- [Swift SDK](docId\:rZ3rlzkpwEnk5DxMa9h_O)

:::hint{type="info"}
The following examples use the JavaScript (Browser) SDK.
:::

Example `onDecision` listener.

```javascript
const {
  createInstance,
  createPollingProjectConfigManager,
  NOTIFICATION_TYPES
} = require("@optimizely/optimizely-sdk");


const projectConfigManager = createPollingProjectConfigManager({
	sdkKey: ""
})

const optimizely = createInstance({
	projectConfigManager
});

const onDecision = ({ type, userId, attributes, decisionInfo }) => {
  // Add a DECISION Notification Listener for type FLAG
  if (type === 'flag') {
    // Access information about feature, for example, key and enabled status
    console.log(decisionInfo['flagKey']);
    console.log(decisionInfo['enabled']);
    console.log(decisionInfo['decisionEventDispatched']);
    if (decisionInfo['decisionEventDispatched']) {
      // Send data to analytics provider here
    }
  }
}

const notificationId = optimizely.notificationCenter.addNotificationListener(
  NOTIFICATION_TYPES.DECISION,
  onDecision
);
```

:::hint{type="info"}
The notification listener returns the decision. It is possible to update what is returned by editing the `onDecision` notification listener. Review the [Decision notifications listeners](docId\:wfUq0fCZCJ9jY1Fl1t5fx) developer documentation for information.
:::

Example of a **targeted delivery** `decisionInfo` object.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/_FkIKUw6Yh-cMWpWVroCw_27a6ae2-new-targeted-delivery-decisioninfo.png)

Example of an **experiment** `decisionInfo` object.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/jbsflMRCG750ZKUA3RsED_d840139-new-experiment-decisioninfo.png)

You can distinguish between a [flag delivery (targeted delivery)](docId\:R0KSPrSRYev0Q6jXL27QK) or an experiment ([A/B test](docId\:eJW6k2_6lGLnvTRoS2FIC) or [multi-armed bandit optimization](docId\:JaXCjRbh8BbYMGgmsuTvr)) based on `decisionEventDispatched`. An experiment has this value set to `true`. A targeted delivery returns `false`, as there is no dispatched event for rollouts. See the [decision event dispatched parameter](docId\:VvzGp6Ybax8O3PzZgzygn) developer documentation for information.

## Integrate with or without Google Tag Manager

You can configure the integration between Optimizely and GA4 with or without Google Tag Manager (GTM). You should use GTM to track the data and variables sent by Optimizely, as it makes timing issues much more manageable.

GTM lets you push items to GTM’s data layer even while the integration end object is unavailable, such as the Google Analytics (GA) object. Using GTM is especially useful if you run a back-end experiment and pass that information to your front-end to send it to GA.

Alternatively, configuring GA4 without GTM requires manually tracking the events and variables sent by Optimizely and verifying that they are sent after GA is initialized.

## With Google Tag Manager

### Push Optimizely data to Google Tag Manager

Push each Optimizely decision to the GTM `dataLayer` so GTM can forward the flag, rule, and variation to GA4. Add the following code to your `onDecision` notification listener, where the JavaScript SDK example sends data to your analytics provider:

```javascript
window.dataLayer = window.dataLayer || [];
dataLayer.push({
  // Must match the Event name of the GTM Custom Event trigger exactly
  'event': 'optimizely-decision-fs',
  'optimizely-flagKey': decisionInfo.flagKey,
  'optimizely-ruleKey': decisionInfo.ruleKey,
  'optimizely-variationKey': decisionInfo.variationKey,
});
```

### Create user-defined variables in Google Tag Manager

1. Go to **Workspace > Variables > New**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/EM2H-NX1eguUswdMEG-4n_a433f79-1.png)

2. Enter *Optimizely - flagKey* in the variable's name field.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/J-4P04jam1mCv51qpQcWV_96acad0-2.png)

3. Click **Variable Configuration** and select **Data Layer Variable**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/_nwsq_E0l9N-kwTgvDdJV_70bee4e-3.png)

4. In the **Data Layer Variable Name** field, enter *optimizely-flagKey*.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/jJeP2JmqOHkOVVnVzmRVH_055227d-4.png)

5. Click **Save**.
6. Repeat steps one through five to create a ruleKey and variationKey data layer variable with the following information:

| Variable     | Variable name             | Data layer variable name  |
| ------------ | ------------------------- | ------------------------- |
| ruleKey      | Optimizely - ruleKey      | `optimizely-ruleKey`      |
| variationKey | Optimizely - variationKey | `optimizely-variationKey` |

When completed, you should have the following user-defined data layer variables:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/CeZ7gKWesoWIYMEJCQFXo_4eba3bd-user-defined-variable.png)

### Configure the configuration tag in GTM

1. Go to **Workspace > Tags > New**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/SS0a8agrIeamjA_nKyszR_56ecd68-1-tags.png)

2. Enter *Google Analytics GA4 Configuration* in the name field.
3. Click **Tag Configuration** and select **Google Analytics: GA4 Configuration**.
   Enter your Measurement ID. For information on where to find your Measurement ID, refer to the [GA4 documentation](https://support.google.com/analytics/answer/9539598).

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/1wRnDt5ZCF1W5LaXdCX8i_133744b-3-tags.png)

4. Click **Triggering** and select **Initialization - All Pages**.
5. Click **Save**.

### Configure the event tag in GTM

1. Go to **Workspace > Tags > New**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/6X-xMNEWFPrtFVjChSW4w_f664e52-1-events.png)

2. Enter *Optimizely - GA4 EventUpdate* in the name field.
3. Click **Tag Configuration** and select **Google Analytics: GA4 Event**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/SnJaEbj3tAJzItqDGPGA1_04f0823-3-events.png)

:::hint{type="info"}
If you plan on creating both an Optimizely Web Experimentation experiment and a Feature Experimentation experiment, you may want to differentiate between your projects.

As a best practice, name your event: `optimizely-decision-fs` for Feature Experimentation and `optimizely-decision-web` for Web.

For instructions on setting up Optimizely Web Experimentation and GA4, review the corresponding documentation:

- [Integration Optimizely Web Experimentation with Google Analytics 4](docId\:CdTRiIxfUIWJ6YyWdmQKM)
- [Integration Optimizely Web Experimentation with Google Analytics 4 using Google Tag Manager](docId\:bl7Kf7SQDgmer6F4-guiG)
:::

4. Enter *optimizely-decision-fs* in the **Event Name** field.
5. Select **Google Analytics GA4 Configuration** in the **Configuration Tag** drop-down menu.
6. Expand **Event Parameters**.
   a) Select **Add Row**.
   b) Enter `Flag` in the **Parameter Name** field.
   c) In the **Value** field, select the **Choose a Variable** icon and select **Optimizely - flagKey**, which you created in Step two.
   d) Repeat steps a-c for `Rule` and `Variation`, selecting the corresponding data layer variable for each.

When complete, your Tag Configuration should look like the following:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/vX6cMeOCCmn5PffEB_mlk_5c8e642-6.png)

7. Click **Triggering** and click **New Trigger (+)** to create the following trigger:
   a) Enter *Optimizely - GA4 Trigger* as the trigger name.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/SzfDgGswIOKcZ-SnC5L6-_36a3b12-7a.png)

b) Click **Trigger Configuration**, scroll down, and select **Custom Event**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/G4TTJrvgModAe5bk_yDSZ_316eccd-7b.png)

c) In the **Event name** field, enter *optimizely-decision-fs*. Click **Save**.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/D2AyigXNFpVSVbQnTGg-3_ac020f7-7c.png)

d) Then click **Save** again on the overall tag configuration page.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/soy-5YVH1gNHwHYohTLin_76fc43c-7d.png)

### Match the event names in your code and GTM

Match the event names exactly so GTM sends every Optimizely decision to GA4. A GTM Custom Event trigger fires only when the `event` value in `dataLayer.push` equals the trigger **Event name**, including capitalization. When the names differ, the trigger does not fire. GA4 then reports `(not set)` for the `Flag`, `Rule`, and `Variation` parameters.

The following table lists the three event name settings and which ones must match:

| Setting        | Location                 | Must match                                                                         |
| -------------- | ------------------------ | ---------------------------------------------------------------------------------- |
| `event` value  | `dataLayer.push` code    | Yes. Matches the trigger **Event name**, for example `optimizely-decision-fs`.     |
| **Event name** | GTM Custom Event trigger | Yes. Matches the `event` value in your code, for example `optimizely-decision-fs`. |
| **Event Name** | GA4 Event tag            | No. Sets the event name that GA4 reports display, so any name works.               |

### Verify the event in GTM preview mode

Test the setup in GTM preview mode before you publish. Preview mode catches a mismatched event name before data goes missing in GA4.

1. In your GTM workspace, click **Preview**. Tag Assistant opens in a new tab.
2. Enter the URL of a page that runs your Optimizely flag decision, and click **Connect**.
3. Return to the Tag Assistant tab and click **Continue**.
4. In the event timeline, select the `optimizely-decision-fs` event.
5. Under **Tags Fired**, confirm that **Optimizely - GA4 EventUpdate** displays.

When the event is missing from the timeline, the `dataLayer.push` code did not run. Confirm that your notification listener runs when the SDK decides a flag.

When the event displays but the tag displays under **Tags Not Fired**, compare the names. The trigger **Event name** does not match the `event` value in your code.

### Submit and publish GA workspace

Submit and publish your workspace changes by going to **Workspace >  Submit > Publish** (adding any details you would like to the **Submission Configuration**).

You can then see results in GA, along with their sent values.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/VIZc1K1X3ptl3lt394PpY_a54bca7-events-in-ga.png)

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/BBRjN8o30kjoEjcieGIdo_1c5d4c6-sent-values.png)

This can be verified by viewing the [Realtime overview in the Reports tab of GA4](https://support.google.com/analytics/answer/9271392?hl=en).

## Without GTM

You can directly push events to GA4 without using GTM, but tracking the events and variables sent by Optimizely is significantly more complicated.

To send Optimizely data to GA4, you use GA4’s Send events methods. For information, refer to GA4’s complete documentation on its send events methods.

- [iOS](https://firebase.google.com/docs/analytics/ios/events)
- [Android](https://firebase.google.com/docs/analytics/android/events)
- [Web Apps](https://firebase.google.com/docs/analytics/web/events)
- [Website](https://support.google.com/analytics/answer/11147304)

### Prerequisites

- Ensure that `gtag` is defined.
- Ensure you have GA4 initialized and ready to interpret variables returned by Optimizely.

For the JavaScript example, you would use the GA4 [send events](https://support.google.com/analytics/answer/11147304) call. You would add the following sample call to your code base:

```javascript
gtag("event", "optimizely-decision-fs", {
  Flag: decisionInfo.flagKey,
  Rule: decisionInfo.ruleKey,
  Variation: decisionInfo.variationKey
});
```

Within GA4, you can name your variables whatever you would like. You can remove or include any variables. But for a flag rule, you should use the following:

- `flagKey`
- `ruleKey`
- `variationKey`

## Conclusion

The next step is to create segments in GA. Segments are a subset of your analytics data. Review the [Create segments for Google Analytics 4](docId\:cpGtISDiEJWnNGYqf8ZMP) documentation for complete instructions.
