Uniform conference tutorial (Next.js)

This tutorial guides you through adding personalization to the UniformConf site built using Next.js. By the end of this tutorial you will have a personalized Next.js application with content and personalization configured by content authors in Contentful using the Uniform app from the Contentful marketplace:

  • Content authors can assign enrichments to entries to identify the visitor's interests.
  • Content authors can define the conditions that must be met in order for each hero component to be displayed on the home page.
  • When the visitor's interests are identified, the home page displays personalized content.

Before you get started, be sure you have the following:

  1. Administrator access to Contentful - to import content and add the Uniform app to your Contentful space.
  2. Administrator access to Uniform - to configure the personalization settings that are available in Contentful. If you don't already have a Uniform account, you can request one at https://uniform.dev/try.
  3. Node.js (version 14 or greater) - installed on your machine to work with the Next.js app.
  4. Uniform Context browser extension - to facilitate development and testing personalization on the Next.js app. You can get the extension here. This isn't required to use Uniform Context, but it makes development and testing much easier.

In Uniform, a project is the basic unit of organization. A project is where you will define the criteria you want to use to configure personalization.

  1. Log into Uniform.

  2. On the Projects page, click (+) to create a new project.

    uniform-add-project
  3. Enter the following for the project name:

    UniformConf for Contentful
  4. Scroll down and click Empty project.

    uniform-empty-project
  5. Click Continue.

  6. Your project is created and you are taken to the project home page.

    uniform-project-home-page
  1. In Contentful, create a content management token.

    About this step

    This token is needed to load data into your Contentful space. Note this value because you will need to add it to your .env file later.

  2. In Contentful, create a content delivery access token.

    About this step

    This access token is needed to read content from your Contentful space. Note this value because you will need to add it to your .env file later.

  3. Clone the following repository:

    https://github.com/uniformdev/uniform-docs-examples
  4. Check out the following branch:

    apps/contentful/nextjs/no-uniform
  5. Add the following file:

    NEXT_PUBLIC_CONTENTFUL_SPACE_ID=<YOUR CF SPACE ID> NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN=<YOUR CF CONTENT DELIVERY ACCESS TOKEN> CONTENTFUL_MANAGEMENT_TOKEN=<YOUR CF MANAGEMENT TOKEN>
  6. Open a terminal in the root of the repository.

  7. Enter the following commands:

    npm install npm run cf:import
  8. In Contentful, confirm you have a entries in the content model, content, and media sections.

    cf-content-model-loaded
    cf-content-loaded
    cf-media-loaded

    About this step

    You might notice there are two hero content types: Enriched Hero and Personalized Hero. There is nothing special about these content types - yet. You will assign enrichment tags to the former and personalization criteria to the latter.

You must install and configure the Uniform app from the Contentful Marketplace to your space.

  1. Install the Marketplace app.

    info

    Be sure to note the Uniform API key you create. You will need this value in a later step.

Now you need to add classification and personalization settings to Contentful. This involves the following:

  • Add enrichment tagging to the content type Enriched Hero.
  • Assign enrichment tags to Enriched Hero content entries.
  • Add personalization criteria to the content type Personalized Hero.
  • Assign personalization criteria to Personalized Hero content entries.
  • Create a content type to define a list of Personalized Hero entries.
  • Configure a content entry for the list of Personalized Hero entries for the home page.

tip

If you prefer to get Contentful configured and import the finished configuration into your Contentful space, you can skip to the finished configuration section.

Uniform personalization depends on the Uniform tracker. This is a client-side component that captures visitor activity. When the visitor views a page with an enriched hero, you want the Uniform tracker to keep track of the persona associated with the hero. This enables you to understand the personas the visitor's activity matches.

  1. In Contentful, navigate to Apps > Manage apps.

  2. Open the Uniform app.

  3. In the ENRICHMENT TAGGING section, from the dropdown select Enriched Hero.

    cf-app-enrichment-tags-selected

    About this step

    This adds a new field to the content type Enriched Hero.

  4. Click Save.

  5. Open the content type Enriched Hero. Notice the field Enrichment Tags.

    cf-content-type-enriched-hero-updated
  6. Open the entry Marketer Content.

  7. Scroll down to the field Enrichment Tags.

    cf-field-no-enrichments-defined
  8. Click on the word here to open a new tab with the Uniform Enrichments page.

    uniform-no-enrichments
  9. Click (+) to create a new enrichment.

  10. Enter the following values:

    • Name: Persona
    • Public ID: 1
    uniform-add-enrichment
  11. Click Save.

    uniform-enrichment-added
  12. Click Add value.

  13. Enter the following values:

    • Name: Marketer
    • Public ID: 1
    uniform-add-enrichment-value-marketer
  14. Click Save.

    uniform-marketer-value-added
  15. In Contentful, refresh the entry page.

    field-tags-no-enrichments-selected
  16. Click on the word here.

    field-tags-enrichment-select
  17. Click Select > Enrichment: Marketer.

    field-tags-enrichment-marketer-selected
  18. Click Add.

    field-tags-enrichment-marketer-added
  19. Click Publish.

  20. In Uniform, add another value to the enrichment Persona:

    • Name: Developer
    • Public ID: 2
    uniform-developer-value-added
  21. Click Publish.

    About this step

    When settings are configured under personalization, they're not available to be used in an application until they're published.

  22. In Contentful, set the value on the field Enrichment Tags on the following Enriched Hero entries:

    TitleEnrichment Tags
    Developer ContentEnrichment: Developer
  23. Publish the entries.

