Rendering Personalizations and Experiments

This guide describes the steps you need to follow to render components that have personalized or testing variants React.
An experience can be either a personalization or an experiment. The Ninetailed React SDK provides an <Experience /> component that wraps the component you use to render your content. It automatically detects the properties needed from the wrapped component. The experiences prop accepts Ninetailed Experience content that has been appropriately transformed by the ExperienceMapper available from our Utility Libraries.
The <MergeTag> component allows you to render any property of the current visitor's profile. Use this alongside the Ninetailed Merge Tag content type in your CMS to allow content editors to dynamically personalize inline content.

<Experience> Component Props

Pass in props of any name that correspond to the props your component expects to receive
The React component that your baseline or variant will use to render
An array of experience CMS entries mapped using the ExperienceMapper methods available from our Utilitly Libraries
An object containing key-value pairs of props that should be sent to the component irrespective of the selected experience variant
(Optional) A custom component to show prior to the <Experience> component selecting a variant. This defaults to a transparent version of your component using the baesline props.

Example Use

This example shows working with hardcoded JSON data and our JavaScript Utility Library for demonstrative purposes. Consult the Utility Libraries documentation to know what data to fetch from your CMS and how transform experience CMS entries to the format required by the <Experience> component.
import React from 'react';
import { Experience } from '@ninetailed/experience.js-react';
import { ExperienceMapper } from '@ninetailed/experience.js-utils'
type HeadlineProps = {
text: string;
const Headline: React.FC<HeadlineProps> = ({ text }) => {
return <h1>{text}</h1>
export const Page = () => {
// The baseline and your experiences are normally fetched from your CMS
// Consult the Utility Libraries documentation for information on how to map experiences
const baseline = {
id: ""
text: "This is the baseline text"
// Experiences must be in this format prior to being mapped by the ExperienceMapper
const experiences = [
id: ""
name: ""
type: "nt_personalization" // Will either be 'nt_personalization' or 'nt_experiment'
config: {...} // A config object with traffic allocation, distribution, and component information
audience: {
id: ""
variants: [
id: 'variant-id', // A top-level id property must be present on each variant
text: 'This is the variant text'
const mappedExperiences = experiences
.filter((experience) => ExperienceMapper.isExperienceEntry(experience))
.map((experience) => ExperienceMapper.mapExperience(experience))
return (
{...baseline} // Supply your baseline content as direct props

Inline Personalization with Merge Tags

The React SDK also provides a <MergeTag /> component. After Merge Tag entries are set up in your CMS, the <MergeTag /> component allows you to declaratively render data dynamic to each visitor's profile.
import React, { useState, useEffect } from 'react';
import { MergeTag } from '@ninetailed/experience.js-react';
const Greeting = () => {
return <h2>Hey <MergeTag id="traits_firstname" />👋, how is your day?</h2>

Contentful Rich Text

Merge tags can be allowed as embedded inline entries within Contentful rich text fields. This allows personalize microcopy on content types that you use to make a personal connection with the visitor. You will need to customize your application to render Merge Tags when working with Contentful's React Rich Text Renderer library.
import React from 'react';
import { INLINES } from '@contentful/rich-text-types';
import { documentToReactComponents} from '@contentful/rich-text-react-renderer';
import { MergeTag } from '@ninetailed/experience.js-react';
export const renderRichText = (richTextDocument) => {
return documentToReactComponents(richTextDocument, {
renderNode: {
if ( === 'nt_mergetag')) {
return <MergeTag id={} />;