Search the Documentations
Categories

Integration Guide

This Custom Integration Guide shows the step-by-step integration of a new store with Releva. Although the guide leads to our detailed API documentation where necessary, we recommend reading the documentation before you start the integration project.

If you have any questions, please contact us by email:

● support@releva.ai

and by phone:

● Georgi: +359878992829

● Yavor: +359886168983

About Releva 

Releva plays the role of CRM or a Customer Data Platform (CDP) for our customers (referred to in this document as the brand or the client). This database collects events related to two important entities: the users and the products. Based on the information collected, Releva allows full automation of the marketing process based on segments, triggers, and cohorts. For example, in the case of a trigger for an abandoned basket the framework sends an automatic message via a channel of choice, or an automatic promotional message with relevant products is sent to the cohort of users with one order in the last two weeks with relevant products for each individual user. 

In order to work correctly, Relеva must receive timely events about the behavior of the users on the trader’s website, as well as any changes in prices, quantities, etc. of the products. Relеva guarantees that all sent data will be available for automation up to 1 minute after the data are accepted from our API.

Integration with Releva

Integration with Relеva involves the sending of events (API requests) by the online shop to Relеva for two types of profiles: anonymous and registered.

 Anonymous profiles are identified on the basis of the tool with which they access the trader’s website, such as phone, internet browser, etc. Actions are saved in the Relеva database and connected to an identifier related to the access tool that we keep in a first-party cookie. After registration of the user, all events connected to the anonymous account will be linked (moved) to the registered account.

 Relеva recognizes two types of registered accounts: first, accounts that have consented to marketing, and secondly, accounts that have not given such consent. Consent can be given in general for all marketing channels or for specific channels such as email, SMS, web push, etc.

It should be considered that without consent users will not receive marketing messages concerning push channels. These include, for example, emails, SMS, and web push messages. Information on the trader’s website, such as banners and recommendations on the home, product, category, basket and other pages will be delivered without the user’s consent after providing consent for first-party cookies.

In this document, we will describe all the pages where Relеva has to be integrated into the case of a custom integration/project.

This integration guide will help you get up and running with the Releva service in a few easy steps.

A full Releva Integration consists of the following:

  1. Web Tracking – to track user behavior. You may choose to set up client-side (web) or server-side tracking. Currently, we provide a JavaScript SDK which makes the web frontend integration a breeze. For other use cases where the frontend integration is not an option, you may consider the server-side integration approach.
  2. Sync APIs – to send product updates whenever a change in your catalogue occurs, and sync products periodically to ensure Releva know about changes that have happened even if you don’t send product updates for whatever reason. These APIs are optional but implementing them is highly recommended as it will help keep personalized content up-to-date with your catalogue.
  3. GDPR APIs – to subscribe and unsubscribe from marketing communication, to fulfill GDPR data access requests, and to fulfill GDPR data deletion requests.

Front-end Library

Front-end integration is implemented using a JavaScript library supplied by Relеva. The library works with cookies and in order to comply with the GDPR, the store should use the library only for users who have given such consent.

You can add the library to the end of the body tag of the HTML in the following way:

<script async type="text/javascript" src="https://releva.ai/sdk/v0/js/releva-sdk-js.min.js" onload="document.dispatchEvent(new Event('relevaSdkLoaded'));"></script>

The onload option and the document.addEventListener(…) function ensure that the Releva.push (…) query is executed after the JavaScript library is loaded. This technical detail is only a suggestion, you can use other ways to implement this strategy, the important thing is to follow the sequence described above.

Once the page has loaded, the following request must be made to Releva’s API through the library.

document.addEventListener('relevaSdkLoaded', function() {
  Releva.push("<AccessToken>", {
    "cart": {
      "products": [
        {
          "id": "1",
          "price": 10,
          "currency": "BGN",
          "quantity": 2,
        }
      ]
    },
    "profile": {
      "firstName": "Georgi",
      "lastName": "Georgiev",
      "email": "georgi@releva.ai",
      "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
    },
    "page": {
   "token”: "<PageToken>",
   "locale": "bg"
  }
  }, function(results) {
    // TODO: handle visualisation of product recommendations and banners
    console.log(results);
  }, function (error) {
    // TODO: handle error
    console.log(error);
  });
});