Personalized Hero entries provide the personalized content that will be displayed on the home page. The specific entry that's used when a visitor views the home page depends on the visitor's activity.

  1. In Uniform, navigate to Personalization > Signals.

    uniform-no-signals
  2. Click the red (+) button.

  3. Enter the following values:

    • Name: Registered for Event
    • Public ID: registeredForEvent
    uniform-registered-signal-name
  4. Click Cookie.

    uniform-registered-signal-criteria
  5. Enter the following values:

    • Cookie Name: unfrmconf_registered
    • Comparison: equals
    • Match: true
    uniform-registered-signal-configured
  6. Click Save and close.

    uniform-registered-signal-added
  7. In Uniform, add another signal using the following settings:

    • Name: UniformConf Campaign
    • Public ID: uniformconfCampaign
    • Criteria: Query String
    • Query String Name: utm_campaign
    • Comparison: equals
    • Match: unfrmconf
    uniform-campaign-signal-added
  8. Click Publish.

    About this step

    When settings are configured under personalization, they're not available to be used in an application until they're published.

  9. In Contentful, navigate to Apps > Manage apps.

  10. Open the Uniform app.

  11. In the PERSONALIZATION CRITERIA section, from the dropdown select Personalized Hero.

    cf-app-personalization-criteria-selected

    About this step

    This adds a new field to the content type Personalized Hero.

  12. Click Save.

  13. Open the content type Personalized Hero. Notice the field Personalization Criteria.

    cf-content-type-personalized-hero-updated
  14. Open the entry Marketering Hero.

  15. Scroll down to the field Personalization Criteria.

    cf-field-no-criteria-defined
  16. Click Add Criteria.

    cf-field-criteria-selected
  17. Click Select > Enrichment: Marketer.

    cf-field-criteria-marketer-selected

    About this step

    By default, the criteria is set to match when the enrichment score is greater than 0. The enrichment score is set to 50 when a page with the Enriched Hero on it's viewed. This means the criteria will match if the page is viewed at least one time.

  18. Click Publish.

  19. Edit the following Personalized Hero entries:

    TitlePersonalization criteria
    Call for papers open now!Signal: UniformConf Campaign
    Can't wait to see you soon at UniformConf!Signal: Registered for Event
    Developer HeroEnrichment: Developer
  20. Publish the entries.

You want to select the Personalized Hero entries that can appear on the home page. This is done by creating a new entry that you can use to select and order the heroes.

  1. In Contentful, navigate to Apps > Manage apps.

  2. Open the Uniform app.

  3. In the PERSONALIZATION LISTS section, click + Create New.

    cf-app-create-new-list
  4. Enter the following value and click Confirm:

    Personalized Hero List
    cf-app-create-list-added
  5. Click Save.

  6. Navigate to Content model. Notice a new content type Personalized Hero List.

    cf-content-type-personalized-hero-list-created
  7. Add a new entry using the content type Personalized Hero List.

    cf-list-entry-created
  8. For the field List Name, enter the following:

    Home Page Heros
  9. Click Link existing entries.

  10. Filter the search by the content type Personalized Hero and select the following entries:

    • Call for papers open now!
    • Can't wait to see you soon at UniformConf!
    • Developer Hero
    • Marketer Hero
    • Welcome to UniformConf
    cf-list-entries-selected
  11. Click Insert 5 entries.

    cf-list-entries-added
  12. Drag the entries into the following order:

    1. Can't wait to see you soon at UniformConf!
    2. Call for papers open now!
    3. Developer Hero
    4. Marketer Hero
    5. Welcome to UniformConf
    cf-list-entries-sorted

    About this step

    The order of the entries in the list is significant because the personalization criteria is evaluated in order. The first match is the entry that's displayed. This creates a priority for the personalization instructions. This is important because it's possible a visitor matches multiple criteria. It also affects the way you should go about testing that personalization works.

  13. Click Publish.

