A/B Testing with Vanity
Vanity is an A/B Testing framework for Ruby on Rails applications. I covered A/Bingo previously which is a similar framework. We have moved to Vanity at work as our A/B testing tool for a number of reasons. We are using Redis already and Vanity does its metrics and metric tracking in Redis. One of my colleagues has a good understanding of the internals of the Vanity source code as well.
The Vanity documentation is pretty good but I thought this post could help for those getting started. Read the labnotes blog documentation and the 2-minute demo instructions first. We have used Vanity with Redis, which is the single data store it originally supported, but it has since been expanded to support ActiveRecord (RDBMS) and MongoDB. Keeping experiment and participant tracking in a separate data store like Redis was better than the database in terms of speed. We have also been able to develop some patches to disable Vanity if Redis goes down without taking the (database-backed) site down as well.
Create the experiment directory and files. A generator would be useful here. This example creates an experiment that presents multiple prices for a commerce website. In vanity each experiment requires a Ruby source file in the
experiments directory, which is at the root of the Rails app. Run the following from the Rails root:
mkdir -p experiments/metrics touch experiments/price_options.rb
Add the following configuration to the
price_options.rb file that you just created.
ab_test "Price options" do description "Which price is the best price?" alternatives 19, 29, 39 end
Now the experiment can be referenced by its name using the
ab_test method (a downcased, underscorized, and symbolized version). You can call
ab_test from views, controllers, helpers, and even model files.
Create a metric. When a website visitor of yours is participating in an experiment, they will see one of the alternatives defined by that experiment. An experiment should have some goal associated with it, such as making a purchase. Vanity will handle showing the alternatives randomly, tracking the alternative a given participant saw, and ensuring participants continue to see the same alternative on subsequent visits. We need to instrument the application code at specific places to indicate where a goal has been completed. Create a metric file in the
experiments directory you created earlier:
Add the following to your metrics file. You could have a "database-backed" model by using a model class from the Rails application where Vanity is used, but this example will be a simple metric without a database model.
metric "Purchase" do description "Tracks the performance of various prices in terms of how many purchases their participants produce" end
Site visitors need to be identified in some way for Vanity to work properly. This is a bit easier with logged-in users, because they probably have a database record that identifies their account uniquely, which could be used with Vanity. Without a database record, you can create a session to identify each user, or use their IP address, or some other way that makes sense for your application. In the project I'm working on, we have visitors that do not have accounts yet. I use the
use_vanity method from Vanity without any arguments, which creates a
vanity_id for that visitor. The
vanity_id for a user is available across multiple requests since it is available as a cookie and sent with each request.
When participants have viewed alternatives and you're ready to look at report output, you can generate results to a output file or use a dashboard. As of this writing, the report output does not work. You will need to have your data store running (Redis in our case) since it will use the datastore to pull participant data. Typically we just use the dashboard to view participation counts.
vanity report --output vanity.html
Vanity reports are available with some controller and view code provided by the gem. The documentation has you create a vanity controller, but you can also move these controller actions and view code around in your application. If you follow the instructions, the gem has actions that make assumptions about the controller being there and being named a certain way, and a route being available to route to the vanity controller. The following syntax works in Rails 3.
match '/vanity(/:action(/:id(.:format)))', :controller=>:vanity
Create the vanity controller to report results:
Inside your controller (to get the actions) make sure to
include Vanity::Rails::Dashboard. We ended up using the vanity template Erb files directly by copying them into the main application code so we could edit them and have more control over the presentation.
Viewing the vanity controller dashboard won't work if the experiment object has a nil value for
created_at. By default in development Vanity won't record participants for the experiment, so without recording turned on, the experiment doesn't set
created_at at load time, which breaks the dashboard when you try and load it. To enable tracking in the development environment, I set:
Vanity.playground.collecting = true
Now when the server starts up, it connects to Redis to set the experiment
created_at first, this is the data in redis that backs the experiment model file. You should see something in the Redis log like the following:
+1297968800.845316 "setnx" "vanity:experiments:price_options:created_at" "1297968800"
I'm planning to write more about Vanity as we have some ideas for additional tooling, and have some commits that help make it more robust that we can hopefully push up to the project. I have had a couple minor patches merged in to the main Vanity source, so I know the maintainer is open to adding new features and bug fixes.
Are you doing A/B testing? Are you using Vanity or something else? Hopefully this article helps you get started doing some A/B testing in your project.