XM Cloud- Sitecore CDP Interactive Personalization with Sitecore Pages Variants

Sitecore XM Cloud provides out-of-box personalization using Edge, we are able to create personalization page variants with the help of Sitecore Pages by setting the proper audience.

With the help of Edge personalization XM Cloud is only able to track page views, also the audience rules are also limited, if we want to personalize based on more complex user behaviors, orders, etc, it is not possible with out-of-box personalization.

Sitecore CDP provides personalization based on different factors like

  • User behavior
  • Orders
  • Visits
  • Sessions etc
I want to personalize the home page based on the Sitecore pages variant by using Sitecore CDP interactive experience. Also, we don't want to reinvent the wheel of all the fun things XM Cloud Personalize middleware does for us.

Usually, Sitecore Page Variant personalization is only applicable with Edge-based personalization.
Personalization Middleware does these actions out-of-box for Edge
  • Makes a call to the Sitecore Experience Edge endpoint to get the personalization information about the page, including variants.
  • Calls the Sitecore CDP endpoint with request/user context to determine the page variant to display based on the response.
  • Rewrites the response to the specific page variant using the personalized rewrite path.
  • APIs used by the middleware
    • getPersonalizedRewriteData
    • normalizePersonalizedRewrite
    • personalizeLayout
Steps to replace the edge personalization with Sitecore CDP Interactive personalization:
  • Create a home page with  3 Sitecore Pages variants with some audience, As we are not going to consider the audience in case of CDP personalization.
  • After creating the variant, each variant will be assigned the unique id, we can able to get this variant id from the below screenshots.



  • Once datasource and Page variants are ready, let's customize the middleware to trigger CDP  Interactive Experience and load dynamically page variants for personalization based on decision model offers provided by Sitecore CDP
  • As Middleware in Nextjs runs on every request we need to trigger personalization only on the home page.
  • Get the browser Id of the current user from the browser cookie which was already created by the Engage SDK based on the necessary environment variables(more details), Also PageView events are also triggered by CdpPageView.tsx component,
  • We need to trigger the out-of-box Personalization middleware(Engage SDK) by manipulating the current URL path to include the variant path to get the particular page variant data from the Sitecore Pages variant instead of the default variant.
    • http://localhost:3000/_variantId_{variant id}
    • The variant id is obtained from the Interactive experience decision model
  • Goto to the following file middleware.ts in the root of the application and update the code for triggering personalization which is provided below.
  • We have to create an interactive experience to display offers based on page views.
    • For example, if the user page views less than or equal to 1 then the default page variant will be loaded and no personalization happens based on the variant. 
    • Personalization will happen only if the pageview is greater than 1.
  • Also created the Offer template to include the fields to have information about the Sitecore Pages Variant Id etc
Offer Template:
  • Add Offer template to include Sitecore page variant id and name etc to trigger personalization
Programmable:
  • Create a decision model programmable to return the pageviews based on request params input from frontend, this will used in decision model for offer (Page Variant) selection




Postman request:
  • To get the variant id from the Offers.





Code Sample:

import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
import middleware from 'lib/middleware';
import { data } from './data';
import { GetRequestData, TriggerExperience } from './GetRequestData';

export default async function (req: NextRequest, ev: NextFetchEvent) {

  let browserId=req.cookies.get('BID_xxxxxxxxxxxxxxxxxxxxxxx')?.toString();
    let reqObj: data = GetRequestData(browserId)
  //Check if the request path has already has variant path for personalization then skip
  if(req.nextUrl.pathname.includes('_variant'))
        return middleware(req, ev);
 //Check if the browser id created already been created, if so then trigger
 //the experience to match relevant offers (Sitecore pages variant) from xmcloud and
 //render the rendering.
  if(!req.cookies.get('BID_xxxxxxxxxxxxxxxxxxxxxxxxxxx'))
      return middleware(req, ev);  

    let result =await TriggerExperience(reqObj);
    const url = req.nextUrl.clone()  
   //Personalize home page rendering based on CDP offer and get the Sitecore Pages
   //Variant from xmcloud
   //Example of the variant path:
   // http://localhost:3000/_variantId_149021d65b67436daf4075636dd7e30d
   //Also checking if OfferId is default ie) no personalization needs to happen
    if (url.pathname === '/' )
    {
        if(result.decisionOffers[0].attributes.OfferId !=="default") {
        url.pathname = `/_variantId_${result.decisionOffers[0].attributes.OfferId}/${url.pathname}`
        console.log(`=====Offer variant path ${ url.pathname}=======`)
        return NextResponse.rewrite(url)
        }
    }
    else
    {
        return middleware(req, ev);
    }
    return middleware(req, ev);
}
export const config = {
  // Exclude Sitecore editing API routes
  matcher: ['/', '/((?!api/editing/).*)'],
};

Interface Used to map the input and output from CDP
  • Create separate file data.ts for interface
export interface data {

  clientKey: string;
  channel: string;
  language: string;
  currencyCode: string;
  pointOfSale: string;
  browserId: string;
  params: Params;
  friendlyId: string;

}
export interface Params {

  pageviews: number;

}
export interface Root {
  decisionOffers: DecisionOffer[];
}

export interface DecisionOffer {
  ref: string;
  name: string;
  description: string;
  status: string;
  attributes: Attributes;
}

export interface Attributes {
  OfferName: string;
  OfferVariant: string;
  OfferId: string;
}

Functions for Triggering the Experience
  • Create separate file GetRequestData.ts for functions
import { data, Root } from './data';

export const TriggerExperience = async (reqData: data) => {
  console.log(`=====calling Trigger expereiene"${JSON.stringify(reqData)}=====`);

  const res = await fetch("https://api-us.boxever.com/v2/callFlows", {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(reqData),
  });
  let result: Root = await res.json();
  return result;
};
export function GetRequestData(browserId: string | undefined): data {
  return {
    clientKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    channel: "WEB",
    language: "en",
    currencyCode: "USD",
    pointOfSale: "JNJR.com",
    params: { pageviews: 1 },// pageviews is used to get Offer(Variant) from CDP
    browserId: browserId !== undefined ? browserId : "",
    friendlyId: "xmexperience"
  };
}


Lets see the personalization in action:
  • Update the pageviews in the GetRequestData method to 0 or 1. and start the app npm run start:connected
  • Update the pageviews in the GetRequestData method to 2


  • Update the pageviews in the GetRequestData method to >=3


Happy Programming 😊


Comments

Popular posts from this blog

Custom Item Url and resolving the item in Sitecore - Buckets

Exploring Sitecore XM Cloud Forms: A Comprehensive Overview

Sitecore Custom Rule (Action and Condition)