This section guides you through the process of importing the finished configuration into your Contentful space.

tip

If you followed the steps above, you can skip this section.

  1. In Uniform, add the following permissions to your Uniform API key:

    Uniform Context > Enrichments > Create Uniform Context > Enrichments > Update Uniform Context > Signals > Create Uniform Context > Signals > Update

    warning

    You should always assign the minimal permissions required to meet your requirements. Since this you are going to load configuration from a code repository into Uniform, you need permissions to write to Uniform.

    For more details on permissions, see the administrator guide.

  2. Open a terminal in the root of the repository.

  3. Enter the following command:

    npm run uniform:push

    About this step

    This imports the finished versions of the enrichments and signals.

  4. In Uniform, navigate to Personalization > Enrichments.

    uniform-developer-value-added

    About this step

    You will see the Persona enrichment with two values.

  5. Navigate to Signals.

    uniform-campaign-signal-added

    About this step

    You will see two signals.

  6. In the terminal, enter the following command:

    npm run cf:import-finished

    About this step

    This imports the finished versions of the content types, content entries, and media.

  7. In Contentful, open the content type Enriched Hero.

  8. For the field Enrichment Tags, click Settings.

    cf-finished-tags-settings
  9. Click Appearance.

    cf-finished-tags-appearance-default
  10. Click the Uniform logo.

    cf-finished-tags-appearance-uniform
  11. Click Confirm.

  12. Click Save to save the changes to the content type.

  13. Repeat these steps for the following content types:

    Content typeField
    Personalized HeroPersonalization Criteria
    Personalized Hero ListList Items

Uniform is designed to require minimal Uniform-specific product knowledge so developers can incorporate it into their apps as easily as possible. This section guides you through the process of adding personalization to the Next.js app.

tip

If you learn better by studying a fully implemented, working example, see the finished code section.

Add the following values to your .env file. You collected these values when you created the Uniform API key:

Uniform valueEnvironment variable
API KeyUNIFORM_API_KEY
Project IDUNIFORM_PROJECT_ID

About this step

These environment variables are needed in order for the npm build script to communicate with Uniform.

The Next.js application needs to have access to the personalization settings from Uniform. Uniform can generate a manifest that contains this information so you can use the settings in your application.

tip

In most cases, when using Uniform in an application that uses static site generation, you should generate the manifest before building the application. This ensures the latest manifest is available to the application.

  1. Open a terminal in the root of the repository.

  2. Enter the following command:

    npm install -D @uniformdev/cli npm install @uniformdev/context

    About this step

    This adds a reference to the package with the Uniform CLI, which is a tool that enables you to interact with Uniform from a command-line interface. It also adds a reference to the package that includes a Uniform CLI extension for interacting with Uniform Context from a CLI.

  3. Add the following to package.json:

    { "name": "contentful-uniformconf-nextjs", "description": "UniformConf for Contentful", "version": "0.1.0", "private": true, "scripts": { "cf:export": "node ./content/cf/export.cjs", "cf:import": "node ./content/cf/import.cjs", "start": "next start", "download:manifest": "uniform context manifest download --output ./contextManifest.json", "dev": "run-s download:manifest dev:next", "dev:next": "next dev", "build": "run-s download:manifest build:next", "build:next": "next build", "export": "next export", "ci:build": "next build && next export", "lint": "next lint" }, "dependencies": { ...

    About this step

    This adds a new script that downloads the manifest from Uniform, saves it to a file named contextManifest.json, and incorporates it into the scripts that start and build the application.

  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.

Adding Uniform Context to your application involves two primary tasks. One is making the manifest available to the application. This is required because it establishes the parameters for tracking and personalization. Two is creating a "context" object that's maintains state for Uniform Context within the app.

  1. Open a terminal in the root of the repository.

  2. Enter the following command:

    npm install @uniformdev/context-react cookie

    About this step

    This adds a reference to the package that enables you to add Uniform Context into applications build using React.

  3. Open the file ./pages/_app.jsx in your text editor.

  4. Add the following code:

    import Navbar from "../components/Navbar"; import Footer from "../components/Footer"; import "../styles/style.css"; import { Context, } from "@uniformdev/context"; const context = new Context({ }); ...
  5. Add the following code:

    import Navbar from "../components/Navbar"; import Footer from "../components/Footer"; import "../styles/style.css"; import { Context, } from "@uniformdev/context"; import manifest from "../contextManifest.json"; const context = new Context({ manifest, }); function MyApp({ Component, pageProps, }) { return ( <> <Navbar /%} <Component {...pageProps} /%} <Footer /%} <> ); } export default MyApp;
  6. Add the following code:

    ... const context = new Context({ defaultConsent: true, manifest, }); ...
  7. Add the following code:

    import Navbar from "../components/Navbar"; import Footer from "../components/Footer"; import "../styles/style.css"; import { Context, } from "@uniformdev/context"; import { UniformContext } from "@uniformdev/context-react"; import manifest from "../contextManifest.json"; const context = new Context({ defaultConsent: true, manifest, }); function MyApp({ Component, pageProps, }) { return ( <UniformContext context={context}> <Navbar /%} <Component {...pageProps} /%} <Footer /%} </UniformContext> ); } export default MyApp;
  8. Add the following code:

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

    About this step

    This enables the Uniform browser extension. Production sites usually don't have this enabled, but it can be very helpful during development and testing.

  1. In the terminal, enter the following command:

    npm run dev
  2. Open a browser window to http://localhost:3000 to view the UniformConf application.

    localhost-initial
  3. If you have the Chrome extension installed, you should see that the Uniform logo is now in full color (previously it was black and white). This means that Uniform Context was detected on the site.

    localhost-initial-with-extension

