Tag: Sitecore

Sitecore Webhook – Authorise event processing app with Auth0 by Okta

In the previous posts we saw how to setup the local environment or XM Cloud to debug Webhook handler event processing app i.e. web api using ngrok in this blog post and also checked how to configure the authorization using Auth0 by OKTA in this blog post using OAuth2ClientCredentialsGrant authorization.

Continuation to this we will now extend the Web Api to authorize the endpoint called from the Sitecore Webhook handler.

We already configured Auth0 to have API and Machine-to-Machine application we will configure this in Web API and setup the authorization.

The authorization in Web API will be done to check of the request cam from the valid domain i.e. dev-your_dev_id.uk.auth0.com and valid audience i.e. https://sc-xmcloud which should be part of the token.

Lets configure Web API .env file. Create a .env file and add the following-

CLIENT_ORIGIN_URL can aslo be your XM Cloud instance.

"CLIENT_ORIGIN_URL": "https://xmcloudcmsdfsdfsd.localhost",
"AUTH0_AUDIENCE": "https://hello-world.example.com",
"AUTH0_DOMAIN": "dev-your_dev_id.uk.auth0.com"

Setup the authentication –

    public static void AddAppAuth(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                var audience =
                    configuration.GetValue<string>("AUTH0_AUDIENCE");

                options.Authority =
                    $"https://{configuration.GetValue<string>("AUTH0_DOMAIN")}/";
                options.Audience = audience;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = true,
                    ValidateIssuerSigningKey = true
                };
            });
    }

Create a builder to add Authentication service-

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAppAuth(builder.Configuration);

Decorate the controller wiht Authorize attribute-

The endpoint for local is – https://localhost:7024/api/Item/handler

Setup ngrok to listen to this endpoint

ngrok http --host-header="localhost:7024" https://localhost:7024

ngrok listening now listening on this URL-

https://8a18b6e7e0c1.ngrok.app

Configure the ngrok endpoint in Sitecore Webhook handler

OAuth2ClientCredentialsGrant authorization looks like this-

Webhook Event

Webhook will fire when the Home item or its descendants are saved

Once saved local instance should Authorize and start executing the action method

We can also see the token and the request successfully processed.

Negative testing-

If the audience and the domain doesn’t match should not execute the action method.

I changed the same in .env file.

CLIENT_ORIGIN_URL=https://xmcloudcmxmcloudcm.localhost
AUTH0_AUDIENCE=https://sc-xmcloud-fake-audience
AUTH0_DOMAIN=dev-fakedomain.uk.auth0.com

Sitecore logs also show the request was failed and this due to incorrect domain and audience configured in Web Api-

3896 16:00:20 ERROR Webhooks: Request is not successfull https://8a18b6e7e0c1.ngrok.app/api/Item/handler. Response code was Unauthorized

ngrok helps debug the event processing app to check the authorization.

Hope this helps.

Loading

Configure Sitecore XM Cloud webhook for Authorization using Auth0 by Okta

In previous blog post we saw how to create a Webhook and debug, inspect and test the Webhook handler using ngrok.

Continuation to the previous blog post lets see how to configure the Webhook to use Client Credential grant and secure the Webhook handler in this blog post with Auth0 by Okta.

Register and Login to Auth0

I used free (development) plan to register to Auth0 if you don’t have the account already. This should create a dev id based on the region you selected and should look like this – dev-your_dev_id

https://auth0.com/pricing

Create a API

Navigate to Applications ==> APIs and Create a new API

Provide the name and identifier-

Once created note down the Identifier-

You will also notice that a new Machine To Machine (M2M) Application is created and is mapped and authorized in this API-

Navigate to Applications ==> Applications to see the M2M application-

Note the Domain, Client ID and Client Secret in this application, as this will be required when configuring the Autjorization is Sitecore.

Generate token using postman

Lets test the API and application ocnfigured correctly by generating token using postman-

You will following from above-

Domain Name- dev-your_dev_id.uk.auth0.com

client_id – cC6kPo4AJvY2spdWqZQVuEOjWTMfUZIo

client_secret- wXmuRusYhjJOF12RljeJ5WiJDL6vXnUKuUJO6961CeKG6xafRJpEuBZh_FAbl617

identifier/audience – https://sc-xmcloud

Post request to generate token – https://dev-your_dev_id.uk.auth0.com/oauth/token

Create a Authorization in XM CLoud-

Craee a new OAuth2ClientCredentialsGrant in Authorization folder. This should be available in following path in Sitecore-

/sitecore/system/Settings/Webhooks/Authorizations

Setup the OAuth2ClientCredentialsGrant

Setup the Authority URL, Client ID, Client Secret, Header Prefix and OptionalParameter as follows- This values we noted above whilst creating a API and Application in Auth0.

Setup Webhook Handler

Create a new Webhook handler and provide the newly created authorization –

For testing purpose I have set the

Event – item_saved, Rule – When the Home Item or its descendants are changed

Url – https://webhook.site/a4624c9e-7dda……

Webhook.site should listen to any calls from Sitecore for testing purpose. This can be your Webhook handler app.

Authorization – Select the newly created authorization to Auth0 which create a token

Serialization Type- JSON

Fire a webhook

Save a home or its descendants to fire a webhook

On save it should fire a webhook which can be seen in webhook.site which should also pass the newly created token.

We can see the token was successfully created and a webhook was fired on saving a Home item as configured in Auntorization and Webhook Handler.

Errors-

If the request to Auth0 fails you should be able to see the same in logs- something like this due to configuration-

4016 12:37:00 INFO  AUDIT (sitecore\sandeep@): Save item: master:/sitecore/content/scxmcloud/sxastarter/Home, language: en, version: 1, id: {0B5C4B64-2A85-4F98-B928-0E0B40C68AEA}
1928 12:37:01 ERROR Webhooks: Token request failed with error: Unauthorized

I have tried this in my local instance but the same can also be done in XM Cloud.

Next we will create a Web Api which should be able to validate the token and executes any custom implementation. This will be in next blog.

Hope this helps.

Loading

Debug, inspect, test and run the request triggered by XM Cloud Webhook using ngrok

Sitecore Webhooks allows to receive real-time notification about events to the web api that can handle these requests.

In this blog post will see how to debug such handlers in local environment, events triggered by XM Cloud or from the local instance using ngrok.

What is ngrok?

ngrok allows to connect external netwroks in a consistent, secure and repeatable manner without changing any network configurations.

Pre-requisite-

Sitecore Instance-

Either have a local Sitecore instance or XM Cloud instance. See how to setup local XM Cloud instance

Create a Webhook Handler(Web Api)

For this blog post I have created a simple Web Api with a endpoint /api/item/handler which receives POST requests with a Item payload and just return OK or Badrequest response.

We are going to create a Webhook with item:saved event in Sitecore.

using Microsoft.AspNetCore.Mvc;
using Sitecore.Webhook.Handler.Models;

namespace Sitecore.Webhook.Handler.Controllers;

[ApiController]
[Route("api/[controller]")]
public class ItemController : Controller
{
    [HttpPost("handler")]
    public async Task<IActionResult> ItemHandler(ItemPayload? payLoad, 
        CancellationToken cancellationToken)
    {
        if (payLoad == null)
        {
            return BadRequest();
        }

        // Process the item handler
        return Ok();
    }
}

When I run this from VS the endpoint listens on the port 7024 for me.

Host Name:- https://localhost:7024/

Endpoint: /api/item/handler

Install ngrok on dev machine

Use choclatey to install ngrok on local machine

choco install ngrok

Check the ngrok once installed

ngrok -v

IMP– Antivirus might block executing the ngrok. For me I had to turn off the real time scan. Do this at your own risk based on your antivirus software this might be different.

Execute ngrok http command to listen to the api endpoint-

ngrok http --host-header="localhost:7024" https://localhost:7024

In this example https://1a319cf7d867.ngrok.app should forward request’s to https://localhost:7024 where the Web Api is running on my local machine.

Also note the Web Interface – http://127.0.0.1:4040/

Create a Webhook Handler

Navigate to /sitecore/system/Webhooks and create a webhook handler. In this case will create a item:saved handler.

In the newly created handler select the event the webhook should trigger and call the endpoint created by nrgok (i.e. web api)

Setup the rule – “where the item is the Home item or onle of its descendants”

Means Home or any of its child items when saved this event will be triggered.

Also setup the Url the webhook should call when this event fires.

IMP – Ensure the handler is enabled or it won’t fire the event.

Save the Home or any of its child to fire the event

I changed a field in Home item and Saved the item-

Ensure your Web Api solution is running in debug mode.

And now you should be able to debug, inspect and test the handler. This was done in local Sitecore instance but can also be done in XM Cloud.

ngrok helps to forward the requests to the localy hosted web api running in debug mode.

Now you can handle what should happen on item:saved event.

XM Cloud

I did the same process in XM Cloud-

Updated the Home item and Saved. Note the item id

The event is fired and web api in my local machine is called-

Also the ngrok also shows the calls it is listening.

Web interface should also show the request and payload details-

Hope this helps debuging your Webhook requests fired from Sitecore local or XM Cloud.

If you want to see the webhook payload and perform further actions, like sending mails etc there are online tools availabl e-

https://webhook.site/

https://zapier.com/

https://hookdeck.com/

https://ifttt.com/

Hope this helps.

Loading

XM Cloud local environment – Fork Foundation template

This is first part for setting up the XM Cloud local environment. As a part of this we will first fork the foundation template from reporsitory. This will help you setup sitecore local instance and head your own copy without affecting the Foundation head from Sitecore labs. Note this repo keeps updating and the steps below may differ after any updates.

This post refers following documentation is you want to do your own way-

https://doc.sitecore.com/xmc/en/developers/xm-cloud/walkthrough–setting-up-your-full-stack-xm-cloud-local-development-environment.html

Fork the XM Cloud Foundation Template source for initial deployment from following git repo-

To fork the same you need to have first have git account.

Follow the steps to fork the source code- https://github.com/sitecorelabs/xmcloud-foundation-head

Create a new fork –

Provide a valid repo name and create fork-

You should now a have a main branch forked in your account-

Sitecore Send Custom Automation – Email when user subscribes to specific mailing list

If you want to send welcome email to the user subscribed to the specific mailing list in this example to a Newsletter, you can do so using Sitecore Send Automation.

In this case there is no OOTB automation available. Will crate a custom automation instead

To see how to setup a Subscribe abd Unsubscribe using javascript see this blog

Setting up Custom Autmation to Thanks user for subscribing to the Newsletter

Navigate to Automation and New –> Custom automation

Setting up Automation for welcome email-

This is avaiable in automation recipe-

Navigate to Automation and New –> From recipe

Update title and description of automation-

Select the trigger-

Choose the List Engagement option – When someone subscribes to a specific list

In this case I am choosing the Newsletter Email List- created in my other blog

This should update the automation-

Next add the condition or control step

For this example will choose – Wait a specific time interval-

So after the user subscribes to Newsletter the wokflow will wait for 1 minute to perform further action.

Select Send mail campaign action-

Fill in the appropriate fields and create action-

Automation Worflow should look like this-

Imp- do not forget to activate the automation workflow.

On subscribing to newsletter-

You should be able to see the user added to the Newsletter mailing list-

After a minute you should be able to see custom automation is triggered-

Result- Email been sent after subscription-

You can also choose the exisitng recipe but this has the trigger to send mail if the user subscribes to any list.

Choose Welcome email sequence option-

This should ne now available in Automation Workflows in an Incomplet state-

Should show up with the option to setup the Automation Workflow-

Might see mulitple such steps- update as per your requirements

Click on the Trigger – When someone subscribes to any list as highlighted

Loading

Siecore Send – Setup re-direction to a custom webpage after unsubscription

To setup subscription and un-subscription see this blog

In this case I am setting up the Newsletter mailing list if user un-subscribed redirects to the custom page.

Navigate to the mailing list to setup the unsubscription redirect page-

Select Set your settings option

Enter the Redirect page URL –

When the user unsubscribes to the email list, it will be re-drected to your custom page.

When the user unsubscribes to the mailing list-

Will be redirected to the configured custom page instead of standard Sitecore page.

Loading

Gracefully handle user subscription using Sitecore Send

In this blog will walk you through on implementing subscribing and ubsubscribing user from the mail list using Sitecore Send

Use hostname- https://api.sitecoresend.io/v3

Subscribing a user to a mailing list

Api endpoint to subscribe a user to a mailing list

{hostname}/subscribers/{MailingListID}/subscribe.{Format}?apikey={apikey}

Subscribe Code

function SubscribeNewsletter(){

              let email = document.getElementById("newsletteremail");
              console.log(email)

              if (email.value == "") {
                alert("Ensure you input a value in both fields!");
              } else {
                // perform operation with form input
                
                var request = new XMLHttpRequest();
                request.open('POST', 'https://api.sitecoresend.io/v3/subscribers/{maillist}/subscribe.json?apikey={apikey}');
                request.setRequestHeader('Content-Type', 'application/json');
                request.setRequestHeader('Accept', 'application/json');
                request.onreadystatechange = function () {
                  if (this.readyState === 4) {
                    console.log('Status:', this.status);
                    console.log('Headers:', this.getAllResponseHeaders());
                    console.log('Body:', this.responseText);
                  }
                };
                var body = {
                  'Name': 'Sandeep Pote',
                  'Email': email.value,
                  'HasExternalDoubleOptIn': false
                };
                request.send(JSON.stringify(body));
                email.value = "";
                alert("User subscribed to newsletter")
              }
            };

Unsubscribe a user from a mailing list

Api endpoint to un-subscribe a user to a mailing list

{hostname}/subscribers/{MailingListID}/unsubscribe.{Format}?apikey={apikey}

Unsubscribe Code-

function UnSubscribeNewsletter(){

              let email = document.getElementById("optout-newsletteremail");
              console.log(email)

              if (email.value == "") {
                alert("Ensure you input a value in both fields!");
              } else {
                // perform operation with form input
                
                var request = new XMLHttpRequest();
                request.open('POST', 'https://api.sitecoresend.io/v3/subscribers/{maillist}/unsubscribe.json?apikey={apikey}');
                request.setRequestHeader('Content-Type', 'application/json');
                request.setRequestHeader('Accept', 'application/json');
                request.onreadystatechange = function () {
                  if (this.readyState === 4) {
                    console.log('Status:', this.status);
                    console.log('Headers:', this.getAllResponseHeaders());
                    console.log('Body:', this.responseText);
                  }
                };
                var body = {
                    'Email': email.value,                  
                };
                request.send(JSON.stringify(body));
                email.value = "";
                alert("User subscribed to newsletter")
              }
              };

Looks simple, but you might see when the user un-subscribed from a mailing list the user is never sent a mail from other mailing list or any other transactional mail.

Set user to unsubscribe from a specific mailing list

To allow only to unsubscribe from the a specific mailing list update a Unsubscribe setting-

For this goto Settings –> Set your account settings in Sitecore Send and check the Unsubscribe settings

Select option- When unsubscribing users from a list send to them from other mailing lists

Now the user will be only unsubscribed from the specific mailing list and sending mails from the Other mailing list of capaign should be possible.

This setting is very important whilst working with Sitecore send.

Reference-

https://doc.sitecore.com/send/en/developers/api-documentation/add-a-new-subscriber.html

https://doc.sitecore.com/send/en/developers/api-documentation/unsubscribe-a-subscriber-from-a-mailing-list.html

Loading

Sitecore CDP – Abandon cart with force close event

You can force close event to test Abandon Cart. This works only in non-prod environments.

Assumption- An identified guest which is active and has added products in cart.

If you are corectly tracking you should see in the timeline Session and event a Product been added.

So whilst developing if you want to force close this session, since you might not want to wait for 20 minutes for session to expire or whatever time is set to expire the session, you can force close the session to see or perform the next steps if the cart is been abandoned.

The force close event can be triggered by providing message type as FORCE_CLOSE in the payload.

Send the payload to this endpoint. For more details on what should be the apiEndpoint and client key see this blog

https://{{apiEndpoint}}/{{apiVersion}}/event/create.json?client_key={{CLIENT_KEY}}&message={{message}}

var browser_id = pm.environment.get("browserId") -- browser id
var pointOfSale = pm.environment.get("PointOfSale") -- point of sale

var message = {    
    "channel": "WEB",
    "type": "FORCE_CLOSE",
    "language": "EN",
    "currency": "GBP",
    "page": "home page",
    "pos": pointOfSale,
    "browser_id": browser_id
}

postman.setEnvironmentVariable("message", JSON.stringify(message));

Since the session is now closed we can see the Abandoned Revenue. Further reminder mails can be sent to user to complete the purchase on the abandoned cart.

Hope this helps.

Loading

Sitecore CDP – Upload guest data

Prepare guest data file to upload

Prepare Json file

Take a sample guest data from here

Sample data guest looks like this-

{
   "ref":"b4b92667-54e9-444f-8f64-11672fe9843a",
   "schema":"guest",
   "mode":"upsert",
   "value":{
      "guestType":"customer",
      "firstSeen":"2010-03-07T16:15:11.000Z",
      "lastSeen":"2012-08-23T16:17:16.000Z",
      "firstName": "Eager",
      "lastName": "Benz",
      "email": "eager.benz@malify.com",
      "extensions":[
         {
            "name":"ext",
            "key":"default",
            "loyaltytier":"level2",
            "rewardBalance":"50125"            
         }
      ]
   }
}
{
   "ref":"0cc6c80b-0b19-446f-9e14-579f75a96c4a",
   "schema":"guest",
   "mode":"upsert",
   "value":{
      "guestType":"customer",
      "firstSeen":"2010-03-07T16:15:11.000Z",
      "lastSeen":"2012-08-23T16:17:16.000Z",
      "firstName": "Goofy",
      "lastName": "Trovalds",
      "email": "goofy.trovalds@malify.com",
      "extensions":[
         {
            "name":"ext",
            "key":"default",
            "loyaltytier":"level3",
            "rewardBalance":"50130"            
         }
      ]
   }
}

Load the data in json file. Note that the above is a single row in a json and repeat the rows to upload multiple guets. This is not a json formatted file and should not have “,” to seperate rows as normally json file has. Highlighted email is important to identify the customer and add/update the extended data. This depends on the rule setup for your environment to identify the customer.

gzip the json file to upload

Example-

tar -czvf guest-upload.gz .\guest-upload.json

Generate MD5 File Checksum

Upload the gzip file to generate the check sum on this url –

https://emn178.github.io/online-tools/md5_checksum.html

Prepare Pre-signed Request

Create a new guid for the below batch upload. This guid will be used to know the status of the batch upload.

https://api.boxever.com/v2/batches/<<your guid>>

Request body –

{
    "checksum": "aaab5899b405bc3cb1d9b*******",
    "size": 412
}

Setup the Basic Auth before sending the request-

Request after setting up Authentication and body-

Response-

location – where the file needs to be uploaded. Will see this is next request where we actually upload file.

expiry – date time until the location to upload file is valid

The response should be saved in environment with uploadURL and batchRef variable-

Upload file

Upload URL request should contain the URL received from the pre-signed request-

Set the headers-

x-amz-server-side-encryption – AES256

Content-Md5 – <<Hex to Base checksum value>>

Content-Md5 is the Hex to Base64 converted value of checksum

Use this url to convert to base64-

https://base64.guru/converter/encode/hex

Request Headers should look like this-

The request signature we calculated does not match the signature you provided. Check your key and signing method.

Send request to the provided URL with the attached gzip file and headers. Response 200 Ok

Check the status of the uploaded file-

https://api.boxever.com/v2/batches/{{batchRef}}

The upload is queued and may take time depending on the items queued.

With the below request it shows the upload request is processing.

This request took almost 2 hours to complete, and the response here is error where 1 of the guets is updated but opther failed.

This is the log, where you should be able to rectify any errors in json file-

Lets check the other guest if available in portal-

Errors

SignatureDoesNotMatch

Loading

Send Abandoned Cart email using Sitecore Send Automation

Sitecore Send lets you automate your communication with customers by identifying specific situations that trigger the sending of an email message

In this blog lets create automated mails using automation recipes.

For more details see this link.

Pre-requisite-

Ensure the website is configured and verified before using the automation. See this blog. For this blog post I am using – https://moosend.vercel.app/

Create automation using Abandoned Cart automation recipe

Navigate to Automation link and create new automation using recipe-

Select Abandoned cart recipes-

Will be shown the Abandoned Cart Workflow-

Choose Trigger option-

Select- Trigger every time option

Select your website from dropdown and Save. Only verified website will be visible here. You may also choose all sites.

Open wait operation-

For testing I have selected 5 minutes. Ideally this can be few hours/days as per the requirement or enter specific date. By default it is 45 minutes. Enter the wait time and Save.

Setup the filter

Select apply this filter to mailing list. I have selected the email list of the site, you may select different list.

Enter the product if you wish to or leave empty.

Click on “Add a collection”.

Select the time if the product is not purchased for certain time. I have entered 6 minutes. Enter the details and Save.

Select “Added a Product To Cart” and filter value. In this I have added product “Americano”.

Select timer and enter the wait time to 6 minutes and Save

Select the action

In this case Send the mail to user if the product is not purchased in selected time.

Select Send Mail campaign-

Enter the subject, From address, mail body. Select Emails per day. Save once this option is filled.

Activate the “Abandoned Cart” automation-

Automation List with activated

Once the automation configuration is complete will now add product to cart. the product name here is “Americano” as selected in filter.

In the installation script you can find the details on how to add the product to cart.

function addToCart(){
                // mandatory - a unique code for the product, like its SKU
                    var itemCode = 'Americano';
                    // mandatory - the name / title of this product
                    var itemName = 'Iced Americano';
                    // mandatory - the image url of this product
                    var itemImage = 'http://your.store/product-color-blue.jpg';
                    // mandatory - the price of this product
                    var itemPrice = 10.25;
                    // mandatory - the url to get to the relevant product page
                    var itemUrl = 'http://your.store/product-101';
                    // mandatory
                    var itemQuantity = 1;
                    // mandatory - the total price for purchasing the given quantity of this product
                    var itemTotalPrice = 10.25;
                    // optional - the category of this product
                    var itemCategory = 'Drinks';
                    // optional - the manufacturer, brand name or company / owner of this product (if any)
                    var itemManufacturer = 'Acme Co';
                    // optional - the supplier of this product (if any)
                    var itemSupplier = 'Supplier Co';

                    // you can add custom properies and later use them in segmentations or automations
                    // You can track things like the color or the sze of the t-shirt in this case
                    var extraProps = {'flavor': 'Chocolate', 'type': 'Iced'};

                    // Tracking add to cart events with mandatory arguments
                    mootrack('trackAddToOrder', itemCode, itemPrice, itemUrl, itemQuantity, itemTotalPrice);

                alert("Added to cart event fired");
}

Hook the Add to cart to button-

<button class="button" onclick="addToCart()">Add to cart</button>

The site looks like this with the “Add To Cart” button

Website confirm the event was triggered.

In the automation list you can see the automation been Triggerd-

Once this is triggered you can see the next operation Wait for 5 minutes-

A mail should be triggerd after 6 minutes. Since the product is still in cart and not purchased.

After 5 minutes all the actions should be triggered.

Once all the actions are triggered should receive the mail-

Thats it for this blog. We have managed to trigger a automation event and send themail to the users who have product in the cart and not purchased e.e. Abandoned Cart.

Loading