How we implemented Google Optimize with Ember.JS

Ken Tran
Smartkarma Tech
Published in
6 min readAug 15, 2018
Image credit: Optimizely

The product and engineering team at Smartkarma constantly pushes out new updates in response to our customers and markets. Sometimes this means big changes to the product that have cascading effect across the product funnels, so it’s critical for us to ensure that we don’t inadvertently hurt our numbers. The investment into a split testing tool is a no-brainer.

We use Ember.JS for our web frontend, with Google Analytics/Tag Manager for analytics, so Google Optimize was a natural choice. But Optimize and other tools that we’ve looked at don’t work straight out of the box with single-page applications. Public resources are scant. Google doesn’t have a direct line we can get guidance from, leaving most of the support to a self-help Optimize forum. StackOverflow is full of “Optimize not working with <insert JS framework>”…

Louis and Amir, our frontend developers, managed to figure this out! We’re sharing our approach so other devs with a similar issue can have a reference.

The original post:

If you searched online, most guides or tutorials are on how to implement Google Optimize (Optimize) on server-rendered web apps. Even Google documentation focuses on this type of implementation. This leaves a gap of unknowns on how to integrate it into single-page apps. Google doesn’t provide details on how exactly Optimize works code wise so this leaves a lot of room for assumptions.

The journey of trying to get Optimize to work is basically us testing and trying out different things to confirm or eliminate our assumptions. Google Optimize is a black box. A magical one at that. The best way to understand how it works is by poking it from the outside and see what happens. That is what I and my colleague have been doing and we encourage you guys to do the same. Play around with Optimize on a test web app and test your assumptions there.

For this article, we are going to assume you are somewhat familiar with Google Tag Manager (GTM) and Google Analytics (GA). Our web app is built using Ember.js framework and we use an Ember specific library to implement GTM in the code, so our examples are going to be influenced by our stack. But, it should be straightforward to transfer the code to any other single-page app (SPA) frameworks out there like React or Angular.

Also, we will leave out details that are similar to server-rendered implementation steps. Like we mentioned before, there are already a lot of resources covering server-rendered, so it will be redundant to mention them here. Our focus here is on implementation details for SPA that is different from server-rendered.

Let’s get started.

There are several ways to implement Optimize, but since our web app has been using GTM to integrate GA, our implementation choice for Optimize is naturally going to be via GTM as well. Our experience using GTM has been amazing as it simplifies integrating various analytic tools to the web app. Google also recommends using GTM to integrate Optimize.

In a nutshell these are the steps that we are going to do:

  • Load Optimize using GTM
  • Connect Optimize to GA
  • Create the experiment
  • Set the page evaluation method to custom event
  • Fire the custom event
  • Run the experiment and test the web page

Load Optimize using GTM

To use Optimize, we will need load Optimize whenever the web app is loaded. If you follow Optimize installation steps on Google Optimize dashboard, you will be asked to add a code snippet into your HTML page. We will not be doing that since we will be loading Optimize via GTM. Go to GTM dashboard and add a new Google Optimize tag. Set the firing trigger to be a page view and you should be done. Now GTM will load Optimize when we first open the web app page. This will only happen during the initial page load which is the behavior we wanted for our SPA.

Google Optimize tag on GTM with a Page View trigger.

Connect Optimize to GA

We will also need to connect Optimize to GA. The installation steps on Optimize will require you to do this. For the details on how to connect GA, you can read this document.

Link GA to Optimize.

Create the experiment

Creating an experiment for an SPA should be the same as with for server-rendered web pages except for one thing. Under targeting, we need to set Optimize to evaluate on a custom event rather than page load. The default custom event name is optimize.activate, but it can be set to anything. It is basically the event name that we will need to fire from the web app to run the experiments.

We also have written a quite thorough step by step guide on how to create an experiment on Optimize. You can read it here.

Custom event activation.

Set the page evaluation method to custom event

The main difference between the normal server-rendered and SPA implementation is on when Optimize activates the experiment. For server-rendered, Optimize will run the experiment on page load and this is reflected in the targeting tab in Optimize dashboard. This makes sense since server-rendered web app will load a new page as the user navigates and interacts with the web app. This is not true for an SPA since the page is only loaded once. This is we need to use a custom event that we will need to trigger from the code. Whenever we fire the custom event from the code, Optimize will first check if all the rules. If all of the rules are satisfied, Optimize will apply the changes to the page.

Fire the custom event

The tricky part is, we will need to fire the custom event again if our SPA framework rerenders the components or some section of the page that is affected by the experiment. Since it’s hard to know what section is affected, it’s much easier to always fire the custom event every time the framework renders something on the page.

On our Ember app, we override the standard didRender component lifecycle hook to include the code to fire the custom activation event via the data layer. Below is the code snippet of our implementation on Ember. I have bolded the important part of the code. The rest of the code is there to give more reference, especially for Ember developers.

function optimize(context) {
const metrics = get(context, 'metrics');
if (metrics) {
resetGtmDataLayer();
metrics.trackEvent('GoogleTagManager', {
event: 'optimize.activate',
});
}
}
export function initialize(application) {
application.inject('component', 'metrics', 'service:metrics');
Component.reopen({
didRender() {
run.throttle(Component, optimize, this, 100);
return this._super(...arguments);
},
});
}

The first bolded code section is the custom event activation code. We use the ember-metrics library to integrate GTM on our Ember app and the code snippet is also influenced by that. The second bolded line of code is there to throttle the number of events being fired. We set it to fire at most 1 event every 100ms.

Run the experiment and test the web page

With the custom event firing, the experiment should run correctly and we should see the changes on the page. The last thing to do is to test if Optimize records the user session. To do this we need to go to Optimize dashboard and if everything works correctly, we should see some active users on the dashboard. The session data might be a little bit slow to update. Also, make sure that you publish your GTM changes. Do not use the preview mode since from my experience, user sessions are not recorded in preview mode so it might lead you into thinking there is something wrong with the implementation.

We did skip a lot of details that we think are obvious to make this article short. If you have any problems feel free to ask us in the comments below and we will try our best to answer your questions. We will also update the article based on the comments to fill up important details that we missed.

--

--