In Contentful you assigned enrichment tags to entries based on the Enriched Hero content type. The Uniform tracker is able to use these enrichment tags to track the visitor. The tracker can do this automatically, as long as the enrichment tags are included in the props for the page.

  1. Open the file ./lib/cf/fetch.js in your text editor.

  2. Add the following code:

    function getFields(entry) { const { fields } = entry; if (fields?.image) { fields.image = fields.image.fields.file.url; } if (!fields.id && entry.sys?.id) { fields.id = entry.sys?.id; } if (fields.unfrmOptEnrichmentTag) { fields.enrichments = fields.unfrmOptEnrichmentTag; delete fields.unfrmOptEnrichmentTag; } return fields; }
  3. Open the file ./components/Hero.jsx in your text editor.

  4. Add the following code:

    export const Hero = ({ title, description, buttonText, image, buttonLinkSlug, enrichments, }) => {
  5. Add the following code:

    import Link from "next/link"; import Splitter from "./Splitter"; import { Track } from "@uniformdev/context-react"; export const Hero = ({ title, description, buttonText, image, buttonLinkSlug, enrichments, }) => { return ( <Track behavior={enrichments}> <div className="pt-24"> ... </div> <Splitter /> </Track> ); };
  6. Open the file ./components/Navbar.jsx in your text editor.

  7. Add the following code:

    import React, { useState, useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { useScrollPosition } from "@n8tb1t/use-scroll-position"; import NavMenu from "./NavMenu"; import Logo from "./Logo"; import { useUniformContext } from "@uniformdev/context-react"; ... const Nav = () => { const [submenuVisible, setSubmenuVisible] = useState(false); const [isScrolled, setScrolled] = useState(false); const { context } = useUniformContext(); const router = useRouter(); ...
  8. Add the following code:

    ... <ActionLink isScrolled={isScrolled} onClick={async () => { setSubmenuVisible(false); await context.forget(true); document.cookie = "unfrmconf_registered=; Path=/; samesite=lax; Expires=Thu, 01 Jan 1970 00:00:01 GMT;"; } } label="Forget me" icon={<LockIcon /%}} /> ...
  9. In the terminal, enter the following command:

    npm install cookie
  10. Open the file ./components/RegistrationForm.jsx in your text editor.

  11. Add the following code:

    import { useUniformContext } from '@uniformdev/context-react'; import React from 'react'; import { useState } from 'react'; import Splitter from './Splitter'; export const RegisterForm = (fields) => { const [registered, setRegistered] = useState( typeof document !== 'undefined' ? !!document.cookie.match(/unfrmconf_registered/) : false ); const { context } = useUniformContext(); const onRegister = () => { document.cookie = 'unfrmconf_registered=true; path=/; samesite=lax'; setRegistered(true); }; ...
  12. Add the following code:

    import { useUniformContext } from '@uniformdev/context-react'; import { parse } from 'cookie'; import React from 'react'; import { useState } from 'react'; import Splitter from './Splitter'; export const RegisterForm = (fields) => { const [registered, setRegistered] = useState( typeof document !== 'undefined' ? !!document.cookie.match(/unfrmconf_registered/) : false ); const { context } = useUniformContext(); const onRegister = () => { document.cookie = 'unfrmconf_registered=true; path=/; samesite=lax'; context.update({ cookies: parse(document.cookie) }); setRegistered(true); }; ...
  13. Open a browser window to http://localhost:3000/developers to view a page with an enrichment tag assigned.

    localhost-page-developers
  14. Open the browser extension and navigate to Dimensions.

    localhost-page-developers-extension-initial

    About this step

    This shows that the tracker collected data, but it's not very intuitive. It says that the dimension "1_2" has a score of "50." The "1_2" is a combination of the public IDs for the enrichment Persona and the enrichment value Developer.

  15. In the extension, click Settings.

    localhost-page-developers-extension-settings
  16. Click Manage Connection to Uniform.

  17. Enter the Quick Connect Code you used to configure the app in Contentful.

    localhost-page-developers-extension-settings-set

    About this step

    These settings give the browser extension the ability to read metadata directly from Uniform. This makes it possible to translate "1_2" into something meaningful.

  18. Click Save.

    localhost-page-developers-extension-connected
  19. In the extension, click Dimensions. Now you will see more meaningful descriptions of what the tracker has collected.

    localhost-page-developers-extension-dimensions
  20. In your browser, navigate to http://localhost:3000/marketers.

  21. Open the browser extension. Now you will see that you have scores for 2 enrichments.

    localhost-page-marketers-extension-dimensions

    About this step

    You can see that tracking is working. The next step is to personalize the visitor's experience based on this information that has been tracked.

In Contentful you configured a content entry that represents a personalized list of hero entries for the home page. Uniform provides a React component that can execute the personalization settings configured in the list. This section describes how to add that component to the front-end application.

  1. Open the file ./lib/cf/fetch.js in your text editor.

  2. Add the following code:

    function getFields(entry) { const { fields } = entry; if (fields?.image) { fields.image = fields.image.fields.file.url; } if (!fields.id && entry.sys?.id) { fields.id = entry.sys?.id; } if (fields.unfrmOptEnrichmentTag) { fields.enrichments = fields.unfrmOptEnrichmentTag; delete fields.unfrmOptEnrichmentTag; } if (fields.unfrmOptPersonalizationCriteria) { fields.pz = fields.unfrmOptPersonalizationCriteria; delete fields.unfrmOptPersonalizationCriteria; } return fields; }

    About this step

    This code should look familiar because it's similar to the code you added to rename the field for the enrichment tags. In this case, the personalization criteria is stored in Contentful in a field unfrmOptPersonalizationCriteria, where Uniform expects the field pz.

  3. Add the following code:

    export async function fetchVariations(id) { const entry = await fetch(id); const { unfrmOptP13nList } = entry; return unfrmOptP13nList.map(getFields); }
  4. In Contentful, open the content entry Home Page Heroes.

  5. Navigate to Info and note the ENTRY ID.

  6. Open the file ./pages/index.jsx.

  7. Make the following changes:

    import { Hero } from "../components/Hero"; import { fetchVariations } from "../lib/cf/fetch"; export async function getStaticProps() { const fields = await fetchVariations("29zgaRj1vU1idUq3ydCQeU"); return { props: { ...fields } } } export default function Home(props) { return <Hero {...props} />} };

    About this step

    For the call to fetchVariations, make sure you use the entry ID for the Home Page Heros entry.

  8. Make the following changes:

    import { Hero } from "../components/Hero"; import { Personalize } from '@uniformdev/context-react'; import { fetchVariations } from "../lib/cf/fetch"; export async function getStaticProps() { const fields = await fetchVariations("29zgaRj1vU1idUq3ydCQeU"); return { props: { ...fields } } } export default function Home({ variations }) { return ( <Personalize variations={variations} name="heroPersonalized" component={Hero} />} ); };

    About this step

    The Personalize component receives the collection of the possible variations that were configured in the personalized list in Contentful and is able to evaluate the personalization criteria to find a match.

We provide a finished version of the UniformConf application that you can get running in your preferred environment.

  1. Clone the following repository:

    https://github.com/uniformdev/uniform-docs-examples
  2. Check out the following branch:

    apps/contentful/nextjs/context-activated
  3. Set variables in .env to match the settings that apply to your Contentful and Uniform environments.

  4. Enter the following command:

    npm install
  5. Enter the following command:

    npm run dev

    About this step

    This will start the Next.js app in develop mode on port 3000.

Now that you have a fully functional Next.js application powered with content from Contentful and personalized using Uniform Context, you can use this as a starting point for exploring everything Uniform has to offer, including:

  • Presentation builder - Uniform Canvas offers a tool that gives content authors control over presentation within constraints defined by developers, in a way that fits into modern digital production processes.