Troubleshoot personalization on xm cloud

Here are the troubleshooting steps below that helped personalization to work.

  • We checked the events analytics in the page builder but it was showing nothing for the interaction related to the personalization rules that we created. This mean something is not correct with personalization.

  • I Checked whether the sc_[your-environment-context-id]_personalize cookie is being generated or not. In our case this cookie was not creating in the browser. So it was clear that something is not right with personalization.

  • When personalization works internally, it executes the following graphql query. So I tried this in the edge playground.

query ($siteName: String!, $language: String!, $itemPath: String!) { layout(site: $siteName, routePath: $itemPath, language: $language) { item { id version personalization { variantIds } } } }

Query Variables wrt to home page:

{ "siteName": "yoursitename", "language": "en", "itemPath": "/" }

It will give the response something as

{ "data": { "layout": { "item": { "id": "9640F7E7BBF44502AC38D6FCDFE2C40C", "version": 1, "personalization": { "variantIds": [ variantIds: [ 'fdfc2ba8bsdfsdfsdfsd938b6a11ec641', '0311f9sdfsdfsfwefwef8876a12b72873', 'd2e63ccwgghsdsdfgfwer5c22b84052f3', '5540a6sdcewetgwgsdcsdcwgs116ee8c1', ] } } } } }

In the response, you will see the variantIds. Please note, the default variant ID is not returned here, so if you created 4 additional personalization variants on top of the default, you should see two 4 different variant IDs.

If this is coming this means personalization middleware is able to get the personlization rules setup on the page.

  • Now try to run the layout query to check if it gives you the experiences json object to confirm that your personalization rules are correctly setup and are available on the page so that when personalization will work fine it will be able to get the correct rule specific data from the response.

We tested the following graphql query:

This confirmed that layout rules' datasources are configured correctly as we are able to get the datasources path in the experiences object.

  • Now need to check from code side if something is failing and for that we need to enable the sitecore personalization debugging by setting the DEBUG=sitecore-jss:personalize in the .env or .env.local file. It gives the complete logging info in the PS console or CMD where ever you have run the command (npm run start:connected) to run the site.

  • When you reload the page find for the text sitecore-jss:personalize. One instance should give like following

sitecore-jss:personalize personalize middleware start: { pathname: '/', language: 'en', hostname: 'yoursitename.localhost', headers: { accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', accept-encoding: 'gzip, deflate, br, zstd', accept-language: 'en-GB,en-US;q=0.9,en;q=0.8', cache-control: 'max-age=0', connection: 'keep-alive', cookie: 'sc_site=yoursitename; sc_4TQLWsdfsdf4bQAITV=d60dbc09-sdfsdf-b4c4-5a0cf44fbe20; sc_4TQLWxfsdfsdU4bQAITV_personalize=ebasdfsdfsd-b8d0-2c3d9b10508e; _ga=GA1.1.1525788197.1767721218; _ga_JNR39H2DHS=GS2.1.s1767721217$o1$g1$t1767721219$j58$l0$h0', host: 'yoursitename.localhost:3000', referer: 'http://yoursitename.localhost:3000/', sec-ch-ua: '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"', sec-ch-ua-mobile: '?0', sec-ch-ua-platform: '"Windows"', sec-fetch-dest: 'document', sec-fetch-mode: 'navigate', sec-fetch-site: 'same-origin', sec-fetch-user: '?1', testing: 'yobwoc5991', upgrade-insecure-requests: '1', user-agent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', x-forwarded-for: '::1', x-forwarded-host: 'yoursitename.localhost:3000', x-forwarded-port: '3000', x-forwarded-proto: 'http' } } +7s

Note the pathname. It should be your page URL. If there will any issue to load the personalization for this pathname it will be just after this block.

  • In our case the error was like

Personalization is not enabled.

I did something like following to enable it locally in the file \headapps\nextjs-starter\src\lib\middleware\plugins\personalize.ts


and, in the file \headapps\nextjs-starter\src\components\CdpPageView.tsx


After this I got new error as:

[IE-0018]: Personalize middleware failed:
[TypeError: (0 , server_2.CloudSDK)(...).addPersonalize is not a function]

When checked further on sitecore documenation here https://doc.sitecore.com/sdk/en/developers/latest/cloud-sdk/troubleshooting-the-cloud-sdk.html#ie-errors we noticed the resolution as in screenshot below:


  • On checking further we noticed that we had to upgrade the npm packages as follows:










  • and modify the code in the \headapps\nextjs-starter\src\Bootstrap.tsx as follows

  • After upgrading the packages and fixing the boostrap.jsx, the error for addPersonalize() method was resolved but still it wasn’t working. We searched for the text sitecore-jss:personalize in the PS console and now we noticed the error as

IE-0002

Timeout exceeded. The server did not respond within the allotted time.

This error’s resolution was to increase the default timeout value of 400 to greater than this. I tried with following in the .env file.


After doing all those steps. I noticed that cookiesc_[your-environment-context-id]_personalizeis now available.


Now when I reload the page then all the personalization rules based on utm query string and device were working fine.

What is rebasing

 Let's understand it by example:

Query: I created a feature branch upgrade10.4, from develop 3 months ago and worked on it. On develop, the team was working on sitecore 9.3 specific code. After completing the upgrade work on feature branch now I want to sync all the changes that were going parallelly, on the develop, with upgrade 10.4 to get all the changes of develop on my feature. How can I rebase it?

Solution: ✅ Correct Mental Model (Very Important)

  • develophas latest business changes, but 9.3-specific 

  • upgrade10.4has upgrade changes, but missing last 3 months of develop work

So the operation is:
Rebase upgrade10.4 onto develop


Query: Doesn't it sounds odd that re base feature branch onto develop, where onto sounds like we are migrating changes from feature to develop.

Solution: This confusion is very common, and you’re right to pause — the wording does sound counter-intuitive at first. The key is that “onto” does NOT mean “into”.

The Precise Meaning of “rebase X onto Y”

Rebase X onto Y means
👉 Take the commits from X and replay them on top of Y

It does NOT mean:

  • merging X into Y

  • moving changes from X to Y

  • modifying Y at all

Only X changes, Y stays untouched.

BEFORE:

A---B---C---D   develop (Sitecore 9.3 work)

        \

          E---F---G   upgrade10.4 (your feature work)


  • develop continued with C-D
  • upgrade10.4 branched at B and added E-F-G

Command You Run

  • git checkout upgrade10.4
  • git rebase develop


This literally means:

“Take commits E-F-G and replay them as if they were created after D.”


AFTER REBASING:

A---B---C---D---E'---F'---G'   upgrade10.4

                   ^

          develop (unchanged)

 

Important:

  • develop does not move

  • upgrade10.4 changes base

  • Your commits are copied, not moved


Why the Word “onto” Is Misleading

Natural language suggests:

“Put feature onto develop”

But Git language means:

“Put feature commits on top of develop”

A better mental phrasing is:

“Rebase feature so that it sits on develop”


Rebase does exactly that, but in a clean, linear way:

  • You get all develop changes

  • Your upgrade commits appear last

  • History looks like upgrade happened after latest develop

 



SIF Sitecore installation and unistallation

 

  • We can check the priority version by executing the GetModule command which I have mentioned above.


  • Open PowerShell as administrator
  • Type Get-Module SitecoreInstallFramework –ListAvailable and enter
  • You should see all the SitecoreInstallFramework in your machine.

  • Uninstall-Module -Name "SitecoreInstallFramework" -AllVersions
  • Install-Module -Name SitecoreInstallFramework -Repository SitecoreGallery -RequiredVersion 2.4.0

  • Switching versions: Force PowerShell session to use the version you need. Just execute the below command in powershell as administrator
    • Remove-Module -Name SitecoreInstallFramework
    • Import-Module -Name SitecoreInstallFramework -RequiredVersion #Version Number like 1.2.1

Creating Solr core for sitecore using command prompt

We setup the solr cores using command “C:\solr8985\sc103solr-8.11.2\bin>solr.cmd create -c sitecore_sxa_web_index -d sitecore_configset” and followed the following for configsets https://stackoverflow.com/questions/33060048/sitecore-best-practices-for-setting-up-solr-core-for-multisite.

a) Used the following steps to create the cores

i. Copy conf folder solr\server\solr\sitecore_master_index\conf

ii. Paste into solr\server\solr\configsets\sitecore_configset <-- create this new folder

iii. Run command C:\solr8985\sc103solr-8.11.2\bin>solr.cmd create -c [your-custom-index] -d sitecore_configset

Preview graphql vs Edge graphql playground UI

The preview graphql playground is used to read the unpublished content and the edge graphql playground is used to read the published content.

Here is how preview playground looks




This is how edge playground ui looks


The Url of the edge playground will be same but at the bottom you see, you will have to pass the API Key from deploy.sitecorecloud.io specific to the dev, qa, uat environment.


The url of the preview playground will be different in terms of the hostname. You have to provide the cms hostname for which environment's cms you want to check the preview dev, qa or uat. Also, you need to get the API key, the sitecore item guid which remain in the folder /sitecore/system/Settings/Services/API Keys

Test Multi site setup with xm cloud and local next js app

 1. Verify multisite setup in Sitecore

In XM Cloud, make sure your cloned site has:

  • A new Site Definition item (in /sitecore/content/<your site>).

  • A hostname assigned under Site Grouping. This is important for routing.


If you have to create the site use the clone script in the SXA to create new website it will take care of referencing the new items wrt to your new site and new items automatically


2. ensure you have the multisite.ts middleware file with something like

// middleware/multisite.ts
import { MultisiteMiddleware } from '@sitecore-jss/sitecore-jss-nextjs/middleware';
import { siteResolver } from 'lib/site-resolver';
import type { MiddlewarePlugin } from '.';

export class MultisitePlugin implements MiddlewarePlugin {
  private multisiteMiddleware: MultisiteMiddleware;

  constructor() {
    this.multisiteMiddleware = new MultisiteMiddleware({
      siteResolver,
    });
  }

  async exec(req, res, next) {
    return this.multisiteMiddleware.getHandler()(req, res, next);
  }
}

Somewhere in your code there should be SiteResolver file also that decides which site to execute in the multisite.ts

There also should some code related to the multisite.ts as follows somewhere in your project like

import type { SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs/site';
import config from 'temp/config';
import type { SiteResolverPlugin } from '..';

class MultisitePlugin implements SiteResolverPlugin {
  exec(sites: SiteInfo[]): SiteInfo[] {
    // Add preloaded sites
    sites.push(...(JSON.parse(config.sites) as SiteInfo[]));

    return sites;
  }
}

export const multisitePlugin = new MultisitePlugin();

Below is the SiteResolver

import type { SiteInfo } from '@sitecore-jss/sitecore-jss-nextjs/site';
import { SiteResolver } from '@sitecore-jss/sitecore-jss-nextjs/site';
import * as plugins from 'temp/site-resolver-plugins';

/*
  The site resolver stores site information and is used in the app
  whenever site lookup is required (e.g. by name in page props factory
  or by host in Next.js middleware).

  By default, the app is single-site (one JSS app per Sitecore site).
  However, multi-site is available with the `nextjs-multisite` add-on.
*/

export interface SiteResolverPlugin {
  /**
   * A function which will be called during sites collection
   */
  exec(sites: SiteInfo[]): SiteInfo[];
}

const sites = (Object.values(plugins) as SiteResolverPlugin[]).reduce(
  (sites, plugin) => plugin.exec(sites),
  []
);

export const siteResolver = new SiteResolver(sites);


3. Once you site is created then in the SXA Site Grouping you need to provide value in the sitename and hostname field


Because these setting will be used to confirm which site to execute.

4. Configure .env.local
SITECORE_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx // this is used for querying from preview

SITECORE_API_HOST=https://your-xmcloud-cmsinstance-url.sitecorecloud.io // this is preview graphql url in case to query from Edge url will be https://edge.sitecorecloud.io/

SITECORE_EDGE_CONTEXT_ID=your-edge-context-id // this is used for querying from edge

NEXT_PUBLIC_SITECORE_API_HOST=http://localhost:3000

GRAPH_QL_ENDPOINT=https://edge.sitecorecloud.io/api/graphql/v1 //this is Edge graphql url

GRAPH_QL_ENDPOINT=https://your-xmcloud-cmsinstance-url.sitecorecloud.io/sitecore/api/graph/edge // this is preview graphql url

Yellow setting are required for checking the preview mode site and amber are required to check the Edge (published) mode site.

5. If you noticed in the point 2, the sites information are read from 
config.sites, therefore you need to setup one more setting in the .env.local as 

#multisites
SITES=[{"name":"firstsitename","hostName":"firstsitename.localhost","language":"en"},{"name":"secondsitename","hostName":"secondsitename.localhost","language":"en"}]

6. Use multiple hostnames locally

Edit your hosts file (C:\Windows\System32\drivers\etc\hosts on Windows or /etc/hosts on Mac/Linux):

127.0.0.1 firstsitename.localhost
127.0.0.1 secondsitename.localhost

Now you can run your Next.js app with:

  • http://site1.localhost:3000 → serves Site 1

  • http://site2.localhost:3000 → serves Site 2

(based on your resolver logic).

7. Run locally

Start Next.js as usual:


npm run dev or npm run start:connected

8. Here it will work when you will hit http://firstsitename.localhost:3000 
-> it will go to your nextjs app because next js app is running on 3000 port 
-> it will go to the multisite.ts and will read the setting for config.sites 
-> config.site will give array of [{"name":"firstsitename","hostName":"firstsitename.localhost","language":"en"},{"name":"secondsitename","hostName":"secondsitename.localhost","language":"en"}] because you have set in the .env.local setting
-> based on the hostname it will get the sitename from the JSON's name property
-> graphql will internally pass the sc_site query with that site name 
-> based on your setting specific to the yellow or amber the data will be provided to you from cms.





Graphql playground in local sitecore cms

 To setup the graphql playgroun in the local sitecore CMS you need to install the sitecore headless package that you can download from Sitecore headless rendering link.

When you have installed it you can verify if the JSS is installed or not using following ways.

1. Check in the folder C:\inetpub\wwwroot\sc.dev.local\App_Config\Sitecore if LayoutServices folder, JavaScriptSerivces and Services.GraphQL folder is created, and

2. Check at the path /sitecore/system/Modules, Layout service and JavaScript Services are present in the CMS.



Once this is installed now you can enable the Playground locally. 

  1. There will be one file as Sitecore.Services.GraphQL.Content.Master.config.example in the folder C:\inetpub\wwwroot\sc.dev.local\App_Config\Sitecore\Services.GraphQL. it will be disabled but you can copy in the /Include/zzz folder and enable it.
  2. After doing try to hit the url https://sc.dev.local/sitecore/api/graph/items/master in the browser and check it is giving something except error. If it give unauthorize error then enable the graphql by using the following patch

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">

  <sitecore>
    <settings>
      <!-- Enables GraphQL Playground IDE in local environments -->
      <setting name="GraphQL.Enabled" value="true" />
    </settings>
  </sitecore>
</configuration>

3. If it still doesn't work then try to put the <path>/sitecore/api/graph/items</path> in the App_Config\Sitecore\Owin.Authentication\Sitecore.Owin.Authentication.config as follows:


After doing these changes now https://sc.dev.local/sitecore/api/graph/items/master should work and you can open the playground ui with url https://sc.dev.local/sitecore/api/graph/items/master/ui and try to run the following graphql to check if it is working. It should work otherwise check your API Key in the header below

{
  item(path: "/sitecore/content/Home", language: "en") {
    id
    name
    displayName
    fields {
      name
      value
    }
  }
}

or, in case you have SXA

query { 
  layout(language: "en", routePath: "/", site: "sitename") { 
    item { 
      rendered 
    } 
  } 



If you get unauthorize error message on browser then use the following patch for local only.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <api>
      <GraphQL>
        <defaults>
          <security>
            <systemService>
              <!-- CLI expects this service -->
              <requireAuthentication>false</requireAuthentication>
              <requireApiKey>true</requireApiKey>
            </systemService>
          </security>
        </defaults>
      </GraphQL>
    </api>
  </sitecore>
</configuration>

This is used to patch the config in the \App_Config\Sitecore\Services.GraphQL\Sitecore.Services.GraphQL.config




Troubleshoot personalization on xm cloud

Here are the troubleshooting steps below that helped personalization to work. We checked the events analytics in the page builder but it was...