Quick introduction
Sitecore CDP stands for Sitecore Customer Data Platform. This is a quote from Sitecore documentation:
A Customer Data Platform is packaged software that creates a persistent, unified customer database that is accessible to other systems.
In nutshell it tracks customers’ data across all channels, and later this data can be used to run personalization for segments of customers. Sitecore provides detailed documentation, and you can get more information from their website: What is a CDP
Get access to Sitecore CDP
Thanks, Perficient that as Sitecore platinum partner, we have access to the sandbox where we can practice and work. The Sitecore CDP interface is straightforward:
Goal
I was interested in what need to be done to connect the existing Next.js website to Sitecore CDP. Also, I wanted to see the whole picture of how Sitecore CDP collecting customer data. There is Developer Documentation explaining how to integrate it using vanilla JavaScript. Let’s look how we can apply it to Next.js project.
Setup Sitecore CDP
Obtain Client Key
Login to Sitecore CDP, navigate to System Settings -> API Access
Create Point of Sale
Navigate to System Settings -> Point of Sale to setup a new point of sale for our website
Enable debug mode
Debug mode enables visibility of all data and configuration stored in Sitecore CDP. It will give us access to additional information for requests. To enable debug mode, click on the Bottom left corner -> You Profile -> Feature Flags -> Enable Debug flag.
Review organization identity rules
To be able to send Identity event to Sitecore CDP, we need to know the identity rules for our organization tenant. To verify that information we should navigate to System Settings -> Company Information.
On the company information screen, we should click Debug, and after that Show as JSON, and then locate the identityIndexConfigurations JSON object.
These are the identity rules for our organization’s tenant. In this case the organization is using one identity rule: SITECORE_ID. That means that when we will be sending IDENTITY event to Sitecore CDP it should contain a value for SITECORE_ID attribute to identify a guest.
Implementation
At this point we are ready to connect our application to Sitecore CDP. All sensitive information we will put in the configuration file.
// cdpConfig.js const cdpConfig = { client_key: process.env.BOXEVER_CLIENT_KEY, cookie_domain: process.env.BOXEVER_COOKIE_DOMAIN, pointOfSale: process.env.NEXT_PUBLIC_BOXEVER_POC, clientVersion: process.env.BOXEVER_CLIENT_VERSION, webFlowTarget: process.env.BOXEVER_WEB_FLOW_TARGET, }; export default cdpConfig;
According to documentation, we need to activate JavaScript library by adding script snippet to each page. We can wrap that script into the react component.
// SitecoreCdp.jsx import React from 'react'; import cdpConfig from '@/clients/cdpConfig'; const SitecoreCdp = () => { return ( <React.Fragment> <script dangerouslySetInnerHTML={{ __html: `var _boxeverq = _boxeverq || []; var _boxever_settings = { client_key: '${cdpConfig.client_key}', target: 'https://api-us.boxever.com/v1.2', cookie_domain: '${cdpConfig.cookie_domain}', javascriptLibraryVersion: '${cdpConfig.clientVersion}', pointOfSale: '${cdpConfig.pointOfSale}', web_flow_target: '${cdpConfig.webFlowTarget}', web_flow_config: { async: true, defer: true } }; (function() { var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = 'https://d1mj578wat5n4o.cloudfront.net/boxever-${cdpConfig.clientVersion}.min.js'; var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x); })();`, }} ></script> </React.Fragment> ); }; export default SitecoreCdp;
We can use that component from our _app.js, so we have that script injected to every page.
// _app.js import Head from 'next/head'; import GoogleAnalytics from '@/utils/GoogleAnalytics'; import SitecoreCdp from '@/utils/SitecoreCdp'; import { AppProvider } from '@/contexts/app/AppContext'; const App = ({ Component, pageProps }) => { return ( <Head> <meta name='viewport' content='width=device-width, initial-scale=1' /> <meta httpEquiv='Content-Type' content='text/html; charset=utf-8' /> <GoogleAnalytics /> <SitecoreCdp /> </Head> <AppProvider> <Component {...pageProps} /> </AppProvider> ); }; export default App;
Now we need to implement some logic to send events to Sitecore CDP. Few helper functions will help us to provide some common information.
// helpers.js export const isClientSide = () => typeof window !== 'undefined'; export const getChannel = () => { if (!isClientSide()) { return null; } const userAgent = window.navigator.userAgent || window.navigator.vendor || (window.opera && window.opera.toString() === `[object Opera]`); if (/window phone/i.test(userAgent)) { return 'Windows Phone'; } if (/android/i.test(userAgent)) { return 'Android'; } if (/iPad/i.test(userAgent)) { return 'iPad'; } if (/iPhone/i.test(userAgent)) { return 'iPhone'; } return 'WEB'; }; export const getCdpObjects = () => { if (!isClientSide()) { return null; } const boxever = window.Boxever; const boxeverq = window._boxeverq; if (!boxever) { return null; } const browser_id = boxever.getID(); const channel = getChannel(); const defaultEvent = { browser_id: browser_id, channel: channel, poc: cdpConfig.pointOfSale, ext: { userDevice: channel, }, }; boxever.addUTMParams(defaultEvent); return { boxever, boxeverq, defaultEvent }; };
- isClientSide returning true or false depending on which side of application we are (client or server)
- getChannel returning us a channel depending on user browser
- getCdpObjects returning boxever objects to send events, and the default event object with common information
And the final preparation step is to create actions to send events.
// cdpActions.js import { getCdpObjects } from '@/utils/helpers'; const createCdpEvent = (eventData) => { const { boxever, boxeverq, defaultEvent } = getCdpObjects() || {}; if (!boxever) { return; } const cdpEvent = { ...defaultEvent, ...eventData, }; boxeverq.push(function () { boxever.eventCreate(cdpEvent, function () {}, 'json'); }); }; const createCdpIdentityEvent = (user, eventData) => { const { boxever, boxeverq, defaultEvent } = getCdpObjects() || {}; if (!boxever || !user) { return; } const cdpEvent = { ...defaultEvent, ...eventData, type: 'IDENTITY', email: user.email, lastName: user.lastName, firstName: user.firstName, gender: user.gender, age: user.age, phone: user.phone, identifiers: [ { provider: 'SITECORE_ID', id: user.id, }, ], }; cdpEvent.ext.gender = user.gender; cdpEvent.ext.age = user.age; boxeverq.push(function () { boxever.eventCreate(cdpEvent, function () {}, 'json'); }); }; export { createCdpEvent, createCdpIdentityEvent };
This code is showing that we created two actions which will be used to send general and identified events. Now we can start sending events to Sitecore CDP from our application. Below is an example how to send both types of events from the home page.
// pages/index.js import React, { Fragment } from 'react'; import { createCdpEvent, createCdpIdentityEvent } from '@/actions/cdpActions'; import { useAppContext } from '@/contexts/app/AppContext'; const HomePage = (props) => { const { state } = useAppContext(); useEffect(() => { createCdpEvent({ type: 'VIEW', page: 'home', }); }, []); useEffect(() => { if (state.user.email === '') { return; } createCdpIdentityEvent(state.user, { page: 'home', }); }, [state.user.email]); return ( <Fragment> … </Fragment> ); } export default HomePage;
When user is visiting this page ‘View’ event is getting sent (which is 1st useEffect hook is responsible for), and when user is logged in, Identity event is getting sent. This is responsibility of 2nd useEffect hook.
Review results
If we visit or home page, we can see that view event has been sent to Sitecore CDP.
This is the request:
This is the response:
We can search data in Sitecore CDP by browser_Id
All user interactions associated with that session are available
And since debug mode was activated, event detail information in JSON format available as well
If we are logging into our application, then the Identify event is getting sent to Sitecore CDP. Below is the example of how create event request looks like
And request data can be observed from Sitecore CDP side as well.
Conclusion
As we can see Sitecore CDP integration with an existing application is not requiring a lot of work at all. Discussed approach is not the only way to make that integration. There is Sitecore Personalize npm package which is a wrapper for Sitecore CDP scripts and allows us to add it in react applications. Another approach would be to set up an API server which will be making calls to Sitecore CDP. From an application we will be making calls to that server. In this case we don’t need to inject script to every single page. With Next.js that can be done in the same application. This is an example how these calls could look like.