AB Testing in Elixir, Phoenix
Here's how you can split traffic into multiple variants, while keeping that user on the same page on revisits. Nothing fancy. How to get stats to analytics isn't covered.
Direct all routes to a single function
Optional. I like my static page traffic handled by a single function.
lib/platform_web/router.ex
for path <- PlatformWeb.HomeController.available_paths() do
get "/#{path}", HomeController, :static_page
end
Divide the traffic
I'll show you the whole file and comment in between.lib/platform_web/controllers/home_controller.ex
defmodule PlatformWeb.HomeController do
use PlatformWeb, :controller
I don't want a catch-all routing disaster so I've defined available routes manually. We could map the actual templates here, but then the AB testing templates are available too. Manual is safe.
def available_paths do
["/", "/contact", "projects", "pricing", "about"]
end
The "handle any route" function just takes the requested page, asks the ab_test()
function to adjust the actual file rendered and then renders it.
def static_page(conn, _params) do
path = Enum.at(conn.path_info, 0, "index")
{conn, page} = ab_test(conn, path)
render(conn, page, %{})
end
The ab_test()
function mainly deals with session memory. If this user has already seen a page, then show the same one again. Lets not get our visitors confused. If this page has not yet been seen, choose a random_variation()
.
defp ab_test(conn, requested_path) do
memory = get_session(conn, :ab_test_memory) || %{}
page = Map.get(memory, requested_path) || random_variation(requested_path)
new_memory = Map.put(memory, requested_path, page)
conn = put_session(conn, :ab_test_memory, new_memory)
{conn, page}
end
Choosing a random template was easy after figuring out the View actually holds all of the filenames.
defp random_variation(page) do
PlatformWeb.HomeView.__templates__()
|> elem(2)
|> Enum.filter(&String.starts_with?(&1, page))
|> Enum.random()
end
end
And voila. Pretty basic, once you have the template list at hand. If you've also implemented AB Testing, but in some way cooler manner - let me know.