Skip to main content

UniformConf with Next.js

This tutorial guides you through the process of 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 author can assign enrichments to entries in order to identify the visitor's interests.
  • Content author 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.

Prerequisites

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 do not already have a Uniform account, you can get a free one at https://uniform.app.
  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 is not required to use Uniform Context, but it makes development and testing much easier.

Create Uniform project

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

Configure Contentful

Load sample content into Contentful

  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 in order 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/uniformconf-nextjs
  5. Add the following file:

    .env
    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 contentful: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.

Install Marketplace app

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.

Configure space

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 as quickly as possible and just import the finished configuration into your Contentful space, you can skip to the finished configuration section.

Configure Enriched Hero entries

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 are not available to be used in an application until they are 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.

Configure Personalized Hero entries

Personalized Hero entries provide the personalized content that will be displayed on the home page. The specific entry that is 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 are not available to be used in an application until they are 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 is 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.

Configure list of Personalized Heros

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 heros.

  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 is displayed. This creates a priority for the personalization instructions. This is important because it is possible a visitor matches multiple criteria. It also affects the way you should go about testing that personalization works.

  13. Click Publish.

Finished configuration

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
    caution

    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

Update Next.js app

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 Uniform environment variables

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

Uniform valueEnvironment variable
API Key
UNIFORM_API_KEY
Project ID
UNIFORM_PROJECT_ID
About this step

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

Download manifest

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 does not get added to your source code repository.

Add Context to app

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 is 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 do not have this enabled, but it can be very helpful during development and testing.

Start app

  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

Activate tracking

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.

Activate personalization

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 is very 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 Heros.

  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.

Finished code

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

  1. Open StackBlitz to create your development environment.
  2. After you open StackBlitz you will see an error in the terminal that environment variables are not set. You must set the variables in .env to match the settings that apply to your Contentful and Uniform environments.

  3. Changing the .env file should cause the container to restart. If it doesn't, enter the following command in the StackBlitz terminal:

    npm run dev
  4. In the activity bar the plug icon indicates that 1 port is in use. Click this icon.

    stackblitz-ports-in-use
  5. You will see links to the web app running on the 1 port. Click the link for Port 3000.

    stackblitz-ports-in-use-2
  6. A new browser tab opens. This is your Next.js application running in develop mode.

    https://uniformdev-uniform-docs-examples-######--3000.local.webcontainer.io/

Next steps

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.