Troubleshooting: XDB Certificates on CD Server

It is very common that at some point your certificates expires and you need to renew your certificates. A common issues that I saw in projects is the following error:

The certificate was not found. Store: My, Location: LocalMachine, FindType: FindByThumbprint, FindValue: [YOUR-Thumprint-Value-Here], InvalidAllowed: False.
Source: Sitecore.Xdb.Common.Web

If you have a CM in one Server and CD server in another server. It is probably that you forgot to install the xconnect certificate in CD server.

You can run the following commands to validate if you have correctly installed the certificate for each server.

On CM Server run

Get-ChildItem  -Path Cert:\LocalMachine\MY | Where-Object {$_.Thumbprint -Match "[YOUR-Thumprint-Value-Here]"}

If you see a result then you can conclude that certificate is installed on CM server assuming that connect is installed in the same server.

Then you can check the same on CD server:

Get-ChildItem  -Path Cert:\LocalMachine\MY | Where-Object {$_.Thumbprint -Match "[YOUR-Thumprint-Value-Here]"}

If you noticed that you get no results, then you need to perform the following steps:

  1. Open Manage computer certificates in CM server.
  2. Go to Personal -> find the certificate that match your thumprint.
  3. Export Certificate

4. Move the file to the CD server

5. Install Certificate on Local Machine in Personal folder.

6. Grant Read access to the application app pool.

7. Recycle application pool and check your logs again.

Note: Be sure that thumbprint matches in CD server you can check the file ConnectionStrings.config to confirm that thumbprint is same as you certificate installed.

I hope that helps you to troubleshooting your certificates issues.

Read more

[Workaround] XM Cloud: Error building sample Next.js app

I started an XM Cloud project using Next.js as Rendering Host. I added some Graphql code, but when I want to run jss build I got an error similar to the next one.

Type error: Argument of type 'TypedDocumentNode<ConnectedDemoQueryQuery, Exact<{ datasource: string; contextItem: string; language: string; }>>' is not assignable to parameter of type 'string | DocumentNode'.
  Type 'TypedDocumentNode<ConnectedDemoQueryQuery, Exact<{ datasource: string; contextItem: string; language: string; }>>' is not assignable to type 'DocumentNode'.
    Types of property 'kind' are incompatible.
      Type '"Document"' is not assignable to type 'Kind.DOCUMENT'.


  • @sitecore-jss/sitecore-jss-nextjs: "^21.0.0"
  • @sitecore-jss/sitecore-jss-cli: "^21.0.0"
  • XM Cloud

After some research I found a workaround. I know this is not the best solution. But if someone else know how to fix this issue please, feel free to leave a comment.


In order to stop the type error, I wrap the Graphql call into a js file. index.js

 export async function myFunctionToExecuteQuery
