This is a preview of the Storyblok Website with Draft Content

From content strategy to code, JoyConf brings the Storyblok community together - Register Now!

Run A/B Tests with Storyblok and VWO

Storyblok is the first headless CMS that works for developers & marketers alike.

A/B tests allow marketing teams to evaluate which content variations and user journeys deliver the best user experience and drive conversions.

Storyblok's latest collaboration with VWO's platform lets editors run these tests right from the CMS, combining VWO campaigns with Storyblok’s Visual Editor.

This tutorial demonstrates how to take advantage of this integration to create A/B tests in Storyblok. We will walk you through the setup process, explain how to create banner variations, and render them in a Vue project.

hint:

The code in this tutorial is a subset of a complete demo that runs A/B tests using Storyblok's Vue SDK and VWO's Node.js SDK. Check the repository on GitHub for more information.

Prerequisites

  • An active VWO account
  • A Storyblok space with the VWO App installed.
  • A Vue project configured to work with Storyblok's SDK.
learn:

To integrate Vue with Storyblok, follow our developers' guide. Alternatively, adapt the code to the frontend framework of your choice.

Create blocks for tests

Let's start by defining the block structure in Storyblok.

Open the Block library, click on + New Block, and create a nestable block named experimentation-vwo. Add a variations field to store the alternatives you'd like to test, and save it.

Create another nestable block for the actual tested content. Name this block banner and add the following fields:

  • title Text field
  • An image Asset field
  • A vwo_variation Plugin field. Set its Custom Type to sb-vwo

Now, open the VWO dashboard. Create a new A/B test named "Banner", and add as many variations as you'd like to test.

Add variations to a story

Back in your Storyblok space, open the home story and add the experimentation-vwo block created in the previous step.

warn:

The first time you use the plugin, you must authenticate and provide your VWO account ID and API token.

Add multiple variants of the banner block to the variations field. Change the title or the image—depending on what you're testing—and assign each to the VWO Banner feature flag and variation defined in the previous step.

Adapt your frontend code for experiments

Now that your space is ready, add the VWO integration to your code.

First, install VWO's Node.js SDK:

npm install vwo-fme-node-sdk

Next, add the account ID and API token to the .env file as environment variables named VITE_VWO_ACCOUNT_ID and VITE_VWO_SDK_KEY.

Finally, initialize VMO's client:

src/main.js
import { createApp } from 'vue';
import { StoryblokVue, apiPlugin } from '@storyblok/vue';
import App from './App.vue';
import { init } from 'vwo-fme-node-sdk';
import Page from './components/Page.vue';

const app = createApp(App);

app.use(StoryblokVue, {
 accessToken: import.meta.env.VITE_STORYBLOK_DELIVERY_API_TOKEN,
 apiOptions: {
   region: 'eu',
 },
 use: [apiPlugin],
});

const vwoClient = init({
	accountId: import.meta.env.VITE_VWO_ACCOUNT_ID,
	sdkKey: import.meta.env.VITE_VWO_SDK_KEY,
});

app.provide('vwoClient', vwoClient);

app.component('Page', Page);

app.mount('#app');

Use Vue's provide method to ensure the client is available across your project.

Add the components

In the src/components directory, create two files: a Banner.vue file, which you can copy and adapt from our demo repository, and the ExperimentationVwo.vue file to handle the variations.

The following is an abbreviated version of the code found in the demo repository:

src/components/ExperimentationVwo.vue
<script setup>
import { computed, inject } from 'vue';
import { getUserId } from '../utils/userContext.js';

const props = defineProps({ blok: Object });
const vwoClient = await inject('vwoClient');

const flag = await vwoClient.getFlag(
	props.blok.variations[0]?.vwo_variation?.featureKey,
	{ id: getUserId() },
);

const selectedUuid = flag.isEnabled()
	? flag.getVariable('contentUUID', null)
	: null;

const selectedVariations = computed(() => {
	const variation =
		props.blok.variations.find((v) => v._uid === selectedUuid) ||
		props.blok.variations.find((v) => v.vwo_variation?.isDefault);

	return variation ? [variation] : [];
});
</script>

<template>
	<StoryblokComponent
		v-for="variant in selectedVariations"
		:key="variant._uid"
		:blok="variant"
	/>
</template>

We extract the featureKey from the first variation, call the vwoClient.getFlag method to get the flag object, and then obtain the selectedVariations so the StoryblokComponent helper renders only the ones coming from VWO.

warn:

VWO requires a unique user ID. How you generate this string depends on your business logic.

Finally, add both of the components to your application:

src/main.js
import { createApp } from 'vue';
import { StoryblokVue, apiPlugin } from '@storyblok/vue';
import App from './App.vue';
import { init } from 'vwo-fme-node-sdk';
import Banner from './components/Banner.vue';
import ExperimentationVwo from './components/ExperimentationVwo.vue';

const app = createApp(App);

app.use(StoryblokVue, {
 accessToken: import.meta.env.VITE_STORYBLOK_DELIVERY_API_TOKEN,
 apiOptions: {
   region: 'eu', // Choose the correct region from your Space.
 },
 use: [apiPlugin],
});

const vwoClient = init({
	accountId: import.meta.env.VITE_VWO_ACCOUNT_ID,
	sdkKey: import.meta.env.VITE_VWO_SDK_KEY,
});

app.provide('vwoClient', vwoClient);

app.component('Banner', Banner);
app.component('ExperimentationVwo', ExperimentationVwo);

app.mount('#app');

Check out our demo repository to see the complete implementation.

Wrap up

Now that you know how to create an A/B test using the VWO App, you can help marketers extend this integration to CTAs, headlines, images, and any other element on the site.

Consult with your content team to understand their priorities, prepare matching block templates, and enable them to create personalized experiences that drive conversions.

Author

Jeremias Menichelli

Jeremias Menichelli

Over a decade building seamless web experiences. Web accessibility advocate. Technical lead behind award-winning sites. Design systems tinkerer. Community and event ambassador.