Marketing Cloud Personalization Trends

Marketing Cloud Personalization Trends (IS Trends) uses the power of social validation to increase conversions. Most consumers are overwhelmed by the product choices available to them and can find it challenging to confidently buy products online. Use the “wisdom of the crowd” to influence visitors on your site in real time and build confidence in products viewed by using view and purchase counters. These view and purchase counters drive both validation and urgency ultimately influencing conversions on your site.

By enabling this feature, you’re allowing Personalization to return catalog object purchase and view data via a public API.

Note

API Functionality 

What Does the API Do? 

Given one or more catalog object IDs and a number of lookback minutes, the IS Trends API is designed to return the number of views and recent purchases for those catalog object IDs within that lookback period.

How is the API Called? 

Requests to the IS Trends API can be made to URL endpoints that adhere to the following basic structure.

1https://<accountName>.<instance>.evergage.com/api/dataset/<dataset>/social/smartTrends/Product?itemIds=<string>&lookbackMins=<integer>

For your API requests to work correctly, your request URLs must include your Personalization account name and instance identifier.

Note

The following table lists the required and optional request URL parameters included in the preceding example.

Request URL Parameters 

URL ParameterRequired?Description
accountNameYesYour Personalization account name. You can retrieve it by accessing Gears from the Personalization UI and reviewing the URL. For example, if your Gears URL is demo.us-1.evergage.com, then your account name is demo.
instanceYesYour Personalization instance identifier. You can retrieve it by accessing Gears from the Personalization UI and reviewing the URL. For example, if your Gears URL is demo.us-1.evergage.com, then your instance identifier is us-1.
datasetYesThe name or identifier of the Personalization dataset you’re sending data to.
itemIds: stringYesProvide either a singular item ID or a comma-separated list of item IDs.
lookbackMins: integerNoAn integer representing the number of minutes to be used for a lookback period. This value can’t exceed 2880 minutes (2 days).

Example Requests 

Given parameters:

1accountName = "example"
2instance = "us-1"
3dataset = "engage"
4itemIds = "4100323" | "1010263,1050855,1031064,1050946"
5lookbackMins = 120
  • Single ID: https://example.us-1.evergage.com/api/dataset/engage/social/smartTrends/Product?itemIds=4100323&lookbackMins=120
  • Multiple IDs: https://example.us-1.evergage.com/api/dataset/engage/social/smartTrends/Product?itemIds=1010263,1050855,1031064,1050946&lookbackMins=120

What Data Can It Return? 

Returns an object with keys representing the itemID(s). The value for these keys each have an object containing stats for visitViews and purchases within the lookback period provided in the request.

The stat values in the response reflect the stats that ‘s been tracked against only the specific catalog objects within the lookback period, meaning that the stat values don’t account for views and/or purchases of the catalog object through a relationship to another catalog object. For instance, if a purchase is tracked for Product X and Category Y is related to it, a request to the IS Trends API with the itemId for Category Y results in a response with 0 purchases.

With the preceding note in mind, it is expected that the value for purchases is only greater than 0 when sending itemIds for the Product catalog object.

Note

Example Responses 

  • Single ID: {"4100323":{"visitViews":1,"purchases":0}}
  • Multiple IDs: {"1050946":{"visitViews":0,"purchases":0},"1010263":{"visitViews":0,"purchases":0},"1050855":{"visitViews":0,"purchases":0},"1031064":{"visitViews":0,"purchases":0}}

Sample Template 

Use one of the following links to download a ZIP file containing the sample IS Trends template for your SDK namespace.

While the default configuration of the example template is for Products, you can use it with other catalog types by making the following changes.

  1. Change the value of settings.id to reference the desired Catalog Object type.
  2. Change the URL string returned by settings.url to reference the desired Catalog Object type.

For example, if you’re customizing this template for Articles, you would make the following changes to the properties in settings.

SalesforceInteractions namespace
1const settings = {
2    ...
3    id: (((SalesforceInteractions.mcis.getSitemapResult().currentPage || {}).interaction || {}).catalogObject || {})._id,
4    ...
5    url: () => `https://${settings.account}.evergage.com/api/dataset/${settings.dataset}/social/smartTrends/Article`
6};
Evergage namespace
1const settings = {
2    ...
3    id: (((Evergage.getCurrentPage() || {}).catalog || {}).Article || {})._id,
4    ...
5    url: () => `https://${settings.account}.evergage.com/api/dataset/${settings.dataset}/social/smartTrends/Article`
6};

Full Sample Template Code 

The sample IS Trends template consists of the following:

  • Handlebars code
  • CSS
  • Server-side TypeScript code
  • Client-side JavaScript code for the SalesforceInteractions and the Evergage SDK namespaces