Important aspects here are the public access tokens for the API (Access Token) and the token on the relevant page (Page Token), for example, the Home page has the following token 96f15993-9feb-4f7c-871e-b380aca63b85 (see below).

Page tokens

Releva comes pre-loaded with the most commonly used pages and recommenders per page. The tokens on the individual pages can be taken from the admin interface of Releva. The token is located at the top right of the name of each page.

Tokens for sending and receiving data

To send data from the front end (and receive data accordingly), use ‘Shop Access Token’ (in short, AccessToken). For requests to the Releva’s API from the Back Еnd, you will mainly use the ‘Shop Secret Key’ (in short, SecretKey).

A Back-end request is used to confirm a paid basket, give and remove consent to receive marketing messages.

Receiving GDPR related information about what data has been collected for an account and deleting all data for an account is also done with a backend request to Releva’s API.

Back-end requests are also available to update and add products to the product catalog. See more in our documentation here.

Details about the integration of the product catalog, basket, giving and removing consent, and GDPR are described in separate chapters of this guide.

Quality assurance

Add the rlv_mode=debug parameter this way:

https://myshop.com?rlv_mode=debug

to view in the browser console the full set of information that is sent to Releva. E.g:

The page object is located inside the context object that was sent with a front-end push request to Releva. Inside contextyou can also see the profile object, user profileID, session ID, and more parameters (see above).

In debug mode, you will be able to monitor all recommendations and banners in Releva’s response object, regardless of whether they were switched on in the Admin Interface. E.g:

Response on each page

On each page, Releva returns results for recommenders and banners. For example, on the home page of https//demo.releva.ai (demo store integrated with Releva), we return the results object that contains:

{
  "recommenders": [
    {
      "token": "916c829e-c1eb-4f49-81ec-106ab8471f3b",
      "name": "Trending from This Category",
      "meta": {
        "algorithm": "hot"
      },
      "tags": ["t1, "t2"],
      "response": [
        {
          "available": true,
          "categories": [
            "cat1"
          ],
          "createdAt": "2019-08-18T05:48:42.419Z",
          "currency": "BGN",
          "custom": {
            "string": [
              {
                "values": [
                  "bar"
                ],
                "key": "f"
              }
            ]
          },
          "data": {
            "foo": "bar"
          },
          "description": "Some Description",
          "discount": 0,
          "discountPercent": 0,
          "discountPrice": 0,
          "id": "3847012384816",
          "imageUrl": "https://cdn.shopify.com/s/files/1/0263/8328/6320/products/yes-me-me-me-me_286x381.jpg?v=1565038619",
          "listPrice": 2500,
          "locale": "bg",
          "mergeContext": {
            "rid": "...",
            "rpid": "..."
          }
          "name": "Test Product",
          "price": 2500,
          "publishedAt": "2019-12-25T12:41:30.457Z",
          "updatedAt": "2019-12-25T12:41:30.457Z",
          "url": "https://releva-dev.myshopify.com/products/test-product?rlv_rid=916c829e-c1eb-4f49-81ec-106ab8471f3b",
        }
      ]
    },
    ...
  ],
  "banners": [
    {
      "token": "9f4625ea-4ef1-4503-b55c-f11c13e25a60",
      "name": "Test Banner",
      "html": "<html>\n  Hello World!\n</html>",
      "tags": ["t1", "t2"],
      "mergeContext": {
        "bid": "..."
      }
    },
    ...
  ]
}

A successful push query results in an HTTP status code 200. The data can be used directly to display the products and banners on the trader’s website. 

You can customize the display of banners and recommenders using tags that you add through the admin interface of Releva, here is an example:

You can use the labels in the Front-end, for example:

tags.indexOf('popover') !== -1

Different recommenders are displayed on different pages and in different places on the page. On the home page, this place would be the first 30% of the page. On the product page, the place is directly under the product in focus. For these user cases, we will use the highlight recommended mode (see below). Recommender modes are configurable via Releva Admin. In Highlight mode Releva can return products that already exist on the page.

If the above behavior is unwanted, then Discover mode is used. In this mode, products that are already on a page are removed from the results returned by the Releva. Note that products that repeat in the results returned by Releva (for instance Releva may return two recommendation result sets and some products may equal) are not filtered for the purpose of system performance.

There are custom cases that require the use of re-ordering (according to the recommendation algorithm) of products returned by the system, for example, with full-text search results or re-arrangement of all products we want to show on a page. Then we will use Re-rank mode and show the products accordingly in the current HTML structure and behavior.

A screenshot of how to adjust the recommender’s mode in the admin interface of Releva is given below.

Home page

On the home page, we usually send the cart, profile, and attributes associated with the page:

document.addEventListener('relevaSdkLoaded', function() {
  Releva.push("<AccessToken>", {
     "cart": {
      "products": [
        {
          "id": "1",
          "price": 10,
          "currency": "BGN",
          "quantity": 2,
        }
      ]
    },
    "profile": {
      "firstName": "Georgi",
      "lastName": "Georgiev",
      "email": "georgi@releva.ai",
      "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
    },
    "page": {
    "token”: "96f15993-9feb-4f7c-871e-b380aca63b85",
    "locale": "bg"
  } 
}, function(results) {
    // TODO: handle visualisation of product recommendations and banners
    console.log(results);
  }, function (error) {
    // TODO: handle error
    console.log(error);
  });
});

If the profile is not registered, remove the profile object. The cart object is sent from each page so that Releva can monitor the current cart products at all times. More about the basket object in our API documentation. The page object token is used by Releva to return recommendations and banners for the respective page.

On the category page

The relevant category is sent for each of the category pages as a list of categories in the page object. E.g:

document.addEventListener('relevaSdkLoaded', function() {
    Releva.push("<AccessToken>", {
        "cart": {
            "products": [{
                "id": "1",
                "price": 10,
                "currency": "BGN",
                "quantity": 2,
            }]
        },
        "profile": {
            "firstName": "Georgi",
            "lastName": "Georgiev",
            "email": "georgi@releva.ai",
            "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
        },
        "page": {
            "token": "ef2bbc61 - 8 c9d - 4 ea4 - b3b2 - 6 b4a81463d69",
            "locale": "bg",
            "categories": ["Clothes for boys"]
        }
    }, function(results) {
        // TODO: handle visualisation of product recommendations and banners
        console.log(results);
    }, function(error) {
        // TODO: handle error
        console.log(error);
    });
});

We add the field categories to the page object to indicate the category we are browsing at the moment. The page token has also been replaced with the category page token.

When we create recommenders, we will use categories to filter the results of the recommenders to show only the products from that category. For example, if we want to show products with the recommender ‘Recommended for you‘ but limited only to the category ‘Clothes for boys’ we will use a filter (i.e. included in the admin interface of Releva) by page contextPage context is exactly the page object that is sent on each page.

Very often on the page of the category, the trader’s website has filters by brand, size, color and others. Releva enables recommendations to be filtered by these fields by adding a custom entity. For example, if the user has selected the Adidas brand from the filters, the following request must be sent to Releva:

document.addEventListener('relevaSdkLoaded', function() {
    Releva.push("<AccessToken>", {
        "cart": {
            "products": [{
                "id": "1",
                "price": 10,
                "currency": "BGN",
                "quantity": 2,
            }]
        },
        "profile": {
            "firstName": "Georgi",
            "lastName": "Georgiev",
            "email": "georgi@releva.ai",
            "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
        },
        "page": {
            "token": "ef2bbc61 - 8 c9d - 4 ea4 - b3b2 - 6 b4a81463d69",
            "locale": "bg",
            "categories": ["Clothes for boys"]
        }
    }, function(results) {
        // TODO: handle visualisation of product recommendations and banners
        console.log(results);
    }, function(error) {
        // TODO: handle error
        console.log(error);
    });
});

You can add the custom filed by opening any recommender and then clicking on the custom rule button.

Then in the form select the corresponding custom field (brand in our case):

The custom field will become visible. The presence of a custom brand object would allow us to filter by brand the results of any recommender in the admin interface of Releva. E.g:

The product page

On the product page, we send an additional product object. Here is an example: 

document.addEventListener('relevaSdkLoaded', function() {
  Releva.push('<accessToken>', {
    cart: {
      products: [{
        id: '1',
        price: 10,
        currency: 'BGN',
        quantity: 2
      }]
    },
    profile: {
      firstName: 'Georgi',
      lastName: 'Georgiev',
      email: 'georgi@releva.ai',
      registeredAt: 'YYYY-mm-ddT00:00:00.000Z'
    },
    page: {
      token: '<pageToken>',
      locale: 'bg',
      categories: ['Clothes for boys/Winter jackets'],
      custom: {
        string: [{
          key: 'brand',
          values: ['Adidas']
        }]
      }
    },
    product: {
      id: '12345'
    }
  }, function(results) {
    // TODO: handle visualisation of product recommendations and banners
    console.log(results);
  }, function(error) {
    // TODO: handle error
    console.log(error);
  });
});

Sending the product results in a ProductView event in Releva. In addition, Releva uses the product ID to return recommenders for this page, such as ‘Viewed this viewed that’. This recommender returns products in collaborative filtering mode – people who have looked at this product have also looked at these other products.

If products have options or variants such as color or size, a reference should be sent to Releva when the user changes the selected color or size with an additional custom field like this: 

document.addEventListener('relevaSdkLoaded', function() {
    Releva.push("<AccessToken>", {
        "cart": {
            "products": [{
                "id": "1",
                "price": 10,
                "currency": "BGN",
                "quantity": 2,
            }]
        },
        "profile": {
            "firstName": "Georgi",
            "lastName": "Georgiev",
            "email": "georgi@releva.ai",
            "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
        },
        "page": {
            "token": "ef2bbc61 - 8 c9d - 4 ea4 - b3b2 - 6 b4a81463d69",
            "locale": "bg",
            "categories": ["Clothes for boys"],
            "custom": {
                "string": [{
                    "key": "brand",
                    "values": [
                        "Adidas"
                    ]
                }]
            }
        }
    }, function(results) {
        // TODO: handle visualisation of product recommendations and banners
        console.log(results);
    }, function(error) {
        // TODO: handle error
        console.log(error);
    });
});

The custom field size is saved as part of the fields we keep for the user and so Releva keeps track of the user’s favorite sizes. Note that the system keeps up to 20 of the last products viewed and added to the basket, and their attributes.

With this information, it is possible to filter the recommended products by the user’s favorite sizes. For example:

When the user adds a specific product with respective color to the basket, the following request is sent: 

document.addEventListener('relevaSdkLoaded', function() {
    Releva.push("<AccessToken>", {
        "cart": {
            "products": [{
                "id": "1",
                "price": 10,
                "currency": "BGN",
                "quantity": 2,
                "custom": {
                    "string": [{
                            "key": "size",
                            "values": ["10 years"]
                        },
                        {
                            "key": "colour",
                            "values": ["red"]
                        },
                    ]
                }
            }]
        },
        "profile": {
            "firstName": "Georgi",
            "lastName": "Georgiev",
            "email": "georgi@releva.ai",
            "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
        },
        "page": {
            "token": "ef2bbc61-8c9d-4ea4-b3b2-6b4a81463d69",
            "locale": "bg",
            "categories": ["Clothes for boys"],
            "custom": {
                "string": [{
                    "key": "brand",
                    "values": [
                        "Adidas"
                    ]
                }]
            }
        },
        "product": {
            "id": "12345",
            "custom": {
                "string": [{
                    "key": "size",
                    "values": [
                        "10 years"
                    ]
                }]
            }
        }
    }, function(results) {
        // TODO: handle visualisation of product recommendations and banners
        console.log(results);
    }, function(error) {
        // TODO: handle error
        console.log(error);
    });
});

The cart page

On the basket page, we send the full set of products to the current basket:

document.addEventListener('relevaSdkLoaded', function() {
    Releva.push("<AccessToken>", {
        "cart": {
            "products": [{
                    "id": "1",
                    "price": 10,
                    "currency": "BGN",
                    "quantity": 2,
                    "custom": {
                        "string": [{
                                "key": "sex",
                                "values": ["girl"]
                            },
                            {
                                "key": "size",
                                "values": ["4-years"]
                            },
                        ]
                    }
                },
                {
                    "id": "2",
                    "price": 60,
                    "currency": "BGN",
                    "quantity": 1,
                    "custom": {
                        "string": [{
                                "key": "sex",
                                "values": ["girl"]
                            },
                            {
                                "key": "size",
                                "values": ["18"]
                            },
                        ]
                    }
                }
            ]
        },
        "profile": {
            "firstName": "Georgi",
            "lastName": "Georgiev",
            "email": "georgi@releva.ai",
            "registeredAt": "YYYY-mm-ddT00:00:00.000Z"
        },
        "page": {
            "token": "ef2bbc61-8c9d-4ea4-b3b2-6b4a81463d69",
            "locale": "bg"
        }
    }, function(results) {
        // TODO: handle visualisation of product recommendations and banners
        console.log(results);
    }, function(error) {
        // TODO: handle error
        console.log(error);
    });
});

The cart object has multiple parameters that you can review in our documentation.

 In some cases, some shops directly delete a basket (for example, upon login or log out) and create a new, empty one. In this situation, send an empty basket, like this:

...
"cart": {
  "products": []
},
...

When the user removes the last product from their current shopping cart and it is deleted from the store, send an empty cart as follows:

...
"cart": {
  "products": []
},
...

When removing a product from the cart or changing the quantity of a product, always send the current status every time you change. Releva will automatically remove and add the relevant products and in addition, add Cart Create and CartAdd/CartRemove events to the user’s history.

Upon confirmation that the basket has been paid, the following API call must be sent on the backend side:

curl -H 'content-type: application/json'  -H 'authorization: Bearer <secretKey>' -XPOST https://releva.ai/api/v0/carts -d'{
  "carts": [
    {
      "email": "user@email.com",
      "orderId": "orderId1",
      "cartPaid": true,
      "products": [{
              "id": "1",
              "price": 10,
              "currency": "BGN",
              "quantity": 2,
              "custom": {
               "string": [{
                    "key": "size",
                    "values": ["10 years"]
                },
                {
                    "key": "colour",
                    "values": ["red"]
                }]
            }
        }]
    }
  ]
}'

Note that orderId and cartPaid=true are sent. More information about the request here.

After cartUpdate and orderId are sent, Releva assumes that the current basket is paid and closed.

If you’re sending marketing emails or SMSs and the purchase doesn’t include the standard purchase method, always send a CartUpdate back-end request. It is important for Releva to know that a basket has been purchased and so to cancel any abandoned basket messages.

Unsubscribe/subscribe for marketing messages

This is probably the most important page in the store. It must communicate with a centralized database that holds recent user information. When consent is given in a transaction, it must be saved in the database and also sent to Releva. The other option is to configure triggers or other functions in the database so that any changes in the consent table are also sent over to Releva always. The request is sent from the back-end and uses secretKey with the subscriptions being optional (send only if you have multiple different lists), and unsubscribeLink also being optional (only send if you have different unsubscribe urls for different users, if there is a common unsubscribe url, you don’t need to send it). Here is an example:

curl -H 'content-type: application/json' -H 'authorization: Bearer <secretKey>' -XPOST https://releva.ai/api/v0/subscribe -d'
{ 
"email": "support@releva.ai", 
"subscriptions": ["email", "SMS"] ,
"unsubscribeLink": "..."
}'

Consent can be one for all marketing and transaction channels or by labels that can be used to segment users. This is how you can make a segment in which users provided consent to email and SMS messages.

