This article will help you:
  • Get set up within Google Tag Manager to integrate Optimizely X and Google Universal Analytics
  • Confirm that your integration is working properly

If you’re an existing Google Tag Manager user, you may already have pre-configured Universal Analytics tags that fire off pageview calls and do not want to use a regular custom HTML tag. You can integrate Google UA with Optimizely X with this one-time setup process.

In this article, we walk you through setting up the integration and confirming your setup.

Before you start

You will need to create a Google UA custom dimension and a custom report.

One-time Setup to Integrate via Google Tag Manager

Here's how to use GTM to integrate Optimizely X and Google UA:

  1. In Google Tag Manager, navigate to Workplace > Variables.

  2. Create a new User-Defined Variable calledoptimizely-dimension-number.

    In the Type field, choose Data Layer Variable type optimizely-dimension-number.

    Then, in the Data Layer Version field, choose Version 2. 

  3. Create a new User-Defined Variable named optimizely-dimension-value

    • In the Type field, choose Data Layer Variable.

    • In the Data Layer Variable Name field, type optimizely-dimension-value

    • In the Data Layer Version field, choose Version 2.

  4. Create a new User-Defined Variable named optimizely-referrer .

    • In the Type field, choose Data Layer Variable.

    • In the Data Layer Variable Name field, type optimizely-referrer.

    • In the Data Layer Version field, choose Version 2.

  5. Navigate to Workplace > Triggers.

  6. Create a new Custom Event named "Optimizely campaign decided."

    • In the Event name field, type “campaign-decided.”

  7. Create a new Custom Event named "Optimizely referrer override."

    • In the Event name field, type “optimizely-referrer-override.”

  8. Navigate to Workplace > Tags.

  9. Create a new Custom HTML Tag named "Optimizely Integration Code."

  10. Create a new Google Universal Analytics Tag named "Optimizely Campaign decided" to track event in UA.

    • In the Tag Type field, choose Universal Analytics.

    • Under Configure Tag, include your UA tracking ID.

    • In the Track Type field, choose Event.

    • In the Category field, choose Optimizely.

    • In the Action field, choose Assigned to Campaign.

    • Set Non-Interaction Hit to True.

    • Under Custom Dimensions:

      Set Index to {{optimizely-dimension-number}}
       
      Set Value to {{optimizely-dimension-value}}
      
    • In the Triggering field, choose the "Optimizely campaign decided" custom event.

  11. Create a new Google Universal Analytics Tag named "Optimizely Referrer override" to track event in UA.

    • In the Tag Type field, choose Universal Analytics.

    • Under Configure Tag, include your UA tracking ID.

    • In the Track Type field, choose Event.

    • Set Non-Interaction Hit to False.

    • Under Fields to Set:

      Set Field Name to referrer
       
      Set Value to {{optimizely-referrer}}
    • In the Triggering field, choose the "Optimizely referrer override" custom event.

Tag configuration

Copy this code exactly as-is into the custom HTML section described here. (The easiest way to copy the sample is to click View source on the top right-hand corner of the code box below.)

<script>
var DATALAYER_OBJECT_NAME = 'dataLayer';
var state = window['optimizely'].get && window['optimizely'].get('state');

/**
 * Some analytics platforms have the ability to fix referrer values by overriding the page referrer value.
 * this function is called when a redirect has occured on the previous page. 
 *
 * @param {string} referrer - The effective referrer value
 */
var referrerOverride = function(referrer) {
    var dataLayerObject = window[DATALAYER_OBJECT_NAME] || [];
    dataLayerObject.push({
      'event': 'optimizely-referrer-override', 
      'optimizely-referrer': referrer
    }); 
};

/**
 * Used for experiments created in 'new Optimizely'. This function is executed for all
 * experiments that are running on the page. Use the arguments to send data to your platform.
 *
 * @param {string} campaignName - The name of a campaign that is running on the page
 * @param {string} campaignId - The ID of a campaign that is running on the page
 * @param {string} audienceNames - The names of all the audience the visitor is considered part of related to this campaign
 * @param {string} audienceIds - The names of all the ids the visitor is considered part of related to this campaign
 * @param {string} variationName - The name of the experiment the user is seeing. Frequently, a name is only available for the campaign
 * @param {string} variationId - The ID if the experiment the user is seeing 
 * @param {string} variationName - The name of the variation the user is seeing
 * @param {string} variationId - The ID if the variation the user is seeing 
 * @param {boolean} inHoldback - If true, the visitor has not been exposed to this variation, but is kept in a holdback
 *   which is a sample of the visitor that isn't exposed so that Optimizely can calculate the impact of a campaign.
 */
