> For the complete documentation index, see [llms.txt](https://blings.gitbook.io/blings-knowledge-base/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blings.gitbook.io/blings-knowledge-base/documentation/getting-started/advanced-topics/a-b-test.md).

# A/B test

### A/B testing in Blings MP5 (variants via SDK + UTM for analytics)

This page explains a simple, reliable way to run an A/B (or A/B/C…) test in Blings MP5 by:

1. Picking a variant from URL if provided, otherwise select randomly
2. Passing it into the MP5 data fields (so Studio/Flow can react to it)
3. Persisting it into UTM parameters for analytics/BI.
4. Store it in localStorage so refresh will show the same version

***

#### Full demo code

Copy the code below to Blings Platform ⇒ Integration ⇒ "advanced" code&#x20;

```javascript

// Test #1 (you can add multiple)
runStickyABTest(params, {
  testName: "abtest1", // <<=== Update with your variable name. 
  // Make sure to create the variable in the data-schema inside Blings Studio or Platform->settings page
  variants: ["10off", "free-trial", "summer-promotion"], // <<=== Replace with the A/B options
  utmSlot: "utm_source", // <<=== pick an available UTM slot, or leave it empty
});


// COPY ONCE
/**
   ===========================
   Blings Sticky A/B Tests
   ===========================
 * Runs one sticky A/B test.
 * - If params.data[testName] already exists (and valid), it will be saved (stickied).
 * - Else it will reuse localStorage if available.
 * - Else it randomly picks one, saves it, and writes it into params.data[testName].
 * - Always mirrors result into params.utmParams[utmSlot] for BI.
 */
function runStickyABTest(params, { testName, variants, utmSlot }) {
  params = params || {};
  params.data = params.data || {};
  params.utmParams = params.utmParams || {};

  const key = `blings_${testName}`;
  const pick = () => variants[Math.floor(Math.random() * variants.length)];

  const value =
    (variants.includes(params.data[testName]) && params.data[testName]) ||
    (variants.includes(localStorage.getItem(key)) && localStorage.getItem(key)) ||
    pick();

  params.data[testName] = value;
  localStorage.setItem(key, value);
  if (utmSlot) params.utmParams[utmSlot] = value;

  return value;
}
```

<details>

<summary>Details</summary>

The following details cover the demo code by breaking it to smaller pieces and deep diving into the functionality.

#### 1) Add a variant field to your MP5 data schema

In your Blings project, add a data field like `abtest1`&#x20;

This is important: the variant must exist in your video data fields so you can reference it in:

* Flow Map / scene selection (branching by variant), and
* Studio content selection (conditional text/media blocks).

#### 2) Demo code: pick a variant&#x20;

Use the snippet below in your page before calling BlingsPlayer.create(...).

```javascript
// make sure to put the variable in the video data fields (in studio or in platform settings) 

function pickVariant(variants) {
  const index = Math.floor(Math.random() * variants.length);
  return variants[index];
}

// Either take from url parameters
if (!params.data.abtest1) {
  // if not in url, pick randomally
  params.data.abtest1 = pickVariant(["a", "b", "c"]); 
  // write the different options of the test, e.g "short" and "long
}
```

How it works

* If you pass `?abtest1=b` (or map it into `params.data.abtest1`), the page will respect it.
* If nothing is provided, it will randomly assign "a", "b", or "c".

This lets you support:

* deterministic assignment from marketing links / campaigns, and
* automatic “demo mode” randomization.

#### 3) Save the selected variant on UTM for analytics/BI

To make the selected version visible in analytics, copy the chosen variant into UTM parameters.

Example (simple and effective):

```js
// pick available slot, e.g
params.utmParams = {
  utm_source: params.data.abtest1,
};
```

Now, in your BI / dashboards, you can break down performance by the test variant using `utm_source` (or any UTM field you choose, like `utm_campaign`, `utm_content`, etc.).

### 4) Stickiness

Without stickiness, a user might see different versions on every refresh, which:

* breaks consistent user experience,
* makes debugging harder,
* and can pollute analytics.<br>

With localStorage stickiness:

* the first assigned variant is saved on the device/browser,
* refreshes keep showing the same version,
* and if a variant is provided later via params.data\[testName], it will overwrite and become the new sticky value.<br>

```javascript
const variants = ["a", "b", "c"];

// try existing value first, then localStorage
params.data.abtest1 =
  params.data.abtest1 ||
  localStorage.getItem("abtest1");

// validate; if missing or invalid, pick new
if (!params.data.abtest1 || !variants.includes(params.data.abtest1)) {
  params.data.abtest1 = pickVariant(variants);
}

// always persist
localStorage.setItem("abtest1", params.data.abtest1);
```

Important limitations

* localStorage is device + browser specific. A user switching devices/browsers may get a different variant.
* Clearing browser storage resets the assignment.
* If you need “same variant across devices,” store the chosen variant in your backend user profile and inject it into params.data\[testName] on load.

</details>

#### Where to use the variant inside Blings<br>

Once `params.data.abtest1` is set, you can use it in two common ways:<br>

**A) Scene selection (Flow Map)**

Route users into different scenes/paths based on the variant (a / b / c).

![](https://2160648125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsAHOIWkjYudyFAaqnpQm%2Fuploads%2FxSMQN6SjQsa5RN3F5ckp%2Fimage.png?alt=media\&token=659f52d4-aecc-430f-ba85-e170b842e016)<br>

**B) Content selection (Studio)**

Show different copy, visuals, or offers. E.g add "text connector" and set it's data replacment based on `abtest1`

<div align="left"><figure><img src="https://2160648125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsAHOIWkjYudyFAaqnpQm%2Fuploads%2FHKFjtdm1PzkXR7mOXgH0%2Fimage.png?alt=media&amp;token=59d83adc-460f-4266-94d4-fe142cd7d76e" alt="" width="353"><figcaption></figcaption></figure></div>

#### Verification

Make sure to verify the A/B test works. Since it's "sticky" by default, meaning refresh will open the same test variant over and over, you can open a new "incognito" window every time, and see that the correct content is presented.&#x20;

Another way will be to run the following command on the console: `localStorage.clear()`&#x20;
