decorative yellow lines on background

This is a guest post written by Albert Sunwoo, Solutions Engineer at Segment. It is part two of a two-part series from Segment on how to integrate Segment and Optimizely to optimize customer experience. In the first post, Albert talked about integrating Segment Personas with Optimizely Web.

One of the most powerful ways to build better products is to run experiments to validate different hypotheses and measure the impact on your metrics. Optimizely Full Stack is Optimizely’s product experimentation and feature flagging platform that allows you to integrate experiments and or feature flags into your code base.  These experiments and feature flags can be targeted to specific users or audiences. Combining your experiment platform with your data platform can help you run even more effective experiments. You can use Segment Personas to bring CRM and behavior data from all of your platforms into Optimizely  Below, we’ll walk through an example of how to integrate with Optimizely Full Stack with Personas.

Integrating Personas Traits and Audiences into Full Stack

In our previous blog post, we discussed experimenting using Optimizely Web to test different experiences for potential customers that visited our webpage based on their industry.  We can run a similar experiment using Optimizely Full Stack but we can also run this experiment on a mobile app or across multiple platforms at once.

For instance, if we were to use the “industry” trait again to define our audience for Full Stack, we would create a Full Stack experiment in Optimizely’s UI with the following conditions:

graphical user interface, text, application, email

And then incorporate it into our experiment in the audience section:

timeline

At this point, it is up to the developer to ensure that an “industry” attribute gets included at the time a user is bucketed and when events are tracked.

var variation = optimizelyClient.activate("my_experiment", userId, {
  industry: "b2b"
});

And:

optimizelyClient.track("my_event", userId, {
    industry: "b2b"
});

Or, if you’re using Segment to track your KPIs (which you should be):

