In Google Analytics for iOS, there are two types of campaign measurement. There’s install campaign measurement, which lets you track the channels which brought your visitors to the App Store, where they proceeded to download your app. There’s also launch campaign tracking, which lets you attribute app launches to specific campaigns.

In this tip post, we’ll tackle the latter. We’ll leverage a feature of the Google Analytics iOS SDK to build the parameters, and then push them to dataLayer so that they can be used in the Tag.

We’ll be using Swift as the language of choice. Check out my previous two posts on GTM for iOS if you need more information on how to make GTM work in your iOS / Swift app.

Tip 39: Launch campaign tracking in Google Tag Manager for iOS

To make it all work, you need two things.

  1. Code which parses the parameters from the URL and pushes them to dataLayer.

  2. Data Layer Variables to send the campaign parameters through your Tag.

1. Modifying the app code

To parse the URL, we’ll leverage the setCampaignParametersFromUrl method in the GAIDictionaryBuilder class of the Google Analytics SDK. We won’t use it for anything else except for parsing the URL. So, in your AppDelegate.swift file, locate the overloaded constructor with the handleOpenURL method, or create it yourself:

func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool {

This is where the app parses any URL parameters used in the launch.

So, now we need to leverage the GA SDK’s built-in methods, and we need to push the parameters to dataLayer. The setup might look something like this:

func application(application: UIApplication, handleOpenURL url: NSURL) -> Bool {
  let urlString = url.absoluteString
  let hitParams = GAIDictionaryBuilder.init()
  let dataLayer = TAGManager.instance().dataLayer
    "campaignMedium" : hitParams.get(kGAICampaignMedium) ?? "",
    "campaignName" : hitParams.get(kGAICampaignName) ?? "",
    "campaignSource" : hitParams.get(kGAICampaignSource) ?? ""
  return true

Let’s just quickly walk through this. urlString is the variable where we’ll store the URL string itself (d’oh). hitParams is what we’ll use to parse the URL, and dataLayer is where we’ll push the information.

The setCampaignParametersFromUrl() method takes a URL string, and parses it for the regular UTM campaign parameters. It stores them in a bunch of constants the GA SDK leverages to pass information between the app and Google Analytics.

So, if your app is launched with something like:


The values for source (newsletter), medium (email), and campaign (December_2015) would be stored in the constants kGAICampaignSource, kGAICampaignMedium, kGAICampaignName, respectively.

The dataLayer.push() pulls these from hitParams and stores them in the data structure. If a parameter is missing from the URL, then a blank string is stored for that particular parameter.

Now we have the values in dataLayer. Next, we need our container to pick them up and send them with our Tag(s).

2. Modifying the container

To make it all work, you now need to create three Data Layer Variables (one for each parameter), and add them to your Tag.

DLV - campaignSource
Variable name: campaignSource

DLV - campaignMedium
Variable name: campaignMedium

DLV - campaignName
Variable name: campaignName

Next, edit your Screen View Tag (or whichever Tag fires first on your app). Go to More Settings -> Fields to Set, and add the following three fields:

Field Name: &cs
Value: {{DLV - campaignSource}}

Field Name: &cm
Value: {{DLV - campaignMedium}}

Field Name: &cn
Value: {{DLV - campaignName}}

Finally, publish the container, download the binary, update your app, and go crazy with launch campaign tracking.


There’s one thing you need to pay heed to. We’re pushing the campaign parameters to dataLayer but we’re not sending an ‘event’ key. The reason for this is that we want the app to send its regular Screen View, using these values only if they’re in the dataLayer when the Screen View is dispatched.

You probably see how this can be a problem. If your app sends a Screen View as soon as the initial view appears, it’s possible this dataLayer.push() happens after the Screen View hit is built, leading to a nasty race condition. The best way to ensure it works is to defer the initial hit to Google Analytics until the handleOpenURL method has completed.

The whole thing is slightly more complex than when using just the GA SDK, as many things seem to be with the Google Tag Manager SDK, but it’s still consistent with leveraging dataLayer for message passing, rather than communicating directly with the endpoint.