.... some code here
 const result = await graphQLClient.request(MyQueryDocument, {
    myParam: myParam,

return result;

Then I added an index.d.ts to declare the types.

export declare async function myFunctionToExecuteQuery<TResult>(
  myParam: string
): Promise<TResult| null>;

With that workaround I can still declare the query result type, and also run jss build without any error.

As I mentioned, this is not the best solution, but I can build the Next.js application successfully.

Read more

Sitecore Single Sign-On: Federated Authentication With Azure AD

When you develop an enterprise website you might need to allow your visitors to login into your website to have a unique and personalized experience. Single Sign-On allows to your audience to enter credentials just one time instead of enter the password for each web application that your organization offers.

In the marketplace, there are many identity providers such as Google, Facebook, Microsoft, Github, etc. In enterprise environments you might have your own Azure Active Directory (Azure AD) which you store all your users information.

Sitecore provides a documentation which I found helpful to understand what needs to be configured in order to implement Federated Authentication for front-end login.

Sitecore Documentation:

In this blog post I will explain Federated Authentication with Azure AD using OpenID Connect (OIDC) which is an authentication protocol based on the OAuth2 protocol. For more details please read the following article:

Configure an Identity Provider

First step, you need to create a config file for example, in my Sitecore instance I have a Foundation.Accounts project, so I created a file Foundation.Accounts.SSO.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="">
    <federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">

Then inside federatedAuthentication we should add the following elements identityProvidersPerSites, identityProviders and propertyInitializer

identityProvidersPerSites add a MapEntry element which contains which sites the identity provider will be used. As I mentioned in this article, SSO will be used for website login.

In externalUserBuilder, I´m using a custom UserBuilder and IsPersistentUser is set to false. Because we don´t need to have unnecessary users in the CMS database. In other words, our users will be virtual users.

        <mapEntry name="ADMapEntry" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication" resolve="true">
          <sites hint="list">
          <identityProviders hint="list:AddIdentityProvider">
            <identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='AzureADIdentityProvider']" />
          <externalUserBuilder type="Foundation.Accounts.Services.AzureActiveDirectory.ADExternalUserBuilder, Foundation.Accounts" resolve="true">
  public class ADExternalUserBuilder : DefaultExternalUserBuilder
        public ADExternalUserBuilder(ApplicationUserFactory applicationUserFactory, IHashEncryption hashEncryption) : base(applicationUserFactory, hashEncryption) { }

        protected override string CreateUniqueUserName(UserManager<ApplicationUser> manager, ExternalLoginInfo externalLoginInfo)
            if (externalLoginInfo == null) return "nullUserInfo";

            if (string.IsNullOrWhiteSpace(externalLoginInfo.Email))
                var validUserName = externalLoginInfo.DefaultUserName;

                return $"{Constants.Domains.Extranet}\\{validUserName.Replace(" ", "")}";

            return $"{Constants.Domains.Extranet}\\{externalLoginInfo.Email.Replace(" ", "")}";

Next section identityProviders is important because here we need to specify how claims are transformed for Sitecore Login and Business requirements. Notice that domain is extranet because our users are not part of the Sitecore domain.

<identityProviders hint="list:AddIdentityProvider">
        <identityProvider id="AzureADIdentityProvider" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication" >
          <param desc="name">$(id)</param>
          <param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
          <caption>Go to login</caption>
          <transformations hint="list:AddTransformation">
            <transformation name="Idp Claim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />
            <transformation name="set id_token claim" type="Sitecore.Owin.Authentication.Services.SaveIdTokenInClaim, Sitecore.Owin.Authentication" />
            <transformation name="set role claim" type="Foundation.Accounts.Services.AzureActiveDirectory.SetRoleInClaim, Foundation.Accounts" />
            <transformation name="Name Identifier Claim" type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
              <sources hint="raw:AddSource">
                <claim name="" />
              <targets hint="raw:AddTarget">
                <claim name="" />

For Azure AD Identity Provider I found that those 3 transformations are required. I created a custom transformation to resolve the user’s role as SetRoleInClaim.

<transformation name="Idp Claim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />

<transformation name="set id_token claim" type="Sitecore.Owin.Authentication.Services.SaveIdTokenInClaim, Sitecore.Owin.Authentication" />

<transformation name="Name Identifier Claim" type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
              <sources hint="raw:AddSource">
                <claim name="" />
              <targets hint="raw:AddTarget">
                <claim name="" />

Finally the last part is to intialize User variables like Email, Name, Last Name in propertyInitializer element.

        <maps hint="list">
          <map name="email claim" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
            <data hint="raw:AddData">
              <!--claim name-->
              <source name="" />
              <!--property name-->
              <target name="Email" />
          <map name="Name claim" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
            <data hint="raw:AddData">
              <source name="" />
              <target name="Name" />

Integrate with the owin.IdentityProviders Pipeline.

Next, you must integrate the code into the owin.identityProviders pipeline.

        <processor type="Foundation.Accounts.Services.AzureActiveDirectory.AzureADIdentityProviderProcessor, Foundation.Accounts" resolve="true" />

Add code for the provider

 public class AzureADIdentityProviderProcessor : IdentityProvidersProcessor
        public AzureADIdentityProviderProcessor(FederatedAuthenticationConfiguration federatedAuthenticationConfiguration, ICookieManager cookieManager, BaseSettings settings) : base(federatedAuthenticationConfiguration, cookieManager, settings)

       protected override void ProcessCore(IdentityProvidersArgs args)
            Assert.ArgumentNotNull(args, nameof(args));

            var identityProvider = this.GetIdentityProvider();
            var authenticationType = this.GetAuthenticationType();
            var saveSigninToken = identityProvider.TriggerExternalSignOut;

            var targetHostName = GetTargetHostName();
            string aadInstance = "{0}/";
            string tenant = Settings.GetSetting("Foundation.Accounts.SSO.AD.Tenant");
            string clientId = Settings.GetSetting("Foundation.Accounts.SSO.AD.ClientId");
            string clientSecret = Settings.GetSetting("Foundation.Accounts.SSO.AD.ClientSecret");
            string postLogoutRedirectURI = $"{targetHostName}{Settings.GetSetting("Foundation.Accounts.SSO.AD.PostLogoutRedirectURI")}";
            string redirectURI = $"{targetHostName}{Settings.GetSetting("Foundation.Accounts.SSO.AD.RedirectURI")}";
            string scope = Settings.GetSetting("Foundation.Accounts.SSO.AD.Scope");

            string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);

            //Set the authentication type to use cookies
            args.App.UseCookieAuthentication(new CookieAuthenticationOptions
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,

            args.App.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
                Caption = identityProvider.Caption,
                AuthenticationType = authenticationType,
                AuthenticationMode = AuthenticationMode.Passive,
                ClientId = clientId,
                ClientSecret = clientSecret,
                Authority = authority,
                PostLogoutRedirectUri = postLogoutRedirectURI,
                RedirectUri = redirectURI,
                ResponseType = OpenIdConnectResponseType.CodeIdToken,
                UseTokenLifetime = false,
                CookieManager = this.CookieManager,
                Scope = scope,
                Notifications = new OpenIdConnectAuthenticationNotifications
                    SecurityTokenValidated = notification =>
                        var identity = notification.AuthenticationTicket.Identity;
                        foreach (var claimTransformationService in identityProvider.Transformations)
                                new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));


                        notification.AuthenticationTicket = new AuthenticationTicket(identity, notification.AuthenticationTicket.Properties);

                        return Task.FromResult(0);
                    RedirectToIdentityProvider = message =>
                        // format redirect URI so Sitecore cleans up after itself
                        var revokeProperties = message.OwinContext.Authentication.AuthenticationResponseRevoke?.Properties?.Dictionary;
                        if (revokeProperties != null && revokeProperties.ContainsKey("nonce"))
                            var uri = new Uri(message.ProtocolMessage.PostLogoutRedirectUri);
                            var host = uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped);
                            var path = "/" + uri.GetComponents(UriComponents.Path, UriFormat.Unescaped);
                            var nonce = revokeProperties["nonce"];

                            // for single sign-out, Sitecore expects the URI used below with the nonce in the query string
                            // this URI was found in Sitecore.Owin.Authentication.Pipelines.Initialize.HandlePostLogoutUrl
                            message.ProtocolMessage.PostLogoutRedirectUri = $"{host}/identity/postexternallogout?ReturnUrl={path}&nonce={nonce}";

                        return Task.FromResult(0);

                TokenValidationParameters =
                    SaveSigninToken = saveSigninToken


        protected override string IdentityProviderName => "AzureADIdentityProvider";

This part is when I had a lot of issues, for me it is important to understand the settings. You can set up an enterprise application for Azure AD, then you can provide to the webapp the following fields: Tenant, Client Id and Client Secret.

Also is very important that you set up correctly the Redirect URL in your Azure AD Application, for example, in our case:


Probably for .Net experts is obviously that redirect url will be something like targethostname + /identity/externallogincallback. However I spent a lot of time trying to figured out which is the callback url. Hopefully this article saves your time if this is your first ASP.NET Identity implementation.

Foundation.Accounts.SSO.AD.TenantAzure Tenant
Foundation.Accounts.SSO.AD.ClientIdAzure Application Client Id
Foundation.Accounts.SSO.AD.ClientSecretAzure Application Client Secret
Foundation.Accounts.SSO.AD.Scopeopenid profile roles

Generate sign-in links:

Finally, I created a AuthManager class in order to retrieved the sign-in link, where I can place it for example, in the header component.

 public SignInUrlInfo GetLoginUrl(string redirectUrl = "/")
            var corePipelineManager =
            var args = new GetSignInUrlInfoArgs(site: "website", returnUrl: redirectUrl);
            GetSignInUrlInfoPipeline.Run(corePipelineManager, args);
            var result = args.Result.FirstOrDefault();
            return result;


To quickly recap, It is necessary to create a config file to place federatedAuthentication configurations and a processor in our case AzureADIdentityProviderProcessor to configure owin middleware. Then, you need to override ProcessCore method to add args.App.UseOpenIdConnectAuthentication configuration in IdentityProvidersProcessor implementation. Finally generate sign-in links and you are all set. It sounds easy but for me it took some days of research and trying to understand what values I need to include in the config files. I hope with this example you can save a lot of time and it could be helpful to understand this Sitecore feature.

Read more

Sitecore Geo IP Services (SC 10.2) Updated

Many businesses require to implements GEO IP Services. Business Rules differ between locations. As Developers, Sitecore makes our lives easier by providing a Service that we can use to obtain the location of the website’s visitor.

The IP Geolocation provides information like country, state, city, and every visitor’s registered company name as well. Based on geodata, we can build modules that interact with our visitors and provide accurate information depending on where they are.

Installation and Configuration

Here you will find the official link to activate and set up the Sitecore IP Geolocation: Set up Sitecore IP Geolocation

In your Siecore Solution ensure you add the following Nuget Packages:

  • Sitecore.Kernel
  • Sitecore.Analytics


Sometimes when you work with lower environments or your local environment Geo IP is not available. I developed the following simple class to get the visitor’s country and city. We can add the next file to setup a city and country code when Sitecore IP Geolocation is not available for your local. I used Sitecore 10.2.

<configuration xmlns:patch="" xmlns:set="" xmlns:env="">
    <settings env:require="Local">
      <setting name="Dev.IPGeolocation.IsDevMode" value="true"/>
      <setting name="Dev.IPGeolocation.City" value="Boston"/>
      <setting name="Dev.IPGeolocation.CountryCode" value="US"/>

The next class contains a method GetUserGeolocation to get user location information.

Noticed IGeoIPManager is injected on the constructor class.

 public class GeolocationService : IGeolocationService
        private readonly IGeoIpManager _geoIpManager;

        public GeolocationService(IGeoIpManager geoIpManager)
            _geoIpManager = geoIpManager;
        /// <summary>
        /// Get User IP form Request Context.
        /// </summary>
        /// <returns>(string) IP Address</returns>
        private static string GetUserIP()
            var ip = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null
                      && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != "")
                ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
                : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            if (ip.Contains(","))
                ip = ip.Split(',').First().Trim();

            return ip.Trim();

        /// <summary>
        ///   Fetch country from Sitecore IP Geolocation Service check 
        ///   setup at
        /// </summary>
        /// <returns></returns>
        public GeoData GetUserGeolocation()
            GeoData geoData;
            bool IsDevEnviroment = Settings.GetBoolSetting("Dev.IPGeolocation.IsDevMode", false);
            if (!IsDevEnviroment)
                    var result = _geoIpManager.GetGeoIpData(GetUserIP());
                    if (result.Status == GeoIpFetchDataStatus.Fetched &&
                        result.WhoIsInformation != null)
                        geoData = new GeoData()
                            City = result.WhoIsInformation.City,
                            CountryCode = result.WhoIsInformation.Country
                        throw new Exception("GeoIP whoIsInformation is null");
                catch (Exception e)
                    Log.Error("Error Getting IPAddress", e, typeof(GeolocationService));
                    if (Tracker.Current != null && Tracker.Current.Interaction != null && Tracker.Current.Interaction.GeoData != null)
                        geoData = new GeoData()
                            City = Tracker.Current.Interaction?.GeoData?.City,
                            CountryCode = Tracker.Current.Interaction?.GeoData?.Country

                        Log.Error("IPGeolocation: There is an issue with IP Geolocation Service", typeof(GeolocationService));
                        geoData = new GeoData()
                            City = null,
                            CountryCode = Settings.GetSetting("LocationEngine.IPGeolocation.CountryCode")

                Log.Info("IPGeolocation: Dev Mode is enabled", typeof(GeolocationService));
                geoData = new GeoData()
                    City = Settings.GetSetting("Dev.IPGeolocation.City"),
                    CountryCode = Settings.GetSetting("Dev.IPGeolocation.CountryCode")
            Log.Info($"IPGeolocation: Country Code is {geoData.CountryCode}", typeof(GeolocationService));
            return geoData;

