JavaScript

JavaScript initialization

The communication between the recommendation engine and the customer's site is implemented by asynchronous JavaScript calls directly between the user's browser and the recommendation engine.

First, you need to bootstrap our system by adding the following code to the webpage (this will load and setup our JS library). Paste this snippet into your website template page so that it appears before the closing tag.

<head>
    [...]
<script>
    (function(g,r,a,v,i,t,y){
        g[a]=g[a]||[],y=r.createElement(v),
        g=r.getElementsByTagName(v)[0];y.async=1;
        y.src='//'+i+'/js/'+t+'/gr_reco5.min.js';
        g.parentNode.insertBefore(y,g);y=r.createElement(v),y.async=1;
        y.src='//'+i+'/grrec-'+t+'-war/JSServlet4?cc=1';
        g.parentNode.insertBefore(y,g);
    })(window, document, '_gravity','script', '<customer>-<location>.gravityrd-services.com', '<customer>');
</script>
</head>

You should replace with your partner identifier and with the gravity cluster name!

(The library will register a global object named "GravityRD". Except this object, which is necessary we don't pollute your namespace.)

📘

For debugging reasons, a non-minimized version of the library is also available, named: gr_reco5.js

Client setup

The following interaction types are defined inside the JavaScript framework:

Interaction typeDescription
eventTrack events generated by the webpage visitor to the recommendation engine (such as item VIEW, page BROWSE - main page, item BUY and etcetera).
recommendationRequest a recommendation request from the Gravity server (with optional rendering of the response).
set1. Configure the library settings
2. Set global name values (all global name values set are automatically attached to all requests sent to the server).
explanationRequest explanation for a recommendation.

All interaction requests to the JS library are formed as plain JavaScript objects

You can push requests via the push function, for example:

var _gravity = _gravity || []; // in case tag is fired before initialization, this ensures proper operation
 _gravity.push({
    type: "event",
    eventType: "BROWSE",
    itemId: "32345"
});

There are some part of the inserted codes that has to be dynamically generated like user and item identifiers. The way how this identifiers are inserted into the code snippets depends on the implementation of your e-commerce engine and as so it's not discussed in this tutorial.

Configure the library

You may change the following settings:

property nameproperty valuedefault valuedescription
useJsGeneratedCookietrueIf set to true the library automaticaly generates a cookie (with an unique cookie id inside it), to identify visitors of your site.
cookieNamegr_recoThe name of the cookie the library uses to track visitors.
cookieIdIf useJsGeneratedCookie is false, you need to provide the cookie value that identifies the website vistor.
userIdIf you have a logged in user, you should identify it through this option.
modeDEVELOP or PRODPRODIf you switch to develop mode, error messages and debugging information will be displayed on the "console" to help integration development.

The lifecycle of configuration goes with the "_gravity" JavaScript array, so every time you need to recreate it (e.g: page load) you should also repeat the configuration requests.

Library configuration code should be added right after the bootstrap code:
For Yusp autogenerated Cookie (proposed and easy way to integrate) option:

var _gravity = _gravity || [];
_gravity.push({
    type: 'set',
    useJsGeneratedCookie : true
});

Alternatively, custom cookieId can be used as well (we suggest to use long, at least 1-year expiration for identifier cookies)

var _gravity = _gravity || [];
_gravity.push({
    type: 'set',
    useJsGeneratedCookie : false,
    cookieName :’testCookie’,
    cookieId : ‘12qwfe234ti6g9’
});

Add event

Each website has its own subset of valid event types. There are the suggested lists of event types. Event types that you must integrate are part of your integration guide. Each event has some data fields which usually has to be filled with the appropriate value. All event object must have their eventType attribute defined.

Additional informations can be defined per event type. The set of this additional attributes are not predefined we only have a list of recommended name-values for the various event types but new name-values can be defined by our customers as well. Nevertheless, we do require some attributes to some events, see:

var _gravity = _gravity || [];
_gravity.push({
    type: "event",
    eventType: "BUY",
    itemId: "31856",
    quantity: "12",
    unitPrice: "3400",
    color: "blue"
});

For the REC_CLICK event you need to specify the recId attribute, what identifies the recommendation requests and is sent with each requests answer. However, if the recommendation request is done via JavaScript the framework automatically adds this parameter and is not required to do it manually.

To notify the recommendation engine about an event, you need to use an "event" typed push object, like in the following snippet:

var _gravity = _gravity || [];
_gravity.push({
    type: "event",
    eventType: "VIEW",
    itemId: "31856"
});

For ease of use you can extract it to a helper function, like in the following example:

function pushView(itemId){
    var _gravity = _gravity || [];
    _gravity.push({
       type: "event",
       eventType: "VIEW",
       itemId: itemId
    });
}

Checking if everything is all right

You can list the last events received by the recommendation engine on the DASH. After you integrated the event sending mechanism into your site, please check the event database on the DASH under "Database/Events". The last few hundred events should be visible there. If you are still unsure contact your integration engineer.

Get item recommendation

Callback based

In callback based displaying no HTML templating is used. During the recommendation request, a JavaScript callback function is provided. When the recommended items arrive from the recommendation engine, this callback function will be called, and the recommended items will be passed to it as a function parameter, containing the list of items as JavaScript objects. This way you can use your custom JavaScript logic to display the recommended items on the web page.

A recommendation request looks like:

var _gravity = _gravity || []; // in case tag is fired before initialization, this ensures proper operation
_gravity.push({
    type: 'recommendation',
    scenarioId: 'MAIN_PAGE_CENTER',
    numberLimit: 6,
    resultNames: ["location", "color"],
    callback: callback_fn
});

The following table displays the parameters you may change:

Parameter nameTypeDescription
numberLimitintThe number of items recommended in the item recommendation.
scenarioIdStringOne of the predefined ScenarioIds.
resultNamesString, ArrayThe name of the item parameters which will be contained in the result of the item recommendation request. The item parameters are the name-values and the itemId, itemType and title. This names can be used in the widget template.

Only name values present inside the item catalog may be requested.
callbackFunctionThe name of the callback function that is called once the asynchronous recommendation request finishes.

The following code snippet shows a basic way to visualize the response by adding dynamically a new div inside the page. This also shows the format of the response object, with REC_CLICK event tracking included.

function callback_fn(result){
    document.body.innerHTML += "<div id='reco_callback_target'></div>";
    var div = document.getElementById("reco_callback_target");
    div.setAttribute('class', 'recItems')
  
    // you can use item.title, item.id, item.price and any custom attribute.
    // for multiple valued attributes, you can use item.category_list, which is an array.
    // for the prediction value, you can use item.predictionValue.
    for (var i = 0; i < result.items.length; ++i) {
        var item = result.items[i];
        var itemDiv = document.createElement("div");
        itemDiv.setAttribute('class', 'recItem');
  
        div.appendChild(itemDiv);
        var imgLink = document.createElement("a");
        itemDiv.appendChild(imgLink);
        imgLink.setAttribute('href', '#');
        imgLink.onmousedown =  function() {
            _gravity.push({type:'event', eventType:'REC_CLICK', itemId: item.itemId});
        }
  
        var img = document.createElement("img");
        imgLink.appendChild(img);
        img.setAttribute('width', '90');
        img.setAttribute('src', item.imageUrl);
  
        var textDiv = document.createElement("div");
        textDiv.setAttribute('class', 'recItemTitle');
        textDiv.appendChild(document.createTextNode(item.title));
        itemDiv.appendChild(textDiv);
    }
 }

Template based

The list of the recommended items is displayed in box which we refer as recommendation widget. The design and functionality of this widgets can be controlled by HTML templates. Our templates are based on TrimPath template library.

In the next example three items will be displayed and if you click them an REC_CLICK event will be sent to the recommendation engine.

  1. Create a placeholder HTML element in the webpage, where the recommendation box should be. For example:
<div id="reco_div">recommendations will be displayed here</div>
  1. Create a template which will control the rendering of the recommendation:
<textarea id="reco_tpl" style="display: none;">
    <div class="recItems">
    {for p in products}
        <div class="recItem">
            <!-- the item attributes can be referenced as member variables of the elements in the "products" array -->
            <img src="${p.imageUrl}" width="60">
            <!-- reporting the click events to the recommendation engine -->
            <a onmousedown="_gravity.push({type:'event', eventType:'REC_CLICK', itemId: '${p.itemid}'});" href="/product/${p.itemid}">${p.title}</a>
        </div>
    {forelse}
        <!-- this part is used if the returned "products" array is empty -->
        <div> no recommendation returned </div>
    {/for}
    </div> 
</textarea>
  1. Issue a recommendation request:
var _gravity = _gravity || [];
_gravity.push({
    type: 'recommendation',
    scenarioId: 'PROFILE',
    numberLimit: 5,
    templating: {
        targetElementId: "reco_div",
        templateElementId: "reco_tpl"
}

The following table defines parameters that may be configured:

Parameter nameTypeDescription
templating.targetElementIdStringThe id attribute of the div which will contain the recommendation widget.
templating.templateStringThe whole HTML template as a single String if you do not want to use textarea as template holder.
templating.templateElementIdHTML element idThe id of the textarea containing the template for the recommendation widget.
templating.templateDataMapStatic context for template evaluation. Variables from this can be reached through ${templateData.variableName}
numberLimitintThe number of items recommended in the item recommendation.
scenarioIdStringOne of the predefined ScenarioIds.
resultNamesString, ArrayThe name of the item parameters which will be contained in the result of the item recommendation request. The item parameters are the name-values and the ItemId, ItemType and Title. This names can be used in the widget template.

Only name values present inside the item catalog may be requested.

General use cases

Item page recommendations

For some scenarios, additional context parameters may be required. For example, typically on the item page the recommendation is made based on the current item, so you'll need to pass the displayed items id with an additional context parameter: currentItemId. For example:

var _gravity = _gravity || [];
_gravity.push({
    type: 'recommendation',
    scenarioId: 'ITEM_PAGE',
    numberLimit: 6,
    currentItemId: "843928493",
    callback: callback_fn
});

Filter items from recommendation

The items can be filtered based on metadata attached to them. The filtering is controlled with custom attributes. Specify the attribute according to what the filtering is done, plus the attribute value to filter for. For example:

var _gravity = _gravity || [];
_gravity.push({
    type: 'recommendation',
    scenarioId: 'ITEM_PAGE',
    numberLimit: 6,
    filter_AdultCategoryId: "adult_22",
    callback: callback_fn
});

Filters are configured on the server side. If you want to use filtering, contact us and define your needs, so we the appropriate configuration may be created for you.

Filter items already displayed on the page

If some items (usually already displayed on the page) are to be left out from the answer recommendation these must be enumerated inside a JavaScript array and passed on to the recommendation request via the itemOnPage parameter:

var _gravity = _gravity || [];
 _gravity.push({
    type: 'recommendation',
    scenarioId: 'ITEM_PAGE',
    numberLimit: 6,
    currentItemId: "843928493",
    callback: callback_fn,
    itemOnPage: [43498274,758399,85493895]
});

Filter items in parallel recommendations

Usually, each recommendation box (widget) has its own scenario identifier. When displaying multiple widgets on the same screen multiple recommendation requests need to be made, one per box/scenario. In this case, it is desirable to avoid the same item appearing multiple times on the screen. This can be achieved by using the groupId, groupSeq and groupSize recommendation request parameters. Set the groupSize parameter to the number of widgets displayed on the page, and use the groupSeq parameter to index the widgets from 1 to groupSize number. The groupId is a string to identify recommendation batches.

var _gravity = _gravity || [];
 _gravity.push({
    type: 'recommendation',
    scenarioId: 'ITEM_PAGE',
    numberLimit: 6,
    currentItemId: "843928493",
    callback: callback_fn,
    groupSize:5,
    groupSeq:4,
    groupId: "testGroup1"
});

The recommendation requests are not made until all widgets recommendation request (groupSeq - 1 to groupSize) are pushed. Be careful when adding/removing widgets to change the groupSize parameter accordingly.

Personalized search results

For personalized search results you should set up the search keywords (searchString) and the filtering parameters, such as filter.categoryId. The pagingOffset parameter can be used for setting up the offset for paging.

var _gravity = _gravity || [];
 _gravity.push({
    type: 'recommendation',
    scenarioId: 'ITEM_PAGE',
    numberLimit: 6,
    currentItemId: "843928493",
    callback: callback_fn,
    searchString: "testWord",
    pagingOffset: 10
});

Privacy-related

To meet privacy regulations (presented by GDPR, for instance) the Gravity JS API provides a way to rid the events and recommendation requests (basically, all data that we receive through the JS API, store, and use for training the algorithms) of all personally identifiable data. This means:

  • Client IP Addresses (these are added to events and recommendation requests by the JS API by default)
  • User identifiers (userId)
  • cookieIds (non-logged in identifiers)

To control this feature, you'll need to place a cookie named "gr_optout", in the following way:

  • Default behavior:
    • No gr_optout cookie present
    • The system sends all data, also the identifiers
  • gr_optout=1
    • gr_optout cookie with a value of "1"
    • Sending all the data, except for the above identifiers
  • gr_optout=0
    • gr_optout cookie with a value of "0"
    • The system sends all data, also the identifiers