We started using Optimizely for simple AB testing on Discovery. However since Optimizely is a client side AB testing tool, we run into issues using it with our React code that is rendering the page on the server side.
Server-side tools are different, in that no modification occurs at the browser level. When the visitor lands on your page, a randomly picked version of your test is sent straight from your server. Yes, this means you have to involve your developers in testing, but it also gives you robustness and flexibility.
[Client-Side, Server-Side: What’s The Difference?](http://conversionxl.com/server-side-vs-client-side-ab-testing-tools-whats-the-difference/)
Issue with Optimizely & server-side rendering
React renders the HTML code on the server (NodeJS), sends it down to the browser where React is trying to pick it up where it left off and start modifying the page based on user actions. However after the rendered page arrives to the browser the Optimizely script modifies the DOM based on the different variations using jQuery, so when React in the browser is running into DOM inconsistencies when trying to pick up where it left off on the server.
Unfortunately it appears that there is no way we can make a use of the Optimizely Quick Edit (HTML) feature (client side AB testing) if we keep the server side rendering. Rendering the pages on the server side is crucial for (perceived) performance and UX, as well for SEO. However we don’t need to give up on AB testing for this, we just can’t use Optimizely out-of-the-box.
The drawback of any of the solutions is that to support the server side rendering we need to have the different variations in the codebase. Which means adding and removing variants will need dev effort and deploy. However we can still use online tools to manage the experiments, which can be either Optimizely, or GA, or something else.
How (technology run down)
We use Redux & React to render the pages both on server & client side based on the data we have in the *application store*. That said if the *application store* will have information about the different AB tests, the app can render the different variations easily.
The idea is that before pageload we get all the active experiments, and the decision of what variation to serve for the user **from somewhere**, save that in the *application store*, then log the clicks on the UI and push the results **to somewhere**. (**Somewhere** can be either Optimizely or GA.)
After all the variations are deployed on the server, the pageload consists of the following steps:
I. Before page load (Node.js) 1. Make an API call to get the active experiments, and the decision on the variation for the user 2. Update store with the experiment information 3. Render page on the server side from the store (which will be the variation per the experiment)
II. After page load (Browser) 1. React will be able to pick up the render where the server left it off because the DOM is consistent to the store information -> the correct variation is displayed and React is happy 2. We track different events (experiment goal) on the UI and push them via an Ajax call to where we store the results.
We can continue to use Optimizely for managing the variations, collecting and analyzing the results. Important to note that this solution will require dev efforts to put the variations in place, but once they are deployed to staging/production PO can turn the experiments off and on anytime. Also will see all the results & goals in the same way on the Optimizely UI as she would using their client side library.
Using GA Experiments
Seems like GA is getting in the AB testing game and we could use the same analytics account to create and analyize experiments. This definitely needs a bit more research from us on the GA side, but this looks promising:
* [Roll Your Own A/B Tests With Optimizely and React](http://engineering.tilt.com/roll-your-own-ab-tests-with-optimizely-and-react/) * [npm react-ab-test](https://www.npmjs.com/package/react-ab-test) * [npm redux-ab-test](https://www.npmjs.com/package/redux-ab-test) * [npm react-ab](https://www.npmjs.com/package/react-ab)