var sendCampaignData = function(
  campaignName,
  campaignId,
  audienceNames,
  audienceIds,
  experimentName,
  experimentId,
  variationName,
  variationId,
  inHoldback
) {
  var data = window['optimizely'].get('data');
  var dimension = data.campaigns[campaignId] && data.campaigns[campaignId].integrationSettings && data.campaigns[campaignId].integrationSettings.google_universal_analytics && data.campaigns[campaignId].integrationSettings.google_universal_analytics.universal_analytics_slot;

  if (dimension) {
    var campaign = campaignName ? campaignName + '(' + campaignId + ')' : campaignId;
    var audience = audienceNames.join(',');
    var experiment = experimentName ? experimentName + '(' + experimentId + ')' : audience + '(' + experimentId + ')' ;
    var variation = variationName ? variationName + '(' + variationId + ')' : variationId;
    var holdback = inHoldback ? 'holdback' : 'treatment';

    var customVariableValue = [campaign, experiment, variation, holdback].join(':');
    var dataLayerObject = window[DATALAYER_OBJECT_NAME] || [];
    dataLayerObject.push({
      'event': 'campaign-decided', 
      'optimizely-dimension-value': customVariableValue,
      'optimizely-dimension-number': dimension
    }); 
  }
};

/**
 * This function fetches all the campaign data from the new Optimizely client
 * and calls the functions provided in the arguments with the data that needs to
 * be used for sending information. It is recommended to leave this function as is
 * and to create your own implementation of the functions referrerOverride and 
 * sendCampaignData.
 *
 * @param {Function} referrerOverride - This function is called if the effective referrer value differs from
 *   the current document.referrer value. The only argument provided is the effective referrer value. 
 * @param {Function} sendCampaignData - This function is called for every running campaign on the page. 
 *   The function is called with all the relevant ids and names. 
 */
var initNewOptimizelyIntegration = function(referrerOverride, sendCampaignData) {
  // There can only be one effective referrer on a page. This boolean makes sure the 
  // redirect overwrite only happens once. Multiple referrerOverwrites might result in undesired behavior. 
  var referrerOverwritten = false;
  var newActiveCampaign = function(id) {
    var referrer = state.getRedirectInfo() && state.getRedirectInfo().referrer;
    if (!referrerOverwritten && referrer) {
      referrerOverride(referrer);
      referrerOverwritten = true;
    }

    var activeCampaigns = state.getCampaignStates({
      isActive: true
    });
    var campaignState = activeCampaigns[id];

    var campaignName = campaignState.campaignName;
    var campaignId = id;
    var audienceNames, audienceIds;
    if (campaignState.audiences.length > 0) {
      audienceNames = campaignState.audiences.map(function(audience) {
        return audience.name
      });
      audienceIds = campaignState.audiences.map(function(audience) {
        return audience.id
      });
    } else {
      audienceNames = ['everyone_else'];
      audienceIds = [0];
    }
    var experimentName = campaignState.experiment.name;
    var experimentId = campaignState.experiment.id;
    var variationName = campaignState.variation.name;
    var variationId = campaignState.variation.id;
    sendCampaignData(
      campaignName, 
      campaignId, 
      audienceNames, 
      audienceIds,
      experimentName,
      experimentId,
      variationName, 
      variationId, 
      campaignState.isInCampaignHoldback
    );
  };

  /**
   * At any moment, a new campaign can be activated (manual or conditional activation). 
   * This function registers a listener that listens to newly activated campaigns and 
   * handles them. 
   */
  var registerFutureActiveCampaigns = function() {
    window.optimizely = window.optimizely || [];
    window.optimizely.push({
      type: 'addListener',
      filter: {
        type: 'lifecycle',
        name: 'campaignDecided'
      },
      handler: function(event) {
        var id = event.data.campaign.id;
        newActiveCampaign(id);
      }
    });
  };
  
  /**
   * If this code is running after Optimizely on the page, there might already be
   * some campaigns active. This function makes sure all those campaigns are 
   * handled. 
   */
  var registerCurrentlyActiveCampaigns = function(){
    if (state) {
      var activeCampaigns = state.getCampaignStates({
        isActive: true
      });
      for (var id in activeCampaigns) {
        newActiveCampaign(id);
      }
    }
  };
  
  registerCurrentlyActiveCampaigns();
  registerFutureActiveCampaigns();
};

/**
 * A wrapper around the logic for both the classic and new Optimizely integration. 
 * @param {Function} referrerOverride - This function is called if the effective referrer value differs from
 *   the current document.referrer value. The only argument provided is the effective referrer value. 
 * @param {Function} sendExperimentData - This function is called for every running experiment on the page. 
 *   The function is called with all the relevant ids and names. Used for classic Optimizely. 
 * @param {Function} sendCampaignData - This function is called for every running campaign on the page. 
 *   The function is called with all the relevant ids and names. Used for new Optimizely. 
 */
var initOptimizelyIntegration = function(referrerOverride, sendCampaignData) {
  initNewOptimizelyIntegration(referrerOverride, sendCampaignData);
}

initOptimizelyIntegration(referrerOverride, sendCampaignData);

</script>

Confirm your integration setup

After completing your integration, here’s how to check that it works properly:

  1. Create a new campaign to integrate with Google UA.

  2. Turn on UA integration for the campaign.

  3. Set the custom dimension where Optimizely should send data.

  4. Run the campaign.

  5. Open the Network panel in your browser.

  6. Navigate to the page where the campaign is running.

  7. Filter for “collect” to only show UA requests.

  8. Look in the Headers section of each request for the cd{X} value.

If the integration works properly, you’ll see this output in the Headers section for each request with the cd{X} value ({X} is the dimension number you set in step 3):

campaign_name:experience_name:variation_name:holdback

Each section is delimited by a colon: