CMS Features
Implement A/B Testing
Configure A/B Testing variants in React Bricks, resolve the active variant in middleware, and fetch the right page variant in Next.js.
React Bricks A/B Testing uses page variants.
Editors create multiple variants of the same page, assign weights to active variants, and React Bricks serves them according to those weights.
In code, your app needs to:
- resolve the active variant for each request
- keep the same visitor on the same variant
- pass the selected variant to
fetchPage - track variant impressions in your analytics provider
Docs reference: A/B Testing and Multischeduling
Configure variants in React Bricks
Open the page you want to test in React Bricks and create the variants you need.
Variants can be used for two related workflows:
- multischeduling, where each variant has its own publish and unpublish window
- A/B Testing, where more than one variant is active at the same time and each active variant has a weight
For example:
| Variant | Weight |
|---|---|
| A | 50 |
| B | 50 |
This creates an even split. To run a 70 / 30 test, set the variant weights accordingly.
Add the A/B Testing middleware
The middleware resolves the active variant for the incoming request and stores it in a cookie, so a visitor keeps seeing the same variant across requests.
In current Next.js App starters, middleware.ts can chain A/B Testing with i18n:
import { NextResponse } from 'next/server'
import {
chain,
createI18nMiddleware,
createWithAbTestingMiddleware,
} from 'react-bricks/rsc'
import { i18n } from '@/i18n-config'
import { abTestingEnabled, getConfig } from './react-bricks/getConfig'
const rbConfig = getConfig()
const withAbTestingMiddleware = createWithAbTestingMiddleware({
i18n,
config: rbConfig,
})
const withI18nMiddleware = createI18nMiddleware({ i18n, NextResponse })
const middleware = abTestingEnabled
? chain([withAbTestingMiddleware, withI18nMiddleware])
: withI18nMiddleware
export default middleware
export const config = {
// Matcher ignoring `/_next/` and `/api/`
matcher: [
'/((?!api|_next/static|_next/image|favicon.ico|admin|logo.svg|bricks-preview-images|masks|preview).*)',
],
}Use createWithAbTestingMiddleware in Next.js App Router projects where A/B Testing must work together with i18n.
See the middleware reference docs for the details:
createWithAbTestingMiddlewarefor Next.js App Router projectscreateAbTestingMiddlewarefor Next.js Pages Router and Astro projects
Fetch the selected variant
In your App Router page, read the selected variant from the cookie and pass it to fetchPage as variantName.
import { cookies } from 'next/headers'
import { fetchPage, getAbTestingCookie, types } from 'react-bricks/rsc'
import config from '@/react-bricks/config'
const getData = async (
slug: string | string[] | undefined,
locale: string
): Promise<{
page: types.Page | null
variantName?: string
testName?: string
}> => {
const cleanSlug = !slug
? '/'
: typeof slug === 'string'
? slug
: slug.join('/')
const cookieStore = await cookies()
const variantName = getAbTestingCookie({
slug: cleanSlug,
locale,
cookieStore,
})
const page = await fetchPage({
slug: cleanSlug,
language: locale,
variantName,
config,
fetchOptions: { next: { revalidate: 3 } },
}).catch(() => null)
return {
page,
variantName,
testName: `${cleanSlug}_${locale}`,
}
}getAbTestingCookie reads the variant selected by the middleware. Passing that value to fetchPage keeps the rendered content aligned with the visitor's assigned variant.
Docs reference:
getAbTestingCookie
Track the experiment
React Bricks decides which variant should be rendered, but your analytics provider measures impressions.
The Next.js App Router starter defines a small GAExperimentTracker component for this.
This is not a React Bricks exported component. It is a project component that sends an experiment_impression event to Analytics with the exp_variant_string parameter, composed from the experiment name and variant name.
'use client'
import { sendGTMEvent } from '@next/third-parties/google'
import { useEffect } from 'react'
interface GAExperimentTrackerProps {
testName: string
variantName: string
}
export default function GAExperimentTracker({
testName,
variantName,
}: GAExperimentTrackerProps) {
useEffect(() => {
sendGTMEvent({
event: 'experiment_impression',
exp_variant_string: `${testName}.${variantName}`,
})
}, [testName, variantName])
return null
}Then render the tracker when both identifiers are available:
{
testName && variantName && (
<GAExperimentTracker testName={testName} variantName={variantName} />
)
}With this setup, Analytics receives an experiment_impression event for the rendered variant.
The feature/ab-testing branch of the React Bricks starters repository includes a complete implementation example, including middleware setup and analytics integration:
reactbricks-starters feature/ab-testing
There is also a concrete Next.js App example that sends the test name and variant name to Google Analytics: Next.js App analytics example
Check the result
After wiring A/B Testing:
- create two active variants for a page
- set variant weights in React Bricks
- visit the page in a private browser session
- confirm the middleware stores a stable variant cookie
- refresh and confirm the same variant is served
- verify the selected
variantNameis passed tofetchPage - check that Analytics receives an
experiment_impressionevent with the correctexp_variant_string