Labels can be related to channels, but they can have other, different semantics. For example, a user can subscribe to transactional messages such as when their shipment will arrive and not for marketing messages. In addition, you may want a call for weekly SMS discounts. In this situation, we may have the following labels:

  1. Email-transactional – subscribed
  2. SMS-weekly-discounts – subscribed
  3. Email-marketing – not-subscribed 

In this situation, the following request must be sent:

curl -H 'content-type: application/json' -H 'authorization: Bearer <secretKey> -XPOST https://releva.ai/api/v0/subscribe -d'{ "email": "support@releva.ai", "subscriptions": ["email-transactional", "SMS-weekly-discounts"] , "unsubscribeLink": "..."}'

To unsubscribe a user, the following request must be sent:

curl -H 'content-type: application/json' -H 'authorization: Bearer <secretKey> -XPOST https://releva.ai/api/v0/unsubscribe -d'{ "email": "support@releva.ai"] }'

Synchronizing products

All products must be synchronized in a timely manner between the customer database and the Releva product catalog. This is necessary in order for Releva to always return products with current prices, quantities, etc. A request from the back-end is used as follows:

curl -H 'content-type: application/json' -H 'authorization: Bearer <secretKey>' -XPOST https://releva.ai/api/v0/products -d'{
  "products": [
    {
      "id": "productId1",
      "name": "Test Product",
      "description": "Some Description",
      "locale": "en",
      "currency": "USD",
      "listPrice": 12.5,
      "discountPrice": 10.99,
      "categories": [
        "men/shoes/hiking"
      ],
      "available": true,
      "url": "https://my-awesome-shop/products/productId1",
      "imageUrl": "https://cdn.my-awesome-shop/products/productId1_img1.png",
      "publishedAt": "2019-06-19T23:45:56"
    }
  ]
}'

