Add the Uniform Marketplace app to Contentstack

The Uniform app in the Contentstack Marketplace enables content managers to use Uniform capabilities within the Contentstack user interface.

  • Classification - Assign enrichment tags to Contentstack entries. These tags describe data you want to track on the visitor who views the entry. For example, you might want to track that a visitor is interested in making a purchase when the visitor views a specific entry.
  • Personalization - Associate personalization conditions with Contentstack entries. For example, you might have a hero entry that should only be shown to visitors coming from a specific geographic region.
  • A/B testing - Specify content entries that make up an A/B test. For example, you might want to try a variety of different hero components on your home page in order to determine which one is most effective.

This section guides you through the process of adding the Uniform app from the Contentstack Marketplace.

Before you start

You must have the following available to complete this setup:

  • Contentstack account with administrator access.
  • Uniform account with administrator access. If you don't already have one, you can request an account at https://uniform.dev/try.

A Uniform API key is needed in order for the Marketplace app to read various settings involved with configuring personalization. You need an API key with the following permissions:

Uniform Context > Read Drafts Uniform Context > Manifest > Read

tip

For details on how to create an API key, see the instructions on how to create a Uniform API key.

The Uniform app in the Contentstack Marketplace adds a number of custom field types that allow content authors to configure personalization during the content authoring process. You must add this app to your stack.

  1. In Contentstack, navigate to the Marketplace.

  2. In the Apps section, find the Uniform app and click Install App.

    app
  3. Select your stack, accept the terms of service and click Install.

    install
  4. In the app configuration screen, scroll down to the section Now let's connect this app....

    now-lets-connect
  5. Paste your Quick Connect API key in the field.

    About this step

    This is the value you copied when you created the API key in Uniform.

  6. Click Connect.

    connected

    About this step

    If the Quick Connect API key you entered is valid, you will see a message indicating the Marketplace app was able to connect to your Uniform project.

  7. Now that you have Uniform app added to your stack, some new custom field types are available to add to your content models.

    content-type-custom-field-types

Enrichment tags can be assigned to Contentstack entries. When your front-end application has classification activated, Uniform uses these tags to classify the visitor when the entry is viewed.

Before you start

You should have at least one enrichment defined in your Uniform project. You can enable enrichment tagging without having any enrichments defined, but you won't be able to complete all the steps in this section without them.

You must specify which content types you want content authors to be able to assign enrichment tags to.

  1. In Contentstack, open your stack.

  2. Open your content type.

  3. Add a new field using the Custom type.

  4. Enter the following values:

    PropertyValue
    Display NameEnrichments
    Unique IDenrichments
    Select Extension/AppUniform Context - Enrichment Tags
  5. Save your changes.

A content author must assign enrichment tags to content entries.

  1. In Contentstack, open your stack.

  2. Navigate to an entry based on one of the content types you enabled enrichment tagging on.

  3. Scroll down to the field Enrichments.

    empty-field
  4. Click here.

    field-editing-activated
  5. Select the tag you want to assign.

    field-edited

    About this step

    The value for Strength indicates how much the visitor score increases when the content entry is viewed. The visitor score can act as the basis for personalization criteria.

  6. Click Add.

    field-set

    At this point there are several things you can do:

    • Change the strength value using the input field.
    • Add more enrichment tags by clicking Add More.
    • Publish your changes in Contentstack.
    • Manage enrichments in Uniform by clicking Manage Enrichments.

Personalization criteria can be assigned to Contentstack entries. This criteria describes the conditions when the Contentstack entry is appropriate to use. When your front-end application has classification and personalization activated, Uniform can show and hide content based on the criteria you configure.

You must specify which content types you want content authors to be able to assign personalization criteria to.

  1. In Contentstack, open your stack.

  2. Open your content type.

  3. Add a new field using the Custom type.

  4. Enter the following values:

    PropertyValue
    Display NamePersonalization Criteria
    Unique IDpersonalization_criteria
    Select Extension/AppUniform Context - Personalization Criteria
  5. Save your changes.

A content author must assign personalization criteria to content entries.

  1. In Contentstack, open your stack.

  2. Navigate to an entry based on one of the content types you enabled personalization criteria on.

  3. Scroll down to the field Personalization Criteria.

    empty-field
  4. Click Add Criteria.

    field-editing-activated
  5. Configure the criteria you want to assign.

    field-edited

    At this point there are several things you can do:

    • Change the criteria.
    • Add more criteria by clicking Add Criteria.
    • Publish your changes in Contentstack.

Personalization lists allow you to create lists of content entries where the personalization criteria assigned to the entries is used to determine which entries to display to a visitor.

