Scalable list-based personalization

This recipe describes how to enable content authors to configure personalized lists that are based on a combination of what they know about their site's visitors and content.

Demo of this recipe in action.
  • A content author can define personalization rules that determine which entries in a reference list are displayed and the order the entries are displayed.
  • An entry may be used in multiple reference lists, but the personalization rules are applied to the list of entries, rather than the entries themselves.
  • Content authors manage website content and personalization in Contentful.
  • Uniform enables content authors to configure personalization in Contentful.
  • The website is built using Next.js.

Location detail pages play a large role on your website. Rather than being limited to a specific section of the site, locations are available throughout. Your content authors create curated lists of locations in Contentful.

They want to add personalization to these curated lists. However, the personalization rules that apply to a location depend on the list, not the location.

Example

The headquarters location may always be displayed on a list of locations in the "about us" section of the site, but when that same location is included in a location list in the "training" section, it only need to be displayed if the visitor is located in the same country as the headquarters.

This recipe assumes you have the following:

  • Your Contentful space has the Uniform app installed.
  • Your Next.js application already has personalization activated.
  • Your Next.js application uses the page router and TypeScript.

    Technically neither of these is a requirement for the approach described in this recipe, but the instructions are written for an app that uses this configuration.

  • Your Next.js application uses client-side personalization.

    This recipe will work with edge-side personalization, but in order to keep the instructions as simple as possible, these instructions assume client-side personalization is used.

Walk-through the of the steps in this section.

A personalization rule is an instruction that controls how personalization operates. Just like rules in the real world, a personalization rule describes two things:

What does this describe?How this will be implemented in this solution?
CriteriaWhat needs to be true in order for the rule to take effect.This solution involves two criteria: visitor classification and enrichment tags assigned to the location in the list. For example, the personalization rule will take effect if the visitor is interested in a certain topic and the location is tagged with that same topic.
ActionWhat happens when the condition is true.This solution supports two actions for when the criteria is true: the location will be boosted to the top of the list, or the location will be removed from the list.

The following steps describe how to create a content type that allows a content author to describe personalization rules.

  1. In Contentful, create the following content type:
    NamePersonalization Rule
    Api IdentifierpersonalizationRule
  2. Add the following field:
    PropertyValueNotes
    Field typeShort text
    NameName
    Field IDname
    This field represents the Entry titleChecked
    Required fieldChecked

    About this step

    This is a human-readable description of the personalization.

  3. Add the following field:
    PropertyValueNotes
    Field typeShort text
    NameAction
    Field IDAction
    Required fieldChecked
    Accept only specified valuesCheckedboost and hide
    AppearanceDropdown

    About this step

    This field allows the content author to control the action for the personalization rule. This action is applied to the locations in the list when the criteria (not yet configured) is met.

  4. Save the content type.
  5. Open the Uniform app configuration page.

    About this step

    You get to the Uniform by by navigating to Apps > Installed apps > Uniform > Configure.

  6. Enable enrichment taggings on the content type.
  7. Enable personalization criteria on the content type.

    Be sure to click the Save button

  8. Return to the content type.
  9. Rename the following fields:
    Current nameNew nameNotes
    Enrichment TagsContent CriteriaThis field represents part of the personalization rule's criteria. It allows content authors to specify the enrichment tags that must be assigned to the location in order for the personalization rule to take effect.
    Personalization CriteriaVisitor CriteriaThis field represents part of the personalization rule's criteria. It allows content authors to specify the classification dimensions must be true of the visitor's session in order for the personalization rule to take effect.
  10. Add the following field:
    PropertyValueNotes
    Field typeShort text
    NameContent Criteria Match Type
    Field IDcontentCriteriaMatchType
    Accept only specified valuesCheckedall and any
    AppearanceRadio

    About this step

    This field represents part of the personalization rule's criteria. The field Content Criteria allows the content author to select multiple enrichment tags. This field allows the content author to specify specify how many of the selected enrichment tags must be set on the content in order for the rule to take effect: all means every one of the selected tags must be set, while any means just one of the selected tags must be set (any).

  11. Change the order of the fields to the following:
    PositionField name
    1Name
    2Action
    3Visitor Criteria
    4Content Criteria
    5Content Criteria Match Type
  12. Save the content type.

In this example, a content type already exists that represents a location. Enrichment tagging has already been enabled on the content type, so no changes are needed.

