Add A/B testing to your Next.js website

Prepr CMS enables editors to create A/B tests directly within their content. This means testing different content versions is simple and effective. This chapter of the Next.js complete guide demonstrates how to set up A/B testing in Prepr, including testing the display of variants and measuring the results.

At the end of this section, you'll see the A and B versions on the home page.

Home page A/B test

The steps below make use of the A/B test in the Homepage content item from the Acme Lease demo data.

A/B test in Homepage content item

This chapter continues from the previous section, Set up data collection. If you haven't yet enabled Prepr tracking in your Next.js project, follow the steps in this section first. Otherwise, let's get started.

Set up A/B testing for the home page

You can run an A/B test on parts of a web page to show two different versions of the content to different visitors and compare which variant is more engaging. To show the right variant to the right visitor:

  • Every visitor is given an ID that resolves to an A or a B variant.
  • In your front end, you need to send this ID along with the query to retrieve the right variant.
  • This is done by setting the value for the API request header, Prepr-Customer-Id, when you make the API request to retrieve the content.

By installing the Prepr Next.js package in the previous section, you've already prepared your API request headers.

Set the API request headers

Since the API request headers are already prepared, you can simply set the API request headers for your page. To set the API request headers, update your page.tsx with the highlighted code below:

./src/app/[[...slug]]/page.tsx
import HeaderSection from "@/components/HeaderSection";
import ImageAndTextSection from "@/components/ImageAndTextSection";
import {getClient} from "@/ApolloClient";
import {GetPageBySlugDocument, GetPageBySlugQuery} from "@/gql/graphql";
import {notFound} from "next/navigation";
import { getPreprHeaders } from '@preprio/prepr-nextjs'
 
async function getData(slug: string) {
    const {data} = await getClient().query<GetPageBySlugQuery>({
        query: GetPageBySlugDocument,
        variables: {
            slug: slug,
        },
        context: {
            // Call the getPreprHeaders function to get the appropriate headers
            headers: await getPreprHeaders()
        },
        fetchPolicy: 'no-cache',
    })
 
    if (!data) {
        return notFound()
    }
 
    return data
}
 
export default async function Page({params}: { params: { slug: string | string[] } }) {
    let {slug} = params
 
    if (!slug) {
        slug = '/'
    }
 
    if (slug instanceof Array) {
        slug = slug.join('/')
    }
 
    const data = await getData(slug)
    const elements = data.Page?.stack.map((element, index) => {
        if (element.__typename === 'SectionImageAndText') {
            return <ImageAndTextSection key={index} data={element}/>
        } else if (element.__typename === 'SectionHeader') {
            return <HeaderSection key={index} data={element}/>
        }
    })
 
    return (
        <div>
            <meta property='prepr:id' content={data.Page?._id}/>
            {elements}
        </div>
    );
}

Test your A/B test

The A/B test is now running in your website. Let's check the traffic distribution for the A/B test.

In your Prepr environment, go to the Homepage content item and click the icon in your A/B test group and choose the Manage settings option. You'll notice the traffic distribution is set to 50%. This means that about 50% of customers that visit the home page will see variant A and about 50% will see variant B.

A/B test traffic distribution

To test that the A/B test in the home page is showing variant A and variant B to different customers, you can pretend to be different customers visiting the home page in your browser. Follow the steps below to do this simple test.

  1. Open the home page in the browser and refresh the page. Take note of the first image and text section. The text should read either Business lease (Variant A) or Great Value Business leases (Variant B).

  2. Right click the page to Inspect the page, click the Application tab. Under the cookies, click your localhost. You'll notice the __prepr_uid cookie in the list.

  3. Right-click the localhost entry to clear the cookies and refresh the page again. If you still see the same variant, repeat the process. You might see the same variant a couple of times in a row.

clear cookies

When you see the other variant, you know that the A/B test is running successfully.

There is an easier way to test your A/B test. We'll explore it in the last chapter of the Next.js complete guide when you install the Adaptive preview bar.

Add HTML attributes to track impressions and conversion events

Your A/B test is running successfully, however there are no metrics being recorded yet. You can see this with the Awaiting data message at the top of the A/B test in the Homepage content item.

A/B test in Homepage content item

To get Prepr to start showing some metrics data, you need to add HTML attributes to elements in your A/B test. When you add these attributes, the tracking code you added in the previous section automatically tracks impressions and your chosen conversion events.

  1. To start collecting impressions and clicks, add the HTML attributes data-prepr-variant-key and data-prepr-variant-event to the Image and text section as shown in the highlighted code below. The impression is recorded when the Section image and text element scrolls into view. The click is recorded when the CTA button element is clicked.
./src/components/ImageAndTextSection.tsx
import Link from "next/link";
import Button from "@/components/Button";
import {FragmentType, getFragmentData} from "@/gql";
import {CTA_BUTTON_FRAGMENT, SECTION_IMAGE_AND_TEXT_FRAGMENT} from "@/queries/GetPageBySlug";
 
interface ImageAndTextSectionProps {
    data: FragmentType<typeof SECTION_IMAGE_AND_TEXT_FRAGMENT>
}
 
export default function ImageAndTextSection(props: ImageAndTextSectionProps) {
    const image = (
        <div
            className='order-first flex max-h-[542px] w-full flex-grow basis-6/12 items-center justify-center bg-blue-50 p-16 md:order-none md:p-12 lg:p-16'>
            <svg
                viewBox='0 0 402 260'
                className='w-full max-w-[400px]'
                fill='none'
                xmlns='http://www.w3.org/2000/svg'>
                <path
                    d='M398.251 260H7.15201C4.49222 260 3.14794 256.795 5.01181 254.898L90.6954 167.668C94.5446 163.749 100.834 163.669 104.782 167.487L150.523 211.731C154.934 215.998 162.113 215.321 165.649 210.304L259.838 76.6611C263.834 70.9911 272.249 71.0127 276.216 76.703L400.712 255.284C402.099 257.273 400.676 260 398.251 260Z'
                    fill='#DBEAFE'
                />
                <circle cx='50' cy='50' r='50' fill='#DBEAFE'/>
            </svg>
        </div>
    )
 
    // Get the _context for the image and text. It contains the variant key value for this element which you need below.
    const {_context, align, title, cta_button} = getFragmentData(SECTION_IMAGE_AND_TEXT_FRAGMENT, props.data)
    const cta = getFragmentData(CTA_BUTTON_FRAGMENT, cta_button)
 
    const href = cta?.internal_link && cta.internal_link[0]
        ? `/${cta?.internal_link[0]._slug}`
        : cta?.link
 
    return (
        {/* Set the HTML attribute with the matching data-prepr-variant-key to collect impressions on the image and text section */}
        <div
            className='mx-auto max-w-7xl w-full bg-white' data-prepr-variant-key={_context?.variant_key}>
            <div className='flex w-full flex-wrap'>
                {align === 'left' && image}
                <div className='w-full space-y-8 px-12 py-10 md:basis-6/12 lg:px-28 lg:py-24'>
                    <h2 className='text-4xl font-medium lg:text-5xl text-neutral-900'>
                        {title}
                    </h2>
                    <div className='space-y-2.5'>
                        <div className='h-4 w-full max-w-96 rounded-sm bg-gray-100'></div>
                        <div className='h-4 w-full max-w-72 rounded-sm bg-gray-100'></div>
                        <div className='h-4 w-full max-w-80 rounded-sm bg-gray-100'></div>
                        <div className='h-4 w-full max-w-64 rounded-sm bg-gray-100'></div>
                    </div>
                    {href && <div>
                        {/* Set the HTML attribute to collect click events on the CTA link */}
                        <Link href='#' data-prepr-variant-event><Button buttonType='primary'>{cta?.text}</Button></Link>
                    </div>}
                </div>
                {align === 'right' && image}
            </div>
        </div>
    )
}

If you want to track a conversion other than a click event, e.g. a quote request, then set your data-prepr-variant-event to the custom event. For example: data-prepr-variant-event="QuoteRequest". Check out the A/B testing doc for more details (opens in a new tab).

  1. To start recording metrics, go to the home page in your website, scroll to the first Image and text section (business lease) and click the Learn more button.

  2. Now when you view the A/B test in your Homepage content item, you can click the Metrics link and see the number of impressions and clicks like in the image below.

A/B test metrics

Congratulations! You have a running A/B test with metrics in your Next.js website. Now, you can Add personalization to your website.

Was this article helpful?

We’d love to learn from your feedback