As an approach to potentially avoid performance-intensive clientside A/B tests, we've developed some proofs of concept that use CloudFlare's Service Workers to transform HTML conditionally before sending it to the user.
Two configurable worker files are aimed to address transformations that are simple or more complex.
The first worker file is for simple transformations, such as swapping instances of a word with another, or swapping an image's source url.
Here's an example of this worker in play on the live VV homepage:
The worker divides users into two groups, and the second group will receive a transformed HTML response, in this case, with a swapped hero image source. Group A and Group B will both have a cookie set noting their test group, so the test can be measured through typical analytics tools after the page is delivered. Future visits to the same page will retain the same group and content experience unless the user clears their cookie.
To configure the worker, there are variables to adjust at the top of the file: a test name, text to be potentially replaced, and a url substring that the test should apply to.
// test name. Used to set a cookie to a value of 'a' or 'b' const name = 'AB-heroswap'; // text group a will get (this text exists in the source HTML already) const aText = '/dw5a731c93/images/Homepage/BTS_Zone_1_86.jpg'; // text group b should get instead of aText const bText = '/dw434aac97/images/hdr_Fall1_G_lrg.jpg'; // page that this test should apply to const url = "https://www.vineyardvines.com";
Here's another example. This configuration will replace the href and color a the Sale button in the primary navigation:
// test name. Used to set a cookie to a value of 'a' or 'b' const name = 'AB-redsalebutton'; // text group a will get (this text exists in the source HTML already) const aText = '<a class=\'navbar_itemlink collapsible-header cat_Sale\' href="https://www.vineyardvines.com/whale-of-a-sale/">'; // text group b should get instead of aText const bText = '<a class="navbar_itemlink collapsible-header cat_Sale bg-red text-white" href="https://www.vineyardvines.com/whale-of-a-sale/">'; // page that this test should apply to const url = "https://www.vineyardvines.com";
The second worker file is for larger A/B transformations, such as delivering one multiline HTML chunk or another. This approach is easier to configure, but it requires that you are able to edit the source code of the HTML page that you're targeting so that HTML comments can be placed around the "A" and "B" content in the source, which the worker will find and conditionally enable.
Here's an example of this worker in play on a version of the homepage that is on our preview server:
This worker will show a different hero module to group a and group b.
Like the first worker, this one divides users into two groups, and cookies are set and respected in the same manner. Unlike the first worker, this one expects that both the A and B versions of the markup will be in the source HTML, surrounded by comments denoting their test name and group (a or b). For example, the HTML could contain the following A and B markup test, where the test name is "mytest":
<!--cfworkertest:mytest=a--> <div> <p>Test markup for <i>Group A</i> goes here!</p> </div> <!--/cfworkertest:mytest=a--> <!--cfworkertest:mytest=b--> <div> <p>Test markup for <i>Group B</i> goes here!</p> </div> <!--/cfworkertest:mytest=b-->
Using this pre-configurate markup, the worker finds each occurrance of these blocks in the HTML and removes the blocks that are irrelevant to the user's group before delivering the page. The same worker can be applied to any HTML page and requires no JS configuration. Note: Be sure to prefix each occurrence of the test name with "cfworkertest:", as shown above, so the script can find it.