In this example, a content type already exists that represents a location list. You need to add the ability for content authors to assign personalization rules so they can control personalization.

  1. Open the content type Curated Location List.
  2. Add the following field:
    PropertyValueNotes
    Field typeReference
    NamePersonalization Rules
    Field IDpersonalizationRules
    TypeMany references
    Required fieldChecked
    Accept only specified entry typeCheckedPersonalization Rule
    AppearanceDropdown

    About this step

    This field allows the content author select the personalization rules that apply to the entries in the field Locations.

  3. Change the order of the fields to the following:
    PositionField name
    1Title
    2Personalization Rules
    3Locations
  4. Save the content type.

You have given content authors the ability to configure personalization. Now you need to update the Next.js application in order to make that configuration available to the code responsible for displaying location lists.

  1. Add the following npm packages:

    npm

    npm i @uniformdev-collab/rule-based-personalization \ @uniformdev-collab/rule-based-personalization-contentful \ @uniformdev-collab/rule-based-personalization-react \ @uniformdev-collab/rule-based-personalization-react-contentful
  2. In your _app.tsx file, add the following before the default component is defined:

    ./src/pages/_app.tsx

    import { ContentfulPzConfigLookupConfig, ContentfulPzRuleLookupConfig, } from "@uniformdev-collab/rule-based-personalization-contentful"; /** * Define how Uniform should handle the personalization * entries that have personalized lists on them. */ const contentfulPzConfigs: ContentfulPzConfigLookupConfig = { /** * There is no default configuration, which means that * a content type must be specifically configured in * the 'elements' section in order for Uniform to be * able to personalize a list on an entry. */ defaultElement: undefined, elements: { /** * The settings below only apply to entries with * the content type 'curatedLocationList'. */ curatedLocationList: { contentEntriesFieldId: "locations", pzRulesFieldId: "personalizationRules", }, }, }; /** * Define how Uniform should handle the entries that represent * the personalization rules that control personalized lists. */ const contentfulPzRuleConfigs: ContentfulPzRuleLookupConfig = { /** * These settings are used for entries that represent * personalization rules. These are the default settings. * The 'elements' section can be used to define settings * that apply to specific content types. */ defaultElement: { /** * Entry field that represents the rule name. */ nameFieldId: "name", /** * Entry field that represents the rule action. */ actionFieldId: "action", /** * Entry field that represent the content criteria * match type (i.e. 'all' or 'any'). */ contentCriteriaMatchTypeFieldId: "contentCriteriaMatchType", }, /** * There are settings that only apply to a specific content type. */ elements: {}, };
  3. Add the following code:

    ./src/pages/_app.tsx

    import { RuleBasedPersonalization, } from "@uniformdev-collab/rule-based-personalization-react"; ... <UniformContext context={...}> <RuleBasedPersonalization context={clientContext} pzConfigs={contentfulPzConfigs} pzRuleConfigs={contentfulPzRuleConfigs} > ... </RuleBasedPersonalization> </UniformContext> ...
  4. In the page that has the component that displays the location list, add the following code:
    import { Entry } from "contentful"; import { useEffect, useState } from "react"; import { useUniformContext, } from "@uniformdev/context-react"; import { useContentfulRuleBasedPz, } from "@uniformdev-collab/rule-based-personalization-react-contentful"; ... export default function HomePage(props: HomePageProps) { const { context } = useUniformContext(); const { doPersonalize } = useContentfulRuleBasedPz(); const [locations, setLocations] = useState<Entry>(); /** * This example assumes the Contentful entry is provided * in props. This entry should represent the curated * location list. */ const { entry } = props; /** * On mount, run personalization and add event listeners * on the tracker so personalization runs when visitor * dimensions change. */ useEffect(() => { personalize(); context.events.on("scoresUpdated", personalize); return () => { context.events.off("scoresUpdated", personalize); }; }, []); function personalize() { if (entry) { const { personalized } = doPersonalize(entry); /** * This example assumes */ setLocations(personalized); } } ...

The video at the top of this page demonstrates how the solution is used.

  1. Create a new entry using the content type Curated Location List.
  2. Create new entries using the content type Personalization Rule.
  3. Assign the personalization rules to the field Personalization Rules.
  4. Publish the entries.
  5. Test the personalization.