Skip to content

Instantly share code, notes, and snippets.

@uhhuhyeah
Created October 1, 2013 21:35
Show Gist options
  • Save uhhuhyeah/6785496 to your computer and use it in GitHub Desktop.
Save uhhuhyeah/6785496 to your computer and use it in GitHub Desktop.
How to implement Optimizely on a single page app

Optimizely's script is included in the document's head so they're able to make DOM/Styling changes before the browser has really had the time to render anything. The point of this is to prevent the "flash" of changing the content in front of the user.

This paradigm breaks down with "single page apps". The paradigm that "single page apps" use is one where the initial page load contains just enough HTML and JavaScript to bootstrap the app. The app then downloads/renders the remaining HTML. The problem is that all this happens after Optimizely has tired to make changes and because these elements Optimizely is trying to change are not present on the page yet, it cannot successfully run the code to make the variation.

Here's the workaround we've been using. Create your variation as per norm with the WYSIWYG editor Optimizely provides. Click on 'Edit Code' in the bottom right to reveal the JavaScript Optimizely will run on the page. This is usually jQuery-esque show/hide/replace etc. Write a function that checks for the presence of the right DOM element and if it's not present, have the function call itself after a short delay (setting up a loop).

Here's an example:

window.hideMobileHeaderForOptimizely = function() {
  var menuPresent = function() {
    return $('#mc-phone-header').length > 0;
  }

  var hideMenu = function() {
  	// Optimizely's Code
    $('#mc-phone-header').hide();
    $('#mc-phone-header-old').show();
  }

  if (menuPresent()) {
      hideMenu();
  } else {
    // wait and try again in a moment
    setTimeout(function() {
      window.hideMobileHeaderForOptimizely();
    }, 50);
  }
};

window.hideMobileHeaderForOptimizely();

Another gotcha is that you may need to retrigger the experiment's code as the user navigates around the site and views are perhaps replaced/re-rendered without pageViews. Here's an example where we hide elements on the Style Gallery Outfit Detail view. We're binding to the router 'pageView' event to call our experiment code, then checking the path we're on/if the DOM elements are present and firing Optimizely's experiment code.

Here's the code:

_e.on('router:pageView', function() {
  window.pinitCircleTestCode();
});
 
window.pinitCircleTestCode = function() {
  var widgetsPresent = function() {
    return $('.outfit-detail:visible .widgets').length > 0;
  }

  var hideButtons = function() {
    // Optimizely's Code
    $(".widgets .facebook").css({"display":"none", "visibility":""});
    $(".widgets .twitter").css({"display":"none", "visibility":""});
  }

  // if current path is not outfitDetail, return;
  if ( Backbone.history.fragment.match(/outfits\/\d+/) ) {
    if (widgetsPresent()) {
      hideButtons();
    } else {
      // wait and try again in a moment
      setTimeout(function() {
        window.pinitCircleTestCode();
      }, 50);
    }
  } 

};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment