Note: This page is no longer maintained, and the underlying code may be outdated or unsupported. It may be removed in a future release. To learn how to implement experimentation and personalization workflows, refer to the Personalize documentation.
Uniform is an optimization platform that helps businesses tailor personalized experiences for their users. It uses signals to enhance personalization based on the user's intent.
A user visiting your wesite has a reason or an intent to accomplish something, and the goal of personalization is to simplify this task for your user.
A signal in Uniform helps you identify the user's intention. For example, you can capture real-time user behavior such as pages viewed by the user, the number and type of pages visited by the user, etc.
Additional resources: Learn more about intent and signals in Uniform or refer to Uniform’s architecture to understand how it works.
In this guide, we will walk you through the steps involved in personalizing experiences for your website visitors using Uniform and Contentstack. This guide will help you get set up for the following three use cases.
Let's discuss how we can set up this personalization in Uniform and Contentstack.
Start with creating an account in Uniform. To do this, perform the following steps:
You can also sign up using your Gmail or GitHub account.
With these steps, the account setup process is complete. You can now create intent and signals in Uniform.
An ‘intent’, in Uniform, refers to the reason a visitor comes to your site. Defining an intent would mean specifying the type of audience along with the goal that they intend to achieve. For example, marketers who want to read cases, or partners interested in a quick product overview. And a ‘signal’ is something that will help you determine the intent of the visitors.
Once you set up your Uniform account, you need to set up your first project in Uniform. In this example, we will be creating two intents in our project:
Let's follow the steps given below and add intents and signals for our project.








The intents we have added aren’t ready to use yet. We will have to publish them so we can use them for our purpose.


Note: Please note that every time you make changes to the current intents and signals, you will have to publish your changes to see them in action.
With these steps, we have created and configured intents and signals in Uniform. Let's now look at the steps to perform in Contentstack.
We will now set up the essentials in Contentstack. Log in to your Contentstack account and then follow the steps given below:
csdx cm:import -a <management_token_alias> -d <path_of_folder_where_content_is_stored>
You can see that we have added a Title field, a Custom field (Uniform Opt Intent Tag), an RTE field (Description), a Single Line Textbox field (Rolling Text), a Link field (CTA), and a File field (Banner Image).
You don't have to select any intent inside Uniform Opt Intent Tag in the Marketing Booster entry, as shown below. So this entry will become the default entry.
In the other two entries, Want To Know More and Attention Attendee, the custom field that we added (Uniform Opt Intent Tag), fetches the data from our intents (Annual Event Registration and Know More) that we created in the Uniform app earlier. You can add the intent relevant for this entry and also change a few settings from here if you want to:
We have added the Title, URL, Group (SEO), and Reference (Hero Banner) fields in this content type. The Hero Banner reference field refers to the entries from the Hero banner content type:
We have added an entry for the Home content type:
You can see that Hero Banner is referencing entries from the Hero banner content type.
Note: Do not enter any value for the REACT_APP_REGION parameter in the .env file if you are using the NA region. If you are using the Europe region, enter eu as the value for this parameter. Similarly, to use the Azure North America region, enter the value as azure-na, and for Azure Europe region, enter the value as azure-eu.
npm install
npm start
Note: During deployment, to use the Europe region, add an environment variable named REACT_APP_REGION and set its value to eu. Similarly, for Azure NA region, set the value to azure-na, and for Azure EU region, set the value to azure-eu.
With these steps, the entire setup is ready. Let's learn more about how it works.
Now that we have everything ready and the app is also running, let's understand how it works in the background for the following three use cases.
The first use case is when a regular user visits your website, he/she sees the default entry page (i.e., Marketing Booster). This type of user is not assigned any personalization, and therefore they see the default text as shown below:

Note: We have not selected any intent for this default variation. Therefore, the regular users will see this page whenever they visit the website.
In the second use case, let's assume that there's an event being organized by a company, so it sends out marketing emails. As per our setup, anyone who registers for an event, after receiving the email, will be automatically shown the annual event page as shown below

If users click Event Calendar, they are directed to the event list page. Note the query in the URL in the above image. It's the same Query String signal that we added in the Uniform app.

This behavior is managed and controlled by Uniform and the users registered for the event see this page when they visit the website.
In this use case, if a user finds your product's page via organic search or through any other direct link, and then navigates to the Home page, you may want to show more details about your product.

Now that we have seen how this integration works, you can create your own code and see how the setup works.
npm install @uniformdev/optimize-tracker-browser
npm install -g @uniformdev/cli
"generate:intents": "uniform optimize manifest download --output ./src/lib/intentManifest.json --apiKey $UNIFORM_API_KEY"Note: You have to generate the manifest file every time you make changes to the intent or signals and publish them in the Uniform app.
import { createDefaultTracker } from '@uniformdev/optimize-tracker-browser';
import intentManifest from './intentManifest.json';
const localTracker = createDefaultTracker({
intentManifest,
});
export default localTracker;npm install @uniformdev/optimize-tracker-react
import React from 'react';
import ReactDOM from 'react-dom';
import { UniformTracker } from '@uniformdev/optimize-tracker-react';
import localTracker from './local-tracker';
function MyApp() {
return <UniformTracker trackerInstance={localTracker}>Optimize all the things!</UniformTracker>;
}
ReactDOM.render(<MyApp />, document.getElementById('my-container-element'));// TypeScript
interface PersonalizableListItem {
// `intentTag` tells which intents this variation is relevant to,
// which is used when evaluating whether or not a variation meets personalization criteria.
// Variations with no intent tag are considered 'default' and are shown to anyone.
intentTag?: IntentTags | null;
}// replace `fetchPostsFromCMS` with something that fetches data from your CMS
const allPosts = await fetchPostsFromCMS(); const mappedPosts = allPosts.map((post) => {
return {
...post,
// Assumes your CMS is capable of attaching Uniform Intent tags
// to content items via `unfrmOptIntentTag` property.
intentTag: post.unfrmOptIntentTag,
};
});<Personalize variations={mappedPosts} />import { IntentTagStrength } from '@uniformdev/optimize-common';
import { Personalize } from '@uniformdev/optimize-tracker-react';
function RenderVariation({ title }) {
return <p>Variation rendered: {title}</p>;
}
export default function OneComponentPersonalization() {
// manually define some personalization variations. Normally these would come
// from a content API (headless CMS, commerce, etc)
const variations = [
{ title: 'Default variation', intentTag: undefined },
{
title: 'Variation for intent1 intent',
intentTag: { intents: { intent1: { str: IntentTagStrength.Normal } } },
},
{
title: 'Variation for intent2 intent',
intentTag: { intents: { intent2: { str: IntentTagStrength.Normal } } },
},
];
return <Personalize variations={variations} component={RenderVariation}/>;
}import { IntentTagStrength } from '@uniformdev/optimize-common';
import { Personalize } from '@uniformdev/optimize-tracker-react';
// this mapper component selects which implementation to use based on the `type` it is rendering
// (this can be a switch statement, map lookup, react.lazy, etc as needed)
const ComponentMapper = (variation) => {
switch (variation.type) {
case 'A':
return <RenderVariationTypeA {...variation}/>;
case 'B':
return <RenderVariationTypeB {...variation}/>;
default:
return <p>Not sure how to render {variation.type}</p>;
}
};
function RenderVariationTypeA({ title }) {
return <p>Type A Variation rendered: {title}</p>;
}
function RenderVariationTypeB({ title }) {
return <p>Type B Variation rendered: {title}</p>;
}
export default function ManyComponentPersonalization() {
// manually define some personalization variations. Normally these would come
// from a content API (headless CMS, commerce, etc)
const variations = [
{ title: 'Default variation', intentTag: undefined, type: 'A' },
{
title: 'Variation for intent1 intent',
intentTag: { intents: { intent1: { str: IntentTagStrength.Normal } } },
type: 'B',
},
{
title: 'Variation for intent2 intent',
intentTag: { intents: { intent2: { str: IntentTagStrength.Normal } } },
type: 'B',
},
];
return <Personalize variations={variations} component={ComponentMapper}/>;
}Follow the steps mentioned in the Enabling Optimize on an Existing Contentstack Stack guide and integrate with Contentstack.
Once the integration is ready, you need to fetch content from Contentstack into your application. The contentstackOptimizeListReader function will help your application to read Contentstack data and convert it to a Uniform-understandable format.
npm install @uniformdev/optimize-tracker-contentstack
// <a href="https://github.com/contentstack/contentstack-javascript">https://github.com/contentstac...</a>
import contentstack from 'contentstack'; export const getPageBySlug = async (preview: boolean, slug: string) => {
const config = {
api_key: 'your_contentstack_api_key',
delivery_token: 'your_contentstack_delivery_token',
environment: 'your_contentstack_environment',
};
const contentstackClient = contentstack.Stack(config);
const query = contentstackClient
.ContentType('page')
.Query()
.includeCount()
.includeContentType()
.includeReference(['components', 'components.unfrm_opt_p13n_list'])
.toJSON();
const result = await query.where('url', slug).find(); // result is an array where -
// result[0] == entry objects
// result[result.length-1] == entry objects count included only when .includeCount() is queried.
// result[1] == schema of the content type is included when .includeContentType() is queried. const [first] = result[0];
return { ...first, _content_type_uid: 'page' };
}; import { contentstackOptimizeListReader } from '@uniformdev/optimize-tracker-contentstack';
import { Personalize } from '@uniformdev/optimize-tracker-react';
import { Hero } from './Hero'; export const PersonalizedHero: React.FC<Entry<PersonalizedHeroFields>> = ({ unfrm_opt_p13n_list }) => {
const variations = contentstackOptimizeListReader(unfrm_opt_p13n_list);
return (
<Personalize
name="Personalized Hero"
variations={variations}
trackingEventName="heroPersonalized"
loadingMode={<div>Loading component goes here</div>}
component={Hero}
/>
);
};The following articles for more information: