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:
A/B testing on a Data model follows the same process as testing a Page or Section model. Follow these steps to set up an A/B test for a Data model:
- Create a Data model entry.
- Add variants within the entry. Create as many variants as needed to test different content versions.
- Wrap the data model content in a
<BuilderContent/>
component. This component selects the correct variant and persists the data across a user's session. It also supports server-side rendering (SSR). To enable SSR, pass the content to the content prop, just as you would with a<BuilderComponent/>
.
The example below demonstrates an A/B test on a buy-button-cta
Data model. The correct variant is selected and rendered as the call-to-action (CTA) text:
import { BuilderContent } from '@builder.io/react'
export function MyComponent() {
return (
<BuilderContent model="buy-button-cta" content={buttonCTAContent}>
{(variant, loading, fullContent) =>
<Spinner />
) : (
<button>{variant.ctaText}</button>
)
}
</BuilderContent>
);
}
How this example works
variant
: the selected data variant after the A/B test logic determines the correct variation.loading
: a boolean that indicates whether the content is still being fetched.fullContent
: represents the complete raw data from the server, including all variations.
When the content is still loading, a spinner displays. Once the correct variant is selected, its ctaText
value displays inside a <button>
.
This way the correct A/B test variation is delivered and persists across a user's session.
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"
},
]
}
Each content entry in Builder has a unique content ID, which can be one of the following:
- A standalone unique ID, for example,
bbbc29f3d2dc43b7ad820c7709749e42_654c3085cc514cab8d028a5ab581c768
. - A combination of your Public API Key and a unique ID, formatted as
{API_KEY}_{UNIQUE_ID}
.
To track A/B test variations, Builder uses a cookie named builder.tests.{builderId}
. This cookie stores one of two values:
- The Builder ID, which indicates that the default content is being served.
- The variation key, which represents the selected A/B test variant.
For example, given the following Data model entry:
"variations": {
"1111aaddca3843029a7c5fafaed58ba4": {
"testRatio": 0.5,
"data": {
"title": "Stay cool this summer"
}
}
}
The selected variation would be 1111aaddca3843029a7c5fafaed58ba4
, meaning the cookie builder.tests.{builderId}
would store this value.
This cookie-based tracking method applies to all A/B tests in Builder, not just those for Data models.
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 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>
</>
);
This data
object is now ready 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.