React’s higher order component to stream events to Sitecore CDP

Sitecore Customer Data Platform (CDP) tracks customers’ data across all the channels. This data can later be used by Sitecore Personalize to run personalization for a single or a segment of customers. If you are a React developer and planning to integrate your website to Sitecore’s CDP(f.k.a Boxever), this post will touch base on one of the cleanest ways of achieving this. Tracking a customer’s activities on your website for analytics and personalization is a cross-cutting concern in its nature. React documentation recommends using Higher-Order Component(HOC) or Hooks for cross-cutting concerns.

If you are not familiar with the higher-order components, please have a look at https://reactjs.org/docs/higher-order-components.html official documentation.

Sitecore CDP provides a few different modes of integration. The focus of this post is primarily integrating a React website to CDP using javascript library. If you are not across this integration option, please get yourself familiarized here.

Since the detail of this integration option is not the focus of this post, I am providing certain pointers in case you are new to Sitecore CDP.

  • Sitecore CDP’s JS library exposes a global js object using ES6 features. This object is called Boxever and you can access it in the javascript using window.Boxever.
  • The Boxever object can then be utilized to send out the events(customer activities) to CDP.
  • In order to make event calls asynchronous, the JS library also exposes an event queue called _boxeverq. This queue can be accessed using window._boxeverq.
  • All we have to do is to prepare(json object) and push these events to the queue and then send out the events from the queue to CDP. Why use the queue? have a look at the documentation here.

A screenshot of the chrome console showing both the objects.

ChromeConsole

In my React website, I have different components that are supposed to send out events to CDP. In order to keep the interactions streamed lined, I have created a React HOC component.

import React from "react";

function BoxeverHoc(WrappedComponent) {
  return class extends React.Component {
    constructor() {
      super();
      this.boxever = null;
      this.boxeverq = null;
      this.createCdpEvent = this.createCdpEvent.bind(this);
      this.addFixedData = this.addFixedData.bind(this);
    }
    componentDidMount() {
      this.boxever = window.Boxever;
      this.boxeverq = window._boxeverq;
    }

    createCdpEvent(eventData) {
      eventData = this.addFixedData(eventData);
      this.boxeverq.push(function () {
        window.Boxever.eventCreate(eventData, function (data) {}, "json");
      });
    }

    addFixedData(viewEvent) {
      viewEvent.channel = "WEB";
      viewEvent.pos = "Myogni";
      viewEvent.browser_id = this.boxever.getID();
      return viewEvent;
    }

    render() {
      return (
        <React.Fragment>
          <WrappedComponent
            {...this.props}
            createCdpEvent={this.createCdpEvent}
          />
        </React.Fragment>
      );
    }
  };
}
export default BoxeverHoc;

HOC takes care of sending events to CDP as well as adds fixed data attributes like channel, pos etc.  It passes a function called createdCdpEvent using props to wrapped components. Then my ProductCard component(which triggers add to cart) calls createdCdpEvent to raise the AddProduct event.

Here is my ProductCard component.

import React from "react";

class ProductCard extends React.Component {
  onAddToCart(product) {
    //add to cart using API

    var viewEvent = {
      type: "ADD_PRODUCT",
      product: {
        name: product.name,
        quantity: 1,
        price: product.price,
        currency: "AUD",
      },
    };

    this.props.createCdpEvent(viewEvent);
  }
  render() {
    var { id, name, description, price, imageUrl } = this.props.product;

    return (
      <div key={id}>
        <div className="product__item">
          <div
            className="product__item__pic set-bg"
            style={{
              backgroundImage: "url(" + imageUrl + ")",
            }}
          >
            <ul className="product__item__pic__hover">
              <li>
                <a href="#">
                  <i className="fa fa-heart"></i>
                </a>
              </li>
              <li>
                <a href="#">
                  <i className="fa fa-retweet"></i>
                </a>
              </li>
              <li>
                <a
                  href="#"
                  onClick={() => {
                    this.onAddToCart(this.props.product);
                  }}
                >
                  <i className="fa fa-shopping-cart"></i>
                </a>
              </li>
            </ul>
          </div>
          <div className="product__item__text">
            <h6>{name}</h6>
            <h5>${price}</h5>
          </div>
        </div>
      </div>
    );
  }
}

export default ProductCard;

In order to render my ProductCard component, instead of using it directly, in my products gird, I used BoxeverHoc to render ProductCard as a wrapped component.

import React, { Component } from "react";
import ProductCard from "./ProductCard";
import ProductsList from "./productsList";
import BoxeverHoc from "../main/BoxeverHoc";
const ProductWithEvents = BoxeverHoc(ProductCard);

class ProductsGrid extends React.Component {
  render() {
    return (
      <div className="col-lg-9 col-md-7">        
        <div className="row">
          {ProductsList.map((p) => {
            return (
              <div key={p.id} className="col-lg-4 col-md-6 col-sm-6">
                <ProductWithEvents onAddToCart={this.onAddToCart} product={p} />
              </div>
            );
          })}
        </div>       
      </div>
    );
  }
}

export default ProductsGrid;

 

Happy coding!

 

Leave a Reply