More information in our API documentation.

Support for the General Data Protection Regulation (GDPR)

Releva supports GDPR. The system offers several APIs for working with user data.

To obtain the information that Releva has collected for a user, use the request below:

curl -H 'authorization: Bearer <secretKey>' https://releva.ai/api/v0/trackedData?profileId=<profileId>
curl -H 'authorization: Bearer <secretKey>' https://releva.ai/api/v0/trackedData?email=<email>

More information can be found in our documentation .

Your users may request to delete their data according to GDPR. Again, the easier way is directly through the JavaScript library, for example:

curl -H 'authorization: Bearer <secretKey>' -XDELETE https://releva.ai/api/v0/profiles?profileId=<profileId>
curl -H 'authorization: Bearer <secretKey>' -XDELETE https://releva.ai/api/v0/profiles?email=<email>

More information in our documentation.

Sometimes the user may want detailed information about the cookies that Releva collects. You can get this information in the front end via the JavaScript library like this:

Releva.cookiesUsed();

More information about this functionality can be found in our documentation.

Registration of Service Workers

If you want to send web push notifications you need to download and save service-worker.min.js in the root directory of your website. You can change the name but you must change the name of the library during registration (see the example).

The following object must be added to each request to Releva from the Front-end:

document.addEventListener('relevaSdkLoaded', function() {
  Releva.push("<yourAccessToken>", {
  ...
  }, function(results) {
    ...
  }, function (error) {
    ...
  },
  // add this to register the service worker
  // please make sure you use the correct name here if you renamed the file
  // keep in mind this needs to point to the root of your domain
  {
    serviceWorkerUrl: '/service-worker.min.js'
  });
});
Next Front End Integration
Table of Contents