With Builder, A/B testing works out of the box for Page and Section models, but data models require a bit more set up. In this article we will learn about A/B testing structure in Data models, rendering A/B tests, and delivering the correct variant to users.
To get the most out of this document, you should already be familiar with:
Running A/B tests on a data model within the visual editor follows the exact same flow as setting up an A/B test for a page or section model. Simply create the data model content entry, and then within the entry, create any number of variants. However, in order to access the variants within youir code, there is a bit of set up.
Simply wrap where you use your data model content in a <BuilderContent/>
component, and it will handle picking the correct variant and persisting the data across a user's session for you.<BuilderContent/>
even supports Server Side Rendering, just pass the Builder content to the content prop the same as you would in a <BuilderComponent/>
In the example below, we have a buy-button-cta data model that has text for a CTA that we want to run an A/B test on. The variant is chosen and that data is rendered as the CTA text
import { BuilderContent } from '@builder.io/react'
export function MyComponent() {
return (
<BuilderContent model="buy-button-cta" content={buttonCTAContent}>
{(variant, loading, fullContent) =>
//variant is the data property after the correct variation is chosen
//loading is the loading state, that returns true while content is being fetched
//fullContent represents the raw data from the server that contains all variations
loading ? (
<Spinner />
) : (
<button>{variant.ctaText}</button>
)
}
</BuilderContent>
);
}
The JSON below represents the data returned by a Data model entry that contains an active A/B test. A/B testing is implemented with the standard data
property for the default option and a variations
property containing key/value pairs for each data object for a given variant of the A/B test.
Additionally, the testRatio
sub-property indicates the percentage of time each variation should be shown.
{
"results": [
{
"lastUpdatedBy": "2ej3Ldf2pKYWQiEMPKzdUGcUvU53",
"folders": [],
"data": {
"date": 1699257600000,
"image": "https://cdn.builder.io/api/v1/image/assets%2F988e5176e08a4773bb301a97f9e56493%2F2c2e0b2072104385b721d941710c8a2b",
"author": {
"@type": "@builder.io/core:Reference",
"model": "author",
"id": "bbbc29f3d2dc43b7ad820c7709749e42_3e9fc0cb1016406299b45ac368641c99"
},
"createdBy": "2ej3Ldf2pKYWQiEMPKzdUGcUvU53",
"meta": {
"kind": "data",
"lastPreviewUrl": ""
},
"variations": {
"1111aaddca3843029a7c5fafaed58ba4": {
"testRatio": 0.5,
"createdDate": 1699057084439,
"data": {
"date": 1699257600000,
"image": "https://cdn.builder.io/api/v1/image/assets%2F988e5176e08a4773bb301a97f9e56493%2F70bc2dc8de36427bb19a86be64f1ba6c?format=webp",
"author": {
"@type": "@builder.io/core:Reference",
"model": "author",
"id": "bbbc29f3d2dc43b7ad820c7709749e42_3e9fc0cb1016406299b45ac368641c99"
},
"articleText": "The Pats defeated the Commanders 17-13 in a defensive battle on Sunday. Lorem Ipsum blablablablablabl bal bla b lablaa",
"genre": "sports",
"title": "Patriots Defeat Commanders In Close Game",
"blurb": "New England bounces back in week 9",
"slug": "pats-commanders"
},
"meta": {},
"name": "Variation 1",
"id": "1111aaddca3843029a7c5fafaed58ba4"
}
},
"name": "pats-commanders",
"id": "bbbc29f3d2dc43b7ad820c7709749e42_654c3085cc514cab8d028a5ab581c768",
"rev": "cp41au6hjiv"
},
]
}
The Builder.io content ID for a given content entry usually either consists of a unique ID alone, or your API Key, an underscore, and the unique ID. Builder.io uses a cookie with a name like builder.tests.{builderId}
to track A/B tests. The value of this cookie can either be the Builder id
itself (indicating the default value) or the key of the chosen variation.
In this example, the chosen variation would be 1111aaddca3843029a7c5fafaed58ba4
. This behavior is how Builder handles any A/B Test, so this cookie is not exclusive to data model A/B testing.
When rendering data from a data model within a Builder components (for example, when setting up blog templates), it's vital to wrap the <BuilderComponent>
within a <BuilderContent>
tag. If you don't, the <BuilderComponent>
won't be aware of the A/B test cookie for the given data m and will only return the default data (from the data
object in the JSON).
Consider the following example. Begin with raw data stored in the articleData
variable, obtained through a builder.get()
call. Pass this data to the content
prop within the <BuilderContent/>
component.
Inside, the Builder SDK processes the data and selects the winning variant based on the A/B test cookie (builder.tests.{builderDataId}
). This selected variant becomes the data
object containing only the winning variation, excluding the others.
return (
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
{!articleData && <meta name='robots' content='noindex' />}
</Head>
<BuilderContent model="article" content={articleData}>
{(data, loading, fullContent) => {
//data is the data property after the correct variation is chosen
//loading is the loading state, that returns true while content is being fetched
//fullContent represents the raw data from the server that contains all variations
return (
<>
<BuilderComponent model="blog-template"
content={articleTemplate}
data={{article: data}}
/>
</>
)
}}
</BuilderContent>
</>
);
You can now use this data
object for rendering with the <BuilderComponent>
. The articleTemplate
variable specifies the desired section model, indicating that you want to render that specific segment with the winning variation provided as the data
field.