Finally, GeoData is a model class that contains the location information.

 public class GeoData
        public string CountryCode { get; set; }
        public string City { get; set; }

I hope this information will be usefully when you work with Sitecore Geo IP Services.

Read more

Sitecore Forms: ReCaptcha Enterprise Support

Sitecore is a powerful DXP it is desiged for enterprise-level websites. As Marketers you would need to set up your forms and Sitecore provides a solution out-of-the-box to easily create your own forms by drag and drop your form controls like: Text, Buttons, Inputs and customize submit actions. However, your site is vulnerable to bot attacks and some companies prefer to use Google’s reCaptcha to prevent bot traffict to their websites.

I’ve been working on a Sitecore forms module, which support the ReCaptcha Enterprise version within Sitecore Forms. If you want to contribute in the module development please refer the following Github Repo:


To make it easily to install you need to add a Nuget Package in your Webiste project.

Install-Package SitecoreModules.Foundation.Forms


To setup the module it is required to add Google ReCaptcha Keys Refer to this google docs:

Once you installed the nuget package. The installation will add a config file: \Website\App_Config\Include\Foundation\SitecoreModules.Foundation.Forms.ReCaptchaEnterprise.nonprod.config.example

You need to clone it and change it accordingly your environment.

Foundation.Forms.ReCaptchaEnterprise.PublicKeyV3[Public – V3]
Foundation.Forms.ReCaptchaEnterprise.PublicKeyV2[Public – V2]
Foundation.Forms.ReCaptchaEnterprise.ApiKey[Api Key] – This is used for Server Side Validation
Foundation.Forms.ReCaptchaEnterprise.ScoreDefault to 0.5.

Finally, you need to ensure that forms.recaptcha.js is added on standard values to load the js functionality that is required to work, as the following screenshot.


This module is easy to use. All you need to do is Drag and Drop the control named: “ReCaptcha Enterprise” which is located under Security section.

Then you can configure the module by click on it, then select the mode, it could be:

  • Invisible: Provides a better user experience, reCaptcha v3 is invisible for webiste visitors.
  • Checkbox: Use a challenge if Google detects a bot behaviour.

Finally, save your form. I hope you find this modue useful on your projects.

Read more

Sitecore Hackathon 2022

I’m very happy to participate in Sitecore Hackathon 2022!. I participated with my teammate Daniel Pastor in the team Send Pizza and Coffee and I’m proud of what we archived. This year there were 3 topics for Sitecore Hackathon ideation.

  • Build and e-commerce Minimum Viable Product to sell community t-shirts
  • Extend the Sitecore Command Line (CLI) Plugin
  • Best addition to the Sitecore MVP Site.

Additionally we were thinking in a problematic that business have to facing during the COVID-19. One of the coolest rewards after becoming a Sitecore MVP has always been the Sitecore Swag we receive. However, due to the pandemic and changes from year to year, the delivery process can be a little confusing. We decided to make a “Sitecore MVP Swag tracker” page with some modules where the user could track the delivery status of their care package.

The value of real-time systems came into focus in 2020 as companies responded to the disruptions due to COVID-19. Nowadays, people want to have information at hand efficiently, this creates confidence in technological users, the information must be in real time, the actual generation want the information right now.

This module will display the status of the delivery in real time from an external push service which could come from a mobile app from the delivery service.

Our proposal was focused on the user experience, they could know where the MVP swag package is in the delivery process. Our technology is based in web-sockets using Pusher as key platform to our solution succeed.

Web-sockets provides a channel to broadcast to the users the information about their package tracking with the following events:

  • On Track: Send the deliver man location in real-time, the idea is that each delivery man have a mobile application that sends the geo location.
  • In Order Completed: This event notify to the website’s user that the order is completed and delivered at the door.

Finally, we provide a Sitecore Form which could be use in case that something wrong happens with the delivery, and the people in charge could get in contact.

You’ll find more information about our project in the following link:

Read more

Create your first JSS module with NextJS – Part 1

In Article I’ll show you how to create a module in Sitecore using JSS and NextJS. For who is not familiar with this topics. I explain a little bit in my previous blogpost.

Prepare your environment

Before create a new component, you need to connect your Sitecore website with JSS front end project. The easy solution is using Docker and create a new project based on sitecore.nextjs.gettingstarted template.

If you don’t want to use docker you need to ensure that you have installed Sitecore Headless Services (formally the JSS Server Components).

Create a Json Rendering

Json Rendering let you create a rendering which connects to your React Module. First, you need to create your Json Rendering for this example, I’ll create a "Blue Box" component.

Template: /sitecore/templates/Foundation/JavaScript Services/Json Rendering

In experience editor, to allow content authors the ability to select the new component you can added in the placeholder settings as a normal component in Sitecore.

In your Front End Solution (NextJS Solution), you can add a new file /src/components/BlueBox.tsx, we can create the component as React Functional Component.

To import assets or styles you can use import statement and create your modular style file like [Module-Name].module.css.

In order to support inline-editing through experience editor you can use the Text component which is part of '@sitecore-jss/sitecore-jss-react' library.

Do not forget to start your Front-End server with jss start.

If you want to ensure that Data Source is not empty you can use the withDataSourceCheck() hook

Finally, you can add the rendering in your JSS Application Route Page and you are ready to go. Stay tuned and I will enter in details using Placeholders in JSS Application.

Read more

Getting Started Sitecore JSS with NextJS

JAMStack is a modern way to build website and apps that delivers better performance. JSS enables Sitecore to be a powerful Headless CMS and Next.js gives you the best developer experience to build a hybrid static & server rendering.

In this article, I’ll talk about how to get started on Sitecore JSS and Next.js. For this experiment, I followed the instructions provided by Sitecore in the following link:

Walkthrough: Setting up a development environment with the Sitecore Containers template for Next.js

Once you follow the steps you’ll be able to log in to Sitecore CM and browse the website.

During the initial setup, I found some issues related to Docker configuration and I found this article really useful:

Sitecore 10 on docker – common issues – Error cotidianam (

If you have the latest Docker Desktop, please disable Use Docker Compose V2.

In order to start up JSS project you should navigate to src\rendering folder which contains the NextJS project.

You can run the following command and then you are ready to go.

jss start

I found Docker containers as an easy way to set up a Sitecore environment you don’t need to worry about to install Solr, create the certificates, etc.

Next.js is the future of web development, it is the most famous framework to build super fast and SEO-efficient JAMStack websites with the following important benefits for me:

  • Faster time to market – make and build an MVP (Minimun Viable Product) is much faster.
  • Performance – NextJS generates an static website that runs on NodeJS. Improved page load speed which means higher conversion rate.
  • Live Reload – Working with those frameworks, I love that development is fast you don’t need to wait to compile, it is a live-editing experience.
  • Fully omnichannel– you don’t need to worried about to build API’s for website or mobile applications. You can reuse some React components for your mobile application if you are using web-based technologies.

In future blog posts, I could prepare tutorials about Sitecore module development. Stay tuned!

Read more

Sitecore CDP Decision Models

Sitecore CDP is a Customer Data Platform, which means that we can store data related to our customers.

This valuable data is very useful for analysis and allows you to make assertive marketing decisions. Sitecore CDP allows you to create Decision Tables or even Decision Template which are programmable.

Here we can see some components added to the Decision Model Canvas, you can find more info

Basically best practices mentioned to begin from bottom to top that makes easily to read. Based on that I could say in this example we have three sections.

  • Model Inputs: Here we can add Input Data like guest data or connect to a Data System API’s.
  • Transform and Extract Data: We can add programable boxes to add some logic to validate data, extract fields like GetPropensity, or Order Related Data like HasOrders from the Guest Object.
  • Decision Table, Knowledge Source: At the very top we have the Decision Table.

Decision Table Overview

Client groups according revenue. Adapted from: Esteban-Talaya y Mondéjar-Jiménez (2017). Kotler and Armstrong (2018).

Here we can implement some Marketing Strategies for example if we have a “Butterfly client” we can give them an offer. or if we have a client which is a “unfamiliar” we can give them a lower offer or even decide to do not invest on them.

Our decision table has inputs and outputs:

  • Input: Propensity, Has Orders.
  • Output: Offers

This presented Decision table is a basic example how you can make automated decisions, and how powerful is this platform for your business. It helps you to maintain a good relationship with your clients.

Read more

Sitecore CDP Register Events

Sitecore CDP is a great platform that allows you to register Customer Data for analysis and build Decision Models to create Customer Experiences.

As a developer our first steps are to capture data, it could be some integrations like visiting a page. In this article I will show you how to send events to Sitecore CDP.

Step 1. Create your Point of Sale

Click on System Settings > Point of Sale then click on Create

Fill the form:

  • Name your Point Of Sale: Your Point of Sale Name.
  • Market: Information about the market.
  • Brand: You can fill with your brand.
  • Language: Target language
  • Timeout (in minutes) : Once an user is inactive to close the browser there is a timeout setting that is useful to understand when the user abandon the session.

Step 2: Setup Javascript Library in your Website

var _boxeverq = _boxeverq || [];

// Define the Boxever settings 
var _boxever_settings = {
  client_key: '[YOUR_CLIENT_KEY]', 
  target: '[YOUR_API_VERSION]', 
  cookie_domain: '[YOUR_WEBSITE_DOMAIN]', 
  web_flow_target:  "https://[YOUR_WEBFLOW_TARGET]",
  pointOfSale: "[YOUR_POINT_OF_SALE]"

(function() {
  var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true;  
  s.src = '[CDN]/boxever-1.4.1.min.js';
  var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x);

Add this script into your website and this will inject Sitecore CDP JavaScript Library.

Step 3: Add Event in your website page.

// Place an anonymous function in the Boxever queue
_boxeverq.push(function() {
  var viewEvent = {
    browser_id: Boxever.getID(),
    channel: "WEB",
    type: "VIEW",
    language: "EN",
    currency: "USD",
    page: "/", // Your page path
    pos: "[YOUR_POINT_OF_SALE]"
   //Add UTM params
    viewEvent = Boxever.addUTMParams(viewEvent);
  // Invoke event create
  // (<event msg>, <callback function>, <format>)
  Boxever.eventCreate(viewEvent, function(data) {}, "json");

Step 4: Visit your website

Finally if you visit your website and then go to Sitecore CDP Platform you will see a new event registered for your target user.

Here you can find more information about how to customize an event:–data-model-2-1/send-a-custom-event-to-sitecore-cdp.html

I hope this article will be helpful to start your Sitecore CDP implementations.

Read more