A personalization list is a reference field that a content author can assign the content entries that represent the personalized content.

  1. In Contentstack, open your stack.

  2. Navigate to a content type into which a content author would want to add personalization.

    About this step

    For example, if you have a content type that represents a page, you might want to add a personalized hero to the page. In this case, you would use the page content type.

    Alternatively, you might want to create a new content type, like one that represents the personalized hero.

  3. Add a new field using the Reference type.

  4. Enter the following values:

    PropertyValue
    Display NamePersonalized List
    Unique IDpersonalized_list
    Referenced Content TypeSelect the content types that have the personalization criteria field defined on them.
  5. Click the Advanced tab.

  6. Select the option Multiple.

  7. Save your changes.

The following steps describe how to configure a personalized list.

  1. Create a new content entry using the personalized list.

  2. In the field Personalized List, add content entries.

    configured-list

    About this step

    You should select content entries with personalization criteria configured.

An A/B testing list is a reference field that a content author can assign the content entries that represent the test variations.

  1. In Contentstack, open your stack.

  2. Navigate to a content type into which a content author would want to test.

    About this step

    For example, if you have a content type that represents a page, you might want to add a test to determine which version of a hero works best. In this case, you would use the page content type.

    Alternatively, you might want to create a new content type, like one that represents a hero that can be tested.

  3. Add a new field using the Custom type.

  4. Enter the following values:

    PropertyValue
    Display NameA/B Test
    Unique IDa_b_test
    Select Extension/AppUniform Context - A/B Test
  5. Add a new field using the Reference type.

  6. Enter the following values:

    PropertyValue
    Display NameA/B Test Variations
    Unique IDa_b_test_variations
    Referenced Content TypeSelect the content types that have the personalization criteria field defined on them.
  7. Click the Advanced tab.

  8. Select the option Multiple.

  9. Save your changes.

The following steps describe how to configure an A/B testing list.

  1. Create a new content entry using the A/B testing list.

  2. In the field A/B Test, select the test.

  3. In the field A/B Test Variations, add content entries.

    configured-list

Now that you have the ability to assign classification, personlization, and testing to content, next you must update your front-end application to activate these capabilities.

Your front-end application must read the various classification and testing settings that are configured in your Uniform project. The Uniform manifest file makes this information available to your front-end application.

Uniform valueEnvironment variable
API KeyUNIFORM_API_KEY
Project IDUNIFORM_PROJECT_ID

About this step

The front-end application will use these environment variables to read the classification and testing settings from your Uniform project.

  1. Add the following npm packages to your front-end application:

    npm i -D @uniformdev/cli npm i @uniformdev/context @uniformdev/context-react cookie
  2. Add the following to the scripts section in your package.json file:

    "download:manifest": "uniform context manifest download --output ./contextManifest.json",

    About this step

    This script downloads the latest published manifest from the Uniform project identified by the environment variables you added earlier. Most customers will run this script when the front-end application starts or is built.

  3. Run the following command:

    npm run download:manifest

    About this step

    A file contextManifest.json will be created. This file contains the details of the classification and test settings you configured in your Uniform project.

  4. Add the following to your .gitignore file:

    # uniform contextManifest.json

    About this step

    This ensures the manifest file doesn't get added to your source code repository.

  5. Add the following to your _app.js or _app.tsx file:

    import "@/styles/globals.css"; import { Context, enableContextDevTools, } from "@uniformdev/context"; import manifest from "../contextManifest.json"; import { UniformContext } from "@uniformdev/context-react"; const context = new Context({ manifest, defaultConsent: true, plugins: [ enableContextDevTools(), ] }); export default function App({ Component, pageProps }) { return ( <UniformContext context={context}> <Component {...pageProps} /> </UniformContext> ); }

About this example

In order to make these instructions easier to follow, an example is used. Imagine you have a content type City that you have configured to allow content authors to assign Uniform enrichments to. A component named CityDetails is used in your front-end application to display the content from the content type City.

This content type will have a field enrichments that contains a JSON object that describes any enrichments that were assigned to the content entry. This object must be passed to the component responsible for tracking.

  1. Open the component CityDetail:

    export const CityDetail = (props) => { const { title, description } = props; return ( <div> <h2>{title}</h2> <p>{description}</p> </div> ) }

    About this step

    This is the component before any tracking support is added.

  2. Replace the code with the following:

    import { Track } from '@uniformdev/context-react'; export const CityDetail = (props) => { const { title, description, enrichments } = props; return ( <Track behavior={enrichments.name}> <div> <h2>{title}</h2> <p>{description}</p> </div> </Track> ) }

About this example

In order to make these instructions easier to follow, an example is used. Imagine you have a content type Promotion that stores the region, title, and description for a promotion. You want to allow content authors to personalize the title and description.

Previously, the content type Promotion had separate fields for title and description. You followed the instructions above so content authors can associate personalization conditions the specific title and description values. Now, the promotion is a personalization list. This list has fields for the promotion title and region, along with a reference field personalized_list that points to content entries based on a content type Promotion Details.