analytics.track({
  userId:userId,
  event: 'my_event',
  context: {
    traits:{
      "industry": "b2b"
  }
});

These attributes may not always be easily available at the time of activation and or event tracking.  However, given the user id, any user trait or audience data is easily accessible using the Profile API.

By calling:

https://profiles.segment.com/v1/spaces/<workspace_id>collections/users/profiles/user_id:<user_id>/traits

You would get a response that looks like:

{
  "traits": {
    "email": "albertsemail@segment.com",
    "industry": "b2b",
    "name": "Albert Segment"
  },
  "cursor": {
    "url": "",
    "has_more": false,
    "next": "",
    "limit": 10
  }
}

The industry attribute can then easily be parsed:

attribute = result['traits']['industry'];

Therefore, it can be provided to both the Optimizely Full Stack activate and tracking calls of either Segment or Optimizely.

Group Calls and Bucketing Ids

A convenient aspect of both Segment Personas and Optimizely Full Stack is that they both offer support for account-level tracking and decision making.

For more information on these two offerings, check out the Optimizely documentation and the Segment blog to find out more.

Both platforms allow you to associate individual users to a group id.  This is often applicable for use cases where you need to associate something like an account (company) to a group of individuals (employees).  

In the context of Optimizely Full Stack, you can assign an entire account to a bucketing decision for a rollout or an experiment. In the case of Segment Personas, you can provide account-level profile information and link that to all individual profiles associated to that account.  The account level features of these two platforms are particularly useful when they’re used together.

Similarly to the previous audience attributes example, group or account-level information may not easily be accessible at the time of an experiment.  For example, you may only have the user id of the individual. In cases like this you can use the Profile API once again to retrieve the Account(s) associated with the user and the profile information associated with that Account.

Using the Albert profile once again:

graphical user interface, text, application, email

We see that Albert is associated with an account-level profile:

graphical user interface, text, application, chat or text message

graphical user interface, application

By calling: 

https://profiles.segment.com/v1/spaces/<workspace_id>/collections/users/profiles/email:albertsemail@segment.com/links

You would get a response that looks like:

{
  "data": [
    {
      "to_collection": "accounts",
      "external_ids": [
        {
          "id": "segment123",
          "type": "group_id",
          "source_id": "CJ3MHte3di",
          "collection": "accounts",
          "created_at": "2018-12-05T21:51:09.575215Z",
          "encoding": "none"
        }
      ]
    }
  ],
  "cursor": {
    "url": "",
    "has_more": false,
    "next": ""
  }
}

And, if necessary, you can then call to retrieve any traits/attributes of that Account profile.

https://profiles.segment.com/v1/spaces/<workspace_id>/collections/accounts/profiles/group_id:segment123/traits

The response to that call would look like this:

{
  "traits": {
    "domain": "SaaS",
    "name": "Segment"
  },
  "cursor": {
    "url": "",
    "has_more": false,
    "next": "",
    "limit": 10
  }
}

The information from these calls can then be used in Optimizely’s account-level Bucketing Ids feature:

const bucketingIdAttributes = {
  domain: "SaaS",
  $opt_bucketing_id: "segment123"
};

// Activate with the bucketing ID
var variationKey = optimizelyClient.activate(
  "my_experiment",
  userId,
  bucketingIdAttributes
);

Enabling Omnichannel

One of the great features of Optimizely Full Stack’s set of libraries and SDKs are their stateless deterministic nature.  This gives these SDKs the ability to ensure that when the same user ids are provided across platforms and SDKs, the same bucketing decision will be made for each user id.

However, a common user id may not always be available across these different platforms and creating a unifying id is often not a trivial task.  Fortunately, Segment’s Profile API can bridge the gap of unifying a user across platforms.

Unifying Full Stack using the Profile API

Using the Profile API, you’ll always have access to registered identifiers of a user regardless of platform.

For example, let’s say you have an idea for an Optimizely Full Stack experiment that will span both a web application server and a mobile application.  This experiment presents the user with two possible experiences labeled treatment_a and treatement_b.

Let’s say a user, Albert, enters into that experiment on the web application as albert-web:  

var variation = optimizelyClient.activate("web-mobile-experiment", userId);

The identifier for Albert that is used for the userId variable has a value of “albert-123”.  Let’s say that albert-123 has been bucketed into treatment_a.

Let’s also say that within Personas, the profile associated with Albert has the following ids associated with his identity graph:

graphical user interface, text, application, email

Now let’s say the same user accesses the mobile application and enters into the same Full Stack experiment from the mobile application. With Full Stack, if we used albert-123 as our user-id id again, it would guarantee that the user would be bucketed into treatment_a again due to Optimizely Full Stack’s deterministic architecture.  However, we may not have access to that albert-123 identifier.

Fortunately, with the profile API we can access Albert’s full profile including all of his identifiers using any of the other identifiers. For example, we could use albert-xyz to access the rest of the identifiers associated

So, in this case, we can use one of the ids to call the profile api.

Calling:

https://profiles.segment.com/v1/spaces/<workspace_id>/collections/users/profiles/mobile_id:albert-xyz/external_ids

Or:

https://profiles.segment.com/v1/spaces/<workspace_id>/collections/users/profiles/email:albertsemail@segment.com/external_ids

 

Would return:

{
  "data": [
    {
      "id": "albertsemail@segment.com",
      "type": "email",
      "source_id": "CJ3MHte3di",
      "collection": "users",
      "created_at": "2018-12-06T00:01:13.593504Z",
      "encoding": "none"
    },
    {
      "id": "albert-xyz",
      "type": "mobile_id",
      "source_id": "CJ3MHte3di",
      "collection": "users",
      "created_at": "2018-12-06T00:01:13.593511Z",
      "encoding": "none"
    },
    {
      "id": "albert-123",
      "type": "user_id",
      "source_id": "CJ3MHte3di",
      "collection": "users",
      "created_at": "2018-12-06T00:01:11.888412Z",
      "encoding": "none"
    }
  ],
  "cursor": {
    "url": "",
    "has_more": false,
    "next": ""
  }
}

 

This gives us access to the albert-123 id, which can then be used as the user id for Full Stack’s bucketing call.  This ensures that Albert gets bucketed into treatment_a again and, most importantly, that Albert has a consistent experience across platforms.

 

Get Started

Want to learn more about Segment? Get in touch with us here.