Integrations

You can send VWO's campaign information to third-party analytics platforms by using notification listeners. You can then segment the analytics report by using VWO's campaign id, campaign name, variation id, or name.

Next, you will find suggested implementations for some common analytics platforms. Feel free to use these as showcased or adapt these to meet your specific needs.

Broadcast Receiver also allows for flexibility to implement an integration with a platform that is not listed here.

Broadcast Receiver

The code can listen to a local Broadcast by using LocalBroadcastManager on the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED.

Broadcast Data

  • On Receiving the broadcast intent, you can get the campaign data from Bundle attached with Intent.
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;

import com.vwo.mobile.VWO;

public class MainActivity extends AppCompatActivity {
    
  private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      // Get the campaign data for which the user became part of.
      Bundle extras = intent.getExtras();
      String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
      String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
      String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
      String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

      // TODO: Write your analytics code here.
    }
  };

  @Override
  protected void onStart() {
    super.onStart();
    // Create an intent filter for broadcast receiver.
    IntentFilter intentFilter = new IntentFilter(VWO.Constants.NOTIFY_USER_TRACKING_STARTED);

    // Register your broadcast receiver
    LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
  }

  @Override
  protected void onStop() {
    super.onStop();
    // Unregister your broadcast receiver.
    LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
  }
}
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.support.v4.content.LocalBroadcastManager
import android.support.v7.app.AppCompatActivity

import com.vwo.mobile.VWO

class MainActivity : AppCompatActivity() {
  private val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
      // Get the campaign data for which the user became part of.
      val extras = intent.extras
        val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
        val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
        val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
        val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

        // TODO: Write your analytics code here.
    }
  }

  override fun onStart() {
    super.onStart()
      // Create an intent filter for broadcast receiver.
      val intentFilter = IntentFilter(VWO.Constants.NOTIFY_USER_TRACKING_STARTED)

      // Register your broadcast receiver
      LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter)
  }

  override fun onStop() {
    super.onStop()
      // Unregister your broadcast receiver.
      LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver)
  }
}

πŸ“˜

Note

Broadcast receivers will only be triggered for the first time a user becomes part of the test and is assigned a variation.

It contains the following keys:

  • VWO.Constants.ARG_CAMPAIGN_ID: The identifier of the campaign; this is generated by VWO. This is unique for your account.
  • VWO.Constants.ARG_CAMPAIGN_NAME: The name of the campaign, as set by you. This is not necessarily unique.
  • VWO.Constants.ARG_VARIATION_ID: The identifier of the variation in the campaign of which the user became the part. A Variation Id is unique for its campaign, but it is not unique across different campaigns.
  • VWO.Constants.ARG_VARIATION_NAME: The name of the variation in the campaign, as set by you. This is not necessarily unique.

Amplitude

Please refer to the Amplitude android guide if you are getting started with Amplitude.

In the following suggested approach for Amplitude, we use Events.

We add a Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED. When the callback is requested, we send an event to Amplitude when a user becomes a part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

Events in Amplitude take an event name and event properties in the form of a dictionary.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

private BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the campaign data for which there user has become the part.
    Bundle extras = intent.getExtras();
    String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
    String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
    String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
    String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

    // Create event properties json object
    JSONObject jsonObjectProperties = new JSONObject();
    try {
      jsonObjectProperties.put("campaignId", campaignId);
      jsonObjectProperties.put("campaignName", campaignName);
      jsonObjectProperties.put("variationId", variationId);
      jsonObjectProperties.put("variationName", variationName);
    } catch (JSONException exception) {
      Log.e(LOG_TAG, "Unable to create json object", exception);
    }

    // send event to Amplitude
    Amplitude.getInstance().logEvent("campaign_started", jsonObjectProperties);

  }
};
private val receiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Get the campaign data for which there user has become the part.
    val extras = intent.extras
      val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
      val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
      val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
      val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

      // Create event properties json object
      val jsonObjectProperties = JSONObject()
      try {
        jsonObjectProperties.put("campaignId", campaignId)
          jsonObjectProperties.put("campaignName", campaignName)
          jsonObjectProperties.put("variationId", variationId)
          jsonObjectProperties.put("variationName", variationName)
      } catch (exception: JSONException) {
        Log.e(LOG_TAG, "Unable to create json object", exception)
      }

    // send event to Amplitude
    Amplitude.getInstance().logEvent("campaign_started", jsonObjectProperties)

  }
}

Flurry

Please refer to the Flurry android guide if you are getting started with Flurry.

In the following suggested approach for Flurry, we use Custom Events.

We add a Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED. When the callback is requested, we send an event to Flurry when a user becomes part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

Events in Flurry have a two-level structure. The highest level is the specific action, in this case, VWO. The second level in the Event structure is the Event parameter.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

Per Flurry, you must initiate the session with one of the startSession method variants, prior to logging any events. Any events logged prior to session initialization are not recorded.

private BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the campaign data for which there user has become the part.
    Bundle extras = intent.getExtras();
    String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
    String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
    String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
    String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

    // Create event properties map
    Map<String, String> mapProperties = new HashMap<>();
    mapProperties.put("campaignId", campaignId);
    mapProperties.put("campaignName", campaignName);
    mapProperties.put("variationId", variationId);
    mapProperties.put("variationName", variationName);

    // send event to Flurry
    FlurryAgent.logEvent("campaign_started", mapProperties);

  }
};
private val receiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Get the campaign data for which there user has become the part.
    val extras = intent.extras
      val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
      val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
      val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
      val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

      // Create event properties map
      val mapProperties: HashMap<String, String> = HashMap()
        mapProperties["campaignId"] = campaignId
        mapProperties["campaignName"] = campaignName
        mapProperties["variationId"] = variationId
        mapProperties["variationName"] = variationName

        // send event to Flurry
        FlurryAgent.logEvent("campaign_started", mapProperties)

  }
}

Google Analytics

Please refer to the Google Analytics Android guide if you are getting started with Google Analytics.

In the following suggested approach for Google Analytics, we use Events.

We add a Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED. When the callback is requested, we send an event to Google Analytics when a user becomes part of a campaign. In the event, we send the campaign name and id, along with the variation name and id.

The next step is to build segments for each variation of your campaign. In the segment-builder user interface, look under Advanced and add a new Condition. Select to filter Users by Event Action and Event Label, type a name for the segment, and then click Save.

Finally, build a report of metrics you are interested in.

public class MainActivity extends AppCompatActivity {
  private BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      // Get the campaign data for which there user has become the part.
      Bundle extras = intent.getExtras();
      String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
      String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
      String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
      String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

      // Create data keys
      String category = String.format("%s,%s", campaignName, campaignId);
      String action = String.format("%s,%s", campaignName, campaignId);
      String label = String.format("%s,%s", variationName, variationId);

      // send event to Google analytics
      Tracker tracker = ((VWOApplication) getApplication()).getDefaultTracker();
              tracker.send(new HitBuilders.EventBuilder()
                      .setCategory(category)
                      .setAction(action)
                      .setLabel(label).build());

    }
  };
}
public class VWOApplication extends Application {
  private static GoogleAnalytics sAnalytics;
  private static Tracker sTracker;

  @Override
  public void onCreate() {
    super.onCreate();
    sAnalytics = GoogleAnalytics.getInstance(this);
  }

  /**
     * Gets the default {@link Tracker} for this {@link Application}.
     * @return tracker
     */
  synchronized public Tracker getDefaultTracker() {
    // To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
    if (sTracker == null) {
      sTracker = sAnalytics.newTracker(R.xml.global_tracker);
    }

    return sTracker;
  }
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="ga_trackingId" translatable="false">${YOUR_TRACKING_ID}</string>
</resources>
class MainActivity : AppCompatActivity() {
  private val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
      // Get the campaign data for which there user has become the part.
      val extras = intent.extras
        val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
        val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
        val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
        val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

        // Create data keys
        val category = String.format("%s,%s", campaignName, campaignId)
        val action = String.format("%s,%s", campaignName, campaignId)
        val label = String.format("%s,%s", variationName, variationId)

        // send event to Google analytics
        val tracker = (application as VWOApplication).getDefaultTracker()
        tracker.send(HitBuilders.EventBuilder()
                     .setCategory(category)
                     .setAction(action)
                     .setLabel(label).build())

    }
  }
}
class VWOApplication : Application() {
  /**
     * Gets the default [Tracker] for this [Application].
     * @return tracker
     */
  // To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
  val defaultTracker: Tracker
    @Synchronized get() {
    if (sTracker == null) {
      sTracker = sAnalytics!!.newTracker(R.xml.global_tracker)
    }

    return sTracker
  }

  override fun onCreate() {
    super.onCreate()
      sAnalytics = GoogleAnalytics.getInstance(this)
  }

  companion object {
    private var sAnalytics: GoogleAnalytics? = null
      private var sTracker: Tracker? = null
  }
}

Google Custom Dimensions

Google also offers Custom Dimensions, which enables association of metadata with hits, users, and sessions in Google Analytics.

As part of the above approach, we only send an event to Google Analytics. You may choose to set custom dimensions. To do this, refer to the Custom Dimensions and Metrics section in Google Analytics and then set custom dimensions in the notification callback.

The next step is to make changes in Google Analytics. Look for the Admin option in the menu bar, and then select the appropriate account and a property. Under Property, select Custom Definitions > New Custom Dimensions. Type a unique name for the dimension, select User for the scope, and then click Create.

You can now see the reports according to the custom dimension.

Localytics

Please refer to the Localytics android guide if you are getting started with Localytics.

In the following suggested approach for Localytics, we use the Custom event with attributes.

We add a Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED. When the callback is requested, we send an event to Localytics when a user becomes a part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

Localytics also offers a way to set user attributes. You can set the user attributes for VWO's campaign data as well.

The custom event in Localytics has an event name and attributes.
If the campaign name is TestSignup and campaign id is 21, we can set the event name as VWO Campaign - TestSignup - 21. We also send event parameters as campaign_name, campaign_id, variation_name, and variation_id.

private BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the campaign data for which there user has become the part.
    Bundle extras = intent.getExtras();
    String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
    String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
    String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
    String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

    // Create event properties map
    Map<String, String> mapProperties = new HashMap<>();
    mapProperties.put("campaignId", campaignId);
    mapProperties.put("campaignName", campaignName);
    mapProperties.put("variationId", variationId);
    mapProperties.put("variationName", variationName);

    // send event to Localytics
    Localytics.tagEvent("campaign_started", mapProperties);

  }
};
private val receiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Get the campaign data for which there user has become the part.
    val extras = intent.extras
    val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
    val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
    val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
    val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

    // Create event properties map
    val mapProperties: HashMap<String, String> = HashMap()
    mapProperties["campaignId"] = campaignId
    mapProperties["campaignName"] = campaignName
    mapProperties["variationId"] = variationId
    mapProperties["variationName"] = variationName

    // send event to Localytics
    Localytics.tagEvent("campaign_started", mapProperties)

  }
}

Mixpanel

Please refer to the Mixpanel android guide if you are getting started with Mixpanel.

In the following suggested approach for Mixpanel, we use Events. Mixpanel also offers a way to set super properties and user profiles.

We add Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED. When the callback is requested, we send an event to Mixpanel when a user becomes a part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

If you wish to use super properties or people properties, pleaseΒ feel free to modify the following code and send appropriate values to Mixpanel.

The next step is to look for VWO events in your Mixpanel account. You can look at the funnels with the VWO event or look at the segment data.

private BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the campaign data for which there user has become the part.
    Bundle extras = intent.getExtras();
    String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
    String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
    String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
    String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

    // Create event properties json object
    JSONObject jsonObjectProperties = new JSONObject();
    try {
      jsonObjectProperties.put("campaignId", campaignId);
      jsonObjectProperties.put("campaignName", campaignName);
      jsonObjectProperties.put("variationId", variationId);
      jsonObjectProperties.put("variationName", variationName);
    } catch (JSONException exception) {
      Log.e(LOG_TAG, "Unable to create json object", exception);
    }

    // send event to Mixpanel
    MixpanelAPI mixpanel = MixpanelAPI.getInstance(MainActivity.this, "<YOUR_MIXPANEL_TOKEN>");
    mixpanel.track("campaign_started", jsonObjectProperties);
  }
};
private val receiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Get the campaign data for which there user has become the part.
    val extras = intent.extras
    val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
    val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
    val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
    val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

    // Create event properties json object
    val jsonObjectProperties = JSONObject()
    try {
      jsonObjectProperties.put("campaignId", campaignId)
      jsonObjectProperties.put("campaignName", campaignName)
      jsonObjectProperties.put("variationId", variationId)
      jsonObjectProperties.put("variationName", variationName)
    } catch (exception: JSONException) {
      Log.e(LOG_TAG, "Unable to create json object", exception)
    }

    // send event to Mixpanel
    val mixpanel = MixpanelAPI.getInstance([email protected], "<YOUR_MIXPANEL_TOKEN>")
    mixpanel.track("campaign_started", jsonObjectProperties)
  }
}

Segment

Please refer to the Segment guide if you are getting started with Segment.

Segment has a spec for A/B testing events.

We add a Broadcast Receiver to listen to the Local broadcast with the key VWO.Constants.NOTIFY_USER_TRACKING_STARTED and when the callback is requested, we send an event to Segment when a user becomes part of a campaign. In the event, we are sending the campaign name and id, along with the variation name and id.

If the campaign name is TestSignup and campaign id is 21, we can set the event name as Experiment Viewed. We also send event parameters as experimentId, experimentName, variationId, and variationName.

private BroadcastReceiver receiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get the campaign data for which there user has become the part.
    Bundle extras = intent.getExtras();
    String campaignId = extras.getString(VWO.Constants.ARG_CAMPAIGN_ID);
    String campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME);
    String variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID);
    String variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME);

    // Create event properties object
    Properties segmentProperties = new Properties();
    segmentProperties.put("experimentId", campaignId);
    segmentProperties.put("experimentName", campaignName);
    segmentProperties.put("variationId", variationId);
    segmentProperties.put("variationName", variationName);

    // send event to Segment
    Analytics.with(context).track("Experiment Viewed", segmentProperties);

  }
};
private val receiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context, intent: Intent) {
    // Get the campaign data for which there user has become the part.
    val extras = intent.extras
    val campaignId = extras!!.getString(VWO.Constants.ARG_CAMPAIGN_ID)
    val campaignName = extras.getString(VWO.Constants.ARG_CAMPAIGN_NAME)
    val variationId = extras.getString(VWO.Constants.ARG_VARIATION_ID)
    val variationName = extras.getString(VWO.Constants.ARG_VARIATION_NAME)

    // Create event properties object
    val segmentProperties = Properties()
    segmentProperties.put("experimentId", campaignId)
    segmentProperties.put("experimentName", campaignName)
    segmentProperties.put("variationId", variationId)
    segmentProperties.put("variationName", variationName)

    // send event to Segment
    Analytics.with(context).track("Experiment Viewed", segmentProperties)

  }
}