---
schema_version: "1"
id: 31c69cb941edf1fac7e864f9d84e7e360d5c32b1c2aaf207d3f1c468563ad31a
title: Einstein Activities for Hybrid Implementations
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/commerce-cloud/commerce-api/guides/einstein-activities-for-phased-headless-rollouts.md
canonical_url: https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/einstein-activities-for-phased-headless-rollouts.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 0f0b4d27461c41cf9c1c90f2eb1ec444e73222a229c69310b7696fccd97a934a
products:
  - Composable Storefront
  - Salesforce APIs
---
# Einstein Activities for Hybrid Implementations

With [Reports & Dashboards](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guides/reports-and-dashboards.md), identify trends over time and make smarter business decisions based on your B2C Commerce data.

Reports & Dashboards analytics can only be derived from either web adapter logs or the Einstein Activities API. By default, SFRA and SiteGenesis analytics data are stored in web adapter logs, while the PWA Kit sends analytics data to Einstein Activities API.

If you are pursuing a [Hybrid Implementation Guidance](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/hybrid-storefront-baskets.md), where some pages are powered by PWA Kit and others are powered by SFRA or SiteGenesis, and you want to use Reports & Dashboards across your entire site, you must update your SFRA or SiteGenesis implementation to use the Einstein Activities API. This ensures that the API captures the full shopper experience, regardless of whether the shopper is in PWA Kit, SFRA, or SiteGenesis.

**tip:** Only existing customers can access some of the links on this page. Visit [Salesforce Commerce Cloud GitHub Repositories and Access](https://developer.salesforce.com/docs/commerce/b2c-commerce/guide/b2c-github-repo-access.html) for information about how to get access to the repositories.


This guide shows you **how to integrate the Einstein Activities API with SFRA's checkout**, so that it sends the same activities as [PWA Kit's checkout](https://github.com/SalesforceCommerceCloud/pwa-kit/blob/180cf0b11f9b34e4d504aee3cb3c9d178797d57d/packages/template-retail-react-app/app/pages/checkout/util/checkout-context.js#L60-L72).

If your phased rollout has additional pages on SFRA or SiteGenesis that send analytics data to the web adapter logs, then for those pages follow a process similar to what's described in this guide. Look at the corresponding pages in the [Retail React App](https://pwa-kit.mobify-storefront.com/) and observe which activities they send out. You'll then need to send the same activities on your SFRA or SiteGenesis pages. As a resource, this [overview of Einstein activities](https://developer.salesforce.com/docs/commerce/einstein/guides/einstein-activities/usage.md) shows you where those activities are supposed to be used.

**note:** Implementations using SiteGenesis with Composable Storefront aren't officially supported.

## About the Code Examples

Use caution when integrating the code examples provided, and always test your code thoroughly before pushing it to production.

Lines to be added to existing code are marked with the addition (`+`) symbol and lines to be deleted are marked with the subtraction (`-`) symbol.

Before running the commands in this tutorial, replace any placeholders with actual values. Placeholders are formatted like this: `$PLACEHOLDER`.

## Step 1\: Update Checkout Controller

Start by updating your checkout controller to include the current basket ID.

```diff
  res.render('checkout/checkout', {
+   basketId: currentBasket.UUID,
    order: orderModel,
    customer: accountModel,
    ...
});
```

## Step 2\: Update Checkout Template

Update the ISML template used for checkout. This change makes the basket ID, items, and total available to the browser.

```diff
-    <div id="checkout-main" class="container data-checkout-stage <isif condition="${pdict.order.usingMultiShipping && pdict.order.shipping.length > 1}">multi-ship</isif>" data-customer-type="${pdict.customer.registeredUser ? 'registered' : 'guest'}" data-checkout-stage="${pdict.currentStage}" data-checkout-get-url="${URLUtils.https('CheckoutServices-Get')}">
+    <div id="checkout-main" class="container data-checkout-stage <isif condition="${pdict.order.usingMultiShipping && pdict.order.shipping.length > 1}">multi-ship</isif>" data-customer-type="${pdict.customer.registeredUser ? 'registered' : 'guest'}" data-checkout-stage="${pdict.currentStage}" data-checkout-get-url="${URLUtils.https('CheckoutServices-Get')}" data-checkout-price-total="${pdict.order.priceTotal}" data-checkout-items="${JSON.stringify(pdict.order.items)}" data-basket-id="${pdict.basketId}">
```

## Step 3\: Create Helpers

Create a JavaScript file called `js/einsteinHelpers.js` that contains helper functions:

**important:** Don’t forget to replace the placeholders `$YOUR_SITE_ID` and `$YOUR_CLIENT_ID` with actual values.

```javascript
"use strict";

/**
 * Get the value of a cookie
 * Source: https://gist.github.com/wpsmith/6cf23551dd140fb72ae7
 * @param  {string} name  The name of the cookie
 * @return {string | undefined}       The cookie value
 */
function getCookie(name) {
  var value = "; " + document.cookie;
  var parts = value.split("; " + name + "=");
  var result;

  if (parts.length === 2) {
    result = parts.pop().split(";").shift();
  }
  return result;
}

/**
 * Fire a given Einstein activity with the provided data.
 *
 * @param {string} name - The name of the activity.
 * @param {Object} data - The activity payload.
 */
function fireEinsteinActivity(name, data) {
  // NOTE: These should be placed in the custom preferences of BM. This will help
  // avoid any code deployments if you need to change these values.
  // NOTE 2: this is _Einstein_ site id (not the same as SFRA one like RefArch).
  var SITE_ID = "$YOUR_SITE_ID";
  var CLIENT_ID = "$YOUR_CLIENT_ID";
  // Reports & Dashboards will only show data that's been tagged as `prd` (production)
  var INSTANCE_TYPE = "prd";

  // Assign the realm to the data.
  var activityData = Object.assign(data, {
    realm: SITE_ID.split("-")[0],
    instanceType: INSTANCE_TYPE,
  });

  var userId = data.userId;
  var cookieId = data.cookieId;

  // Apply payload information for logged in users.
  if (userId) {
    activityData = Object.assign(activityData, {
      userId: userId,
    });
  }

  if (cookieId) {
    activityData = Object.assign(activityData, {
      cookieId: cookieId,
    });
  }

  var url = "https://api.cquotient.com/v3/activities" + "/" + SITE_ID + "/" + name;

  try {
    fetch(url, {
      headers: {
        "Content-Type": "application/json",
        "x-cq-client-id": CLIENT_ID,
      },
      method: "POST",
      body: JSON.stringify(activityData),
    });
  } catch (e) {
    console.error(e);
  }
}

var exports = {
  fireEinsteinActivity: fireEinsteinActivity,
  getCookie: getCookie,
};

module.exports = exports;
```

## Step 4\: Record Activities

Update your `checkout.js` script to record activities. You must add this call to `require()` at the top of your checkout script, and it must appear after any existing imports.

```javascript
var einsteinHelpers = require('../einsteinHelpers');
```

Trigger the `checkoutStep` activity when the checkout stage is changed. Append the following code to the `updateUrl` method:

```javascript
/**
 * @returns {boolean} whether the current customer is registered or not
 */
function isRegisteredCustomer() {
  return $(".data-checkout-stage").data("customer-type") === "registered";
}

/**
 * Get the cookieId, which is a unique identifier used for linking subsequent activities to the same user.
 * If the cookieId is not defined, then Reports & Dashboards will treat the activity as coming from an anonymous user.
 * @returns {string | undefined} value of the cookieId param for Einstein Activities API
 */
function getCookieId() {
  var siteId = window.CQuotient && window.CQuotient.siteId;
  // This usid cookie is set by either PWA or plugin_slas
  return (
    einsteinHelpers.getCookie("usid_" + siteId) || einsteinHelpers.getCookie("usid") || undefined
  );
}

/**
 * Get the userId, which is for linking registered users across different devices.
 * @returns {string | undefined} value of the userId param for Einstein Activities API
 */
function getUserId() {
  var siteId = window.CQuotient && window.CQuotient.siteId;
  // This enc_user_id is set by PWA
  return (
    window.localStorage.getItem("enc_user_id_" + siteId) ||
    window.localStorage.getItem("enc_user_id") ||
    undefined
  );
}

/**
 * Updates the URL to determine stage
 * @param {number} currentStage - The current stage the user is currently on in the checkout
 */
function updateUrl(currentStage) {
  // ...

  var cookieId = getCookieId();
  var userId = isRegisteredCustomer() ? getUserId() : undefined;

  einsteinHelpers.fireEinsteinActivity("checkoutStep", {
    basketId: $("#checkout-main").data("basket-id"),
    stepName: checkoutStages[currentStage],
    stepNumber: currentStage,
    cookieId: cookieId,
    userId: userId,
  });
}
```

**note:** Triggering the `checkoutStep` activity in the `updateUrl` method ensures that any transition from one checkout stage to the next (or previous) is tracked.

Trigger the `beginCheckout` activity at the end of the `initialize` function for your checkout code:

```javascript
//
// Send Einstein `beginCheckout` activity
//
// Parse total amount value
var amount = $("#checkout-main").data("checkout-price-total");
amount = Number(amount.replace(/[^0-9.-]+/g, ""));

var products = $("#checkout-main")
  .data("checkout-items")
  .items.map(function (item) {
    return {
      id: item.id,
      price: Number(item.priceTotal.price.replace(/[^0-9.-]+/g, "")),
      quantity: item.quantity,
    };
  });

var cookieId = getCookieId();
var userId = isRegisteredCustomer() ? getUserId() : undefined;

einsteinHelpers.fireEinsteinActivity("beginCheckout", {
  products: products,
  amount: amount,
  cookieId: cookieId,
  userId: userId,
});
```

**note:** The `beginCheckout` activity is only triggered one time per page load during checkout. Activity data preparation is handled automatically.

That’s it! You’ve successfully integrated Einstein Activities with SFRA's checkout. To finish your setup of Reports &amp; Dashboards, complete the steps in [Reports &amp; Dashboards](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guides/reports-and-dashboards.md).

## See Also

- [Hybrid Implementation Guidance](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/hybrid-storefront-baskets.md)
- [Data and Analytics](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guides/data-and-analytics.md)
- [Get Started with Composable Storefront](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guides/pwa-developer-workflow.md)