Each of the Promotion Details content entries has its own fields title and description, along with a field personalization_criteria that defines the personalization conditions.

A component named Promotion is used in your front-end application to display the content from the content type Promotion.

  1. Since references are involved, you must check the logic you use to retrieve content from Contentstack. In this example, you must retrieve fields from the referenced personalization variants. For more information, see the Contentstack documentation.

    About this step

    The shape of the data retrieved from Contentstack looks like the following when the correct link level is specified:

    { title: "Summer Promotion", region: "NA", personalized_list: [ { title: "Super Summer Savings", description: "Savings all summer long!", personalization_criteria: { name: { crit: [ { l: "1_2", op: "+" } ] }, } }, { title: "Amazing Summer Promotion", description: "Get your summer started right!", personalization_criteria: { name: { crit: [ { l: "1_1", op: "+" } ] } } }, ] } }
  1. Open the component Promotion:

    export const Promotion = (props) => { const { title, description } = props; return ( <div> <h2>{title}</h2> <p>{description}</p> </div> ) }

    About this step

    This is the component before any personalization support is added.

  2. Replace the code with the following:

    import { useEffect, useState } from "react"; import { Personalize } from "@uniformdev/context-react"; /** * The shape of the personalization instructions * must be changed slightly in order to be fully * compatible with the Personalize component. */ function reshapePersonalizationList(list) { const reshaped = list.map((fields) => { const { uid, personalization_criteria } = fields; const variation = {...fields}; variation.id = uid; variation.pz = personalization_criteria.name; delete variation.personalization_criteria; return variation; }); return reshaped; } /** * Represents the promotion fields that * can be personalized. */ export const PromotionDetails = (props) => { const { title, description } = props; return ( <div> <h2>{title}</h2> <p>{description}</p> </div> ); } /** * Represents the entire promotion, including * the fields that are and are not personalized. */ export const Promotion = (props) => { const { title, personalized_list } = props; const [variations, setVariations] = useState([]); useEffect(() => { const reshaped = reshapePersonalizationList(personalized_list); setVariations(reshaped); }, []); return ( <Personalize variations={variations} name={title} component={PromotionDetails} /> ) }

About this example

In order to make these instructions easier to follow, an example is used. Imagine you have a content type Press Release that stores the headline, image, date, and body for a press release. You want to allow content authors to test different combinations of headline and image.

Previously, the content type Press Release had specific fields for headline and image. You followed the instructions above so content authors can define the variations they want to test. Now, the press release is an A/B testing list. This list has fields for the press release date and body, along with a reference field a_b_test_variations that points to content entries based on a content type Press Release Variation.

Each of the Press Release Variation content entries has its own fields title and image.

A component named PressRelease is used in your front-end application to display the content from the content type Press Release.

  1. Since references are involved, you must check the logic you use to retrieve content from Contentstack. In this example, you must retrieve fields from the referenced personalization variants. For more information, see the Contentstack documentation.

    About this step

    The shape of the data retrieved from Contentstack looks like the following when the correct link level is specified:

    { title: "New Product Announcement", a_b_test: { id: "winter-product-accountment", name: "Winter Product Announcement" }, a_b_test_variations: [ { title: "Super Exciting News!", image: {} }, { title: "More News!", image: {} } ], date: "2024-10-10T00:00-08:00", body: "There is a lot of excitement around..." }
  1. Open the component PressRelease:

    export const PressRelease = (props) => { const { title, image, body, date } = props; return ( <div> <div> <h2>{title}</h2> <img src={image?.url} /> </div> <p>{date}</p> <p>{body}</p> </div> ) }

    About this step

    This is the component before any A/B testing support is added.

  2. Replace the code with the following:

    import { useEffect, useState } from "react"; import { Test } from "@uniformdev/context-react"; /** * Set the entry id as the variation id for the test. * understand how each variant affects visitor activity. */ function reshapeAbTestList(list) { const reshaped = list.map((entry) => { const { uid } = entry; const variation = { ...entry }; variation.id = uid; return variation; }); return reshaped; } /** * Represents the press release fields that * make up the test. */ export const PressReleaseVariation = (props) => { const { title, image } = props; return ( <div> <h2>{title}</h2> <img src={image?.url} /> </div> ); }; /** * Represents the entire press release, including * the fields that are and are not tested. */ export const PressRelease = (props) => { const { date, body, a_b_test, a_b_test_variations } = props; const testId = a_b_test?.id ?? "unknown-test"; const [variations, setVariations] = useState([]); useEffect(() => { const reshaped = reshapeAbTestList(a_b_test_variations) setVariations(reshaped); }, []); return ( <div> <Test variations={variations} name={testId} component={PressReleaseVariation} /> <div>{date}</div> <div>{body}</div> </div> ); };