Sample IS Trends template Handlebars code
1{{!
2    Template: IS Trends
3
4    Requirements:
5    1) Enable IS Trends for dataset (Settings > General Setup > Advanced Options > Enable IS Trends)
6}}
7
8<ul
9  id="mcis-trends"
10  class="mcis-trends"
11  data-evg-campaign-id="{{campaign}}"
12  data-evg-experience-id="{{experience}}"
13  data-evg-user-group="{{userGroup}}"
14>
15</ul>
Sample IS Trends template CSS
1#mcis-trends.mcis-trends {
2  opacity: 0;
3  padding: 0 15px;
4  font-style: italic;
5}
6
7#mcis-trends.mcis-trends li {
8  color: #ffa500;
9  list-style-type: none;
10}
Sample IS Trends server-side typescript code
1export class ISTrendsTemplate implements CampaignTemplateComponent {
2  purchasesText: string;
3
4  visitorsText: string;
5
6  run(context: CampaignComponentContext) {
7    return {
8      purchasesText: this.purchasesText || "recently purchased",
9      visitorsText: this.visitorsText || "visitors currently viewing",
10    };
11  }
12}
Sample IS Trends client-side JavaScript code for the SalesforceInteractions namespace
1(function () {
2  const ISTrends = (function () {
3    const settings = {
4      account: SalesforceInteractions.mcis.getConfig().account,
5      dataset: SalesforceInteractions.mcis.getConfig().dataset,
6      delay: 3000,
7      id: (
8        ((SalesforceInteractions.mcis.getSitemapResult().currentPage || {}).interaction || {})
9          .catalogObject || {}
10      ).id,
11      lookbackMins: 2 * 60, // maximum 2 day
12      minPurchases: 1,
13      minViews: 1,
14      reloadInterval: 30 * 1000,
15      shouldCycle: true,
16      stopLoadingAfter: 10 * 60 * 1000,
17      url: () =>
18        `https://${settings.account}.evergage.com/api/dataset/${settings.dataset}/social/smartTrends/Product`,
19    };
20
21    const global = {
22      context: null,
23      template: null,
24    };
25
26    const actions = {
27      handleResults: (results) => {
28        const { id, minPurchases, minViews } = settings;
29        const { purchasesText, visitorsText } = global.context;
30
31        const mcisTrendsContainer = SalesforceInteractions.cashDom("ul.mcis-trends");
32        mcisTrendsContainer.css({ opacity: "0" });
33        mcisTrendsContainer.empty();
34        if (results[id].purchases >= minPurchases) {
35          mcisTrendsContainer.append(`
36                        <li id="evg-trend-minPurchases">
37                            ${results[id].purchases} ${purchasesText}
38                        </li>
39                    `);
40        }
41        if (results[id].visitViews >= minViews) {
42          mcisTrendsContainer.append(`
43                        <li id="evg-trend-minViews">
44                            ${results[id].visitViews} ${visitorsText}
45                        </li>
46                    `);
47        }
48        mcisTrendsContainer.css({ opacity: "1" });
49      },
50      loadTrends: () => {
51        const { id, lookbackMins, url } = settings;
52        const requestUrl = `${url()}?itemIds=${id}&lookbackMins=${lookbackMins}`;
53
54        return fetch(requestUrl)
55          .then((resp) => {
56            return resp.json();
57          })
58          .then((data) => {
59            return actions.handleResults(data);
60          })
61          .catch((err) => {
62            console.warn(err);
63          });
64      },
65    };
66
67    return {
68      init: function ({ context, template }) {
69        const { reloadInterval, stopLoadingAfter } = settings;
70        const { loadTrends } = actions;
71
72        Object.assign(global, { context, template });
73        loadTrends();
74        const timerId = window.setInterval(loadTrends, reloadInterval);
75        window.setTimeout(() => {
76          settings.shouldCycle = false;
77          clearInterval(timerId);
78        }, stopLoadingAfter);
79      },
80    };
81  })();
82
83  /**
84   * @function buildBindId
85   * @param {Object} context
86   * @description Create unique bind ID based on the campaign and experience IDs.
87   */
88  function buildBindId(context) {
89    return `${context.campaign}:${context.experience}`;
90  }
91
92  function apply(context, template) {
93    const contentZoneSelector = SalesforceInteractions.mcis.getContentZoneSelector(
94      context.contentZone,
95    );
96    return SalesforceInteractions.DisplayUtils.bind(buildBindId(context))
97      .pageElementLoaded(contentZoneSelector)
98      .then((element) => {
99        if (SalesforceInteractions.cashDom("#mcis-trends").length > 0) return;
100
101        const html = template(context);
102        SalesforceInteractions.cashDom(element).html(html);
103        ISTrends.init({ context, template });
104      });
105  }
106
107  function reset(context, template) {
108    SalesforceInteractions.DisplayUtils.unbind(buildBindId(context));
109    SalesforceInteractions.cashDom("#mcis-trends").remove();
110  }
111
112  function control(context) {
113    const contentZoneSelector = SalesforceInteractions.mcis.getContentZoneSelector(
114      context.contentZone,
115    );
116    return SalesforceInteractions.DisplayUtils.bind(buildBindId(context))
117      .pageElementLoaded(contentZoneSelector)
118      .then((element) => {
119        SalesforceInteractions.cashDom(element).attr({
120          "data-evg-campaign-id": context.campaign,
121          "data-evg-experience-id": context.experience,
122          "data-evg-user-group": context.userGroup,
123        });
124      });
125  }
126
127  registerTemplate({
128    apply: apply,
129    reset: reset,
130    control: control,
131  });
132})();
Sample IS Trends client-side JavaScript code for the Evergage namespace
1(function () {
2  const ISTrends = (function () {
3    const settings = {
4      account: Evergage.getConfig().account,
5      dataset: Evergage.getConfig().dataset,
6      delay: 3000,
7      id: (((Evergage.getCurrentPage() || {}).catalog || {}).Product || {})._id,
8      lookbackMins: 2 * 60, // maximum 2 day
9      minPurchases: 1,
10      minViews: 1,
11      reloadInterval: 30 * 1000,
12      shouldCycle: true,
13      stopLoadingAfter: 10 * 60 * 1000,
14      url: () =>
15        `https://${settings.account}.evergage.com/api/dataset/${settings.dataset}/social/smartTrends/Product`,
16    };
17
18    const global = {
19      context: null,
20      template: null,
21    };
22
23    const actions = {
24      handleResults: (results) => {
25        const { id, minPurchases, minViews } = settings;
26        const { purchasesText, visitorsText } = global.context;
27
28        const mcisTrendsContainer = Evergage.cashDom("ul.mcis-trends");
29        mcisTrendsContainer.css({ opacity: "0" });
30        mcisTrendsContainer.empty();
31        if (results[id].purchases >= minPurchases) {
32          mcisTrendsContainer.append(`
33                        <li id="evg-trend-minPurchases">
34                            ${results[id].purchases} ${purchasesText}
35                        </li>
36                    `);
37        }
38        if (results[id].visitViews >= minViews) {
39          mcisTrendsContainer.append(`
40                        <li id="evg-trend-minViews">
41                            ${results[id].visitViews} ${visitorsText}
42                        </li>
43                    `);
44        }
45        mcisTrendsContainer.css({ opacity: "1" });
46      },
47      loadTrends: () => {
48        const { id, lookbackMins, url } = settings;
49        const requestUrl = `${url()}?itemIds=${id}&lookbackMins=${lookbackMins}`;
50
51        return fetch(requestUrl)
52          .then((resp) => {
53            return resp.json();
54          })
55          .then((data) => {
56            return actions.handleResults(data);
57          })
58          .catch((err) => {
59            console.warn(err);
60          });
61      },
62    };
63
64    return {
65      init: function ({ context, template }) {
66        const { reloadInterval, stopLoadingAfter } = settings;
67        const { loadTrends } = actions;
68
69        Object.assign(global, { context, template });
70        loadTrends();
71        const timerId = window.setInterval(loadTrends, reloadInterval);
72        window.setTimeout(() => {
73          settings.shouldCycle = false;
74          clearInterval(timerId);
75        }, stopLoadingAfter);
76      },
77    };
78  })();
79
80  /**
81   * @function buildBindId
82   * @param {Object} context
83   * @description Create unique bind ID based on the campaign and experience IDs.
84   */
85  function buildBindId(context) {
86    return `${context.campaign}:${context.experience}`;
87  }
88
89  function apply(context, template) {
90    const contentZoneSelector = Evergage.getContentZoneSelector(context.contentZone);
91    return Evergage.DisplayUtils.bind(buildBindId(context))
92      .pageElementLoaded(contentZoneSelector)
93      .then((element) => {
94        if (Evergage.cashDom("#mcis-trends").length > 0) return;
95
96        const html = template(context);
97        Evergage.cashDom(element).html(html);
98        ISTrends.init({ context, template });
99      });
100  }
101
102  function reset(context, template) {
103    Evergage.DisplayUtils.unbind(buildBindId(context));
104    Evergage.cashDom("#mcis-trends").remove();
105  }
106
107  function control(context) {
108    const contentZoneSelector = Evergage.getContentZoneSelector(context.contentZone);
109    return Evergage.DisplayUtils.bind(buildBindId(context))
110      .pageElementLoaded(contentZoneSelector)
111      .then((element) => {
112        Evergage.cashDom(element).attr({
113          "data-evg-campaign-id": context.campaign,
114          "data-evg-experience-id": context.experience,
115          "data-evg-user-group": context.userGroup,
116        });
117      });
118  }
119
120  registerTemplate({
121    apply: apply,
122    reset: reset,
123    control: control,
124  });
125})();