Skip to content

Working with notifications

Notifications can be described as data containing visitor interactions that is sent into Elevate during a visitor session. Notifications are used to gather statistics, enable personalisation, and improve Elevate functionality such as recommendations and search results.

Notifications are primarily sent client side. This is to avoid loss of data due to new server side content requests. All notification types can be sent server side, however only payment notifications are recommended to be made as server side operations.

The set-up of notifications is thus a crucial activity to make sure that Elevate performs at its best and delivers the best possible content to visitors.

Set-up

To be able to send notifications into Elevate there must first be something for visitors to interact with. This means that an integration including defined level of personalisation, published panels, imported data entity types, and markets must be available in a development environment. Essentially, everything needed to perform a panel query and receive a result.

The JavaScript library has methods to perform a panel query and to render Elevate content with tickets, the most common thing to include in a notification.

What to notify

The more notifications sent into Elevate, the more Elevate will learn from the visitor behavior and provide better content as result. All content generated by Elevate includes a unique ticket that is primarily the only thing that needs to be notified if the API object is correctly instantiated.

Always notify Elevate when clicks are made on Elevate content such as products and ads. Notifying clicks on categories is not necessary. The adding-to-cart notification types should only be used to notify interactions with the products Elevate entity.

Notification type Description
Click To be sent when a visitor clicks on Elevate entities with tickets in panels, e.g. ads, products, and categories (when a ticket is present).
Non-eSales click To be sent when a visitor clicks on a product or variant not returned by Elevate (i.e. not having a ticket).
Adding-to-cart To be sent when a visitor adds a product or variant to their cart.
Non-eSales adding-to-cart To be sent when a visitor adds a product or variant not returned by Elevate (i.e. not having a ticket) to their cart.
Add favorite To be sent when a visitor have marked a product or a variant as a favorite.
Remove favorite To be sent when a visitor have unmarked a product or a variant as a favorite.
Secure payment To be sent when a visitor has placed and paid for an order. This is the recommended payment notification to use.
Payment To be sent when a visitor has placed and paid for an order. The Secure payment notification is recommended to use.
End When using a high level of personalisation it is not recommended to use the End notification.

Tickets

All content that is rendered by Elevate, such as products and ads, have a unique string identifying them called a ticket. Tickets are generated automatically by Elevate and include encoded information about the rendered item, its panel path, and more. Below is an example of a ticket returned as part of a panel result JSON.

{
    "ticket": "Oy9keW5hbWljLXBhZ2VzL3N0YXJ0L2VzYWxlcy1zdGFydC0xOyM7cHJvZHVjdF9rZXk7UF8xMjUzODMtMDAxNF9VSzsjOztOT05FOk5PTkU7NjE7"
}

Tickets should not be cached and reused in more than one panel as they are based on context and are connected to their originating panel.

How to notify

Notifications, apart from payment notifications, are to be made client side via the JavaScript library. This is to avoid loss of data due to new server side content requests. Payment notifications are to be made server side with the Restful API.

Notification type Recommended use RESTful API v2 RESTful API v1
Click Client side End point End point
Non-eSales click Client side End point End point
Adding-to-cart Client side End point End point
Non-eSales adding-to-cart Client side End point End point
Add favorite Client side End point End point
Remove favorite Client side End point End point
Secure payment Server side End point End point
Payment Server Side End point End point
End session Client side End point End point

Notifying client side

Different Web API and JavaScript library versions

Implementation and requirements differ between Web API v2 and Web API v1. For more information, see the respective pages for the Web API v2 JavaScript library and the Web API v1 JavaScript library.

Voyado recommends using the Web API v2.

When notifying client side it is highly recommended to always instantiate the API object as a constant. A session key and a customer key token is automatically generated (if not already present) and stored in cookies when the object is instantiated.

Instantiate API object

All examples have instantiated the API object as a constant, api.

const api = window.esalesAPI({ market: '{market}', clusterId: '{cluster-id}' });
const api = window.apptus.esales("{cluster-id}", "{market}");

Click notification

api.notify.click("{ticket}");
api.notifyClick("{ticket}");

Non-eSales click notification

// send with productKey
api.notify.nonEsalesClick({ productKey: '{product_key_1}' });

// send with variantKey
api.notify.nonEsalesClick({ variantKey: '{variant_key_1}'});

// send with both productKey and variantKey
api.notify.nonEsalesClick({ productKey: '{product_key_2}', variantKey: '{variant_key_2}' });
// send with productKey
api.notifyNonEsalesClick("{product_key_1}");

// send with variantKey
api.notifyNonEsalesClick("{variant_key_1}");

// send with both productKey and variantKey
api.notifyNonEsalesClick("{product_key_2}", "{variant_key_2}");

Adding-to-cart notification

api.notify.addToCart('{ticket}');
api.notifyAddingToCart("{ticket}");

Non-eSales adding-to-cart notification

// Send with productKey
api.notify.nonEsalesAddToCart({ productKey: '{product_key_1}'});

// Send with variantKey
api.notify.nonEsalesAddToCart({ variantKey: '{variant_key_1}'});

// Send with both productKey and variantKey
api.notify.nonEsalesAddToCart({ productKey: '{product_key_2}', variantKey: '{variant_key_2}' });
// Send with productKey
api.notifyNonEsalesAddingToCart("{product_key_1}");

// Send with variantKey
api.notifyNonEsalesAddingToCart("{variant_key_1}");

// Send with both productKey and variantKey
api.notifyNonEsalesAddingToCart("{product_key_2}", "{variant_key_2}");

Add favorite notification

// send with both productKey and variantKey and adds as favorite
api.notify.addFavorite({ productKey: '{product_key_1}', variantKey: '{variant_key_1}' });

// sends with variantKey and adds as favorite
api.notify.addFavorite({ variantKey: '{variant_key_1}' });

// sends with productKey and adds as favorite
api.notify.addFavorite({ productKey: '{product_key_2}' });
// The Add favorite notification cannot be sent with the JavaScript API
// for Web API v1.

Remove favorite notification

// send with both productKey and variantKey and removes as favorite
api.notify.removeFavorite({ productKey: '{product_key_1}', variantKey: '{variant_key_1}' });

// sends with variantKey and removes as favorite
api.notify.removeFavorite({ variantKey: '{variant_key_1}' });

// sends with productKey and removes as favorite
api.notify.removeFavorite({ productKey: '{product_key_2}' });
// The Remove favorite notification cannot be sent with the JavaScript API
// for Web API v1.

Payment notification

Client side payments disabled by default

This payment notification method does not require any authentication and is disabled by default. It is recommended to use the Secure payment notification. Contact Voyado Support if there is a need to enable unauthenticated payment notifications.

var payment = api.notify.payment();

// Add 2 items with productKey
payment.add({
    productKey: '{product_key_1}',
    quantity: 2,
    unitSellingPrice: 99.90
});

// Add 5 items with variantKey
payment.add({
    variantKey:'{variant_key_1}',
    quantity: 5,
    unitSellingPrice: 165
});

// Add 1 item with both productKey and variantKey
payment.add({
    productKey:'{product_key_2}',
    variantKey:'{variant_key_2}',
    quantity: 1,
    unitSellingPrice: 150.00
});

payment.send();
var payment = api.newPaymentNotification();

// Add 2 items with productKey
payment
    .addProduct("{product_key_1}")
    .quantity(2)
    .unitSellingPrice(99.90);

// Add 5 items with variantKey
payment.addVariant("{variant_key_1}")
    .quantity(5)
    .unitSellingPrice(165.00);

// Add 1 item with both productKey and variantKey
payment.addProductWithVariant("{product_key_2}", "{variant_key_2}")
    .quantity(1)
    .unitSellingPrice(150.00);

payment.send();

End session notification

api.notify.end();
api.endSession();

Notifying server side

All notifications can be sent server side via the RESTful API. However all notifications except for payment notifications are recommended to be sent client side. Voyado Elevate RESTful API includes two different payment notification methods. The recommended notification method to use is Secure payment notification.

Secure payment notification

The Secure payment notification enables the product attribute cost to be sent in a notification to Elevate. The attribute cost is important for both statistics as well as for Exposure strategies. If cost is not available it should not be included in the notification.

Web API v2
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace payment
{
    class SecurePaymentExample
    {
        static void Main(string[] args) {
            SendAsync().Wait();
        }
        static async Task SendAsync()
        {
            String url = "https://{cluster-id}.api.esales.apptus.cloud/api/v2/notifications/payment";
            // Query parameters
            String customerKey = "{customer_key}";
            String sessionKey = "{session_key}";
            String market = "{market}";

            // Payment information
            String content = 
                @"{
                    'lines':[{ 
                    'productKey': 'P1',
                    'variantKey': 'V1',
                    'sellingPrice': 99.0,
                    'quantity': 2,
                    'cost': 33.0 }]
                }";
                // Add new lines for each different item in the order

            using (HttpClient client = new HttpClient())
            {
                using(HttpRequestMessage request = new HttpRequestMessage() {
                    RequestUri = new Uri(String.Format("{0}?esales.customerKey={1}&esales.sessionKey={2}&esales.market={3}",url, customerKey, sessionKey, market)),
                    Method = HttpMethod.Post
                }) {
                    request.Content = new StringContent(content, Encoding.UTF8);
                    // Set the required Api-Key header as this is a protected resource
                    request.Headers.Add("Api-Key", "{API-KEY}");
                    HttpResponseMessage response = await client.SendAsync(request);

                    if(Math.Floor((int)response.StatusCode / 100.0) != 2) {
                        // Return error information if things go wrong
                        Console.WriteLine(await response.Content.ReadAsStringAsync());
                    }
                }
            }
        }
    }
}
// This example uses the Jersey Client for RESTful Web Services 
// Any HTTP or REST client library can be used
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class SecurePaymentExample {
    public static void main(String[] args) {
        Client client = ClientBuilder.newClient();

        WebTarget target = client
                .target("https://{cluster-id}.api.esales.apptus.cloud")
                .path("/api/v2/notifications/payment")
                // Query parameters
                .queryParam("esales.customerKey", "{customer_key}")
                .queryParam("esales.sessionKey", "{session_key}")
                .queryParam("esales.market", "{market}");

        Response response = target.request()
                                  // Set the required Api-Key header as this is a protected resource
                                  .header("Api-Key", "{API-KEY}")
                                  // Payment information
                                  .post(Entity.entity(
                                          "{"
                                          + "'lines':[{ "
                                          + "'productKey': '{product_key_1}',"
                                          + "'variantKey': '{variant_key_1}',"
                                          + "'sellingPrice': 99.0,"
                                          + "'quantity': 2,"
                                          + "'cost': 33.0 }]"
                                          + "}", MediaType.TEXT_PLAIN
                                          // Add new lines for each different item in the order
                                   ));

        int responseCode = response.getStatus();

        if (Math.floor(responseCode / 100) != 2) {
            // Return error information if things go wrong
            System.out.println(response.readEntity(String.class));
        }
    }
}
<?
// Query parameters
$customerKey = '{customer_key}';
$sessionKey = '{session_key}';
$market = '{market}';

// Payment information
$paymentInformation = json_encode([
    'lines' => [
        ['productKey' => '{product_key_1}',
        'variantKey' => '{variant_key_1}',
        'sellingPrice' => 99.0,
        'quantity' => 2,
        'cost' => 33.0]
    ]
    // Add new lines for each different item in the order
]);

// Set the required Api-Key header as this is a protected resource
$headers = array('Api-Key: {API-KEY}', 'Content-Type: application/json');

$url = 'https://{cluster-id}.api.esales.apptus.cloud/api/v2/notifications/payment';

$ch = curl_init($url . '?esales.customerKey=' . $customerKey . '&esales.sessionKey=' . $sessionKey . '&esales.market=' . $market);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $paymentInformation);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (floor($responseCode / 100) !=  2) {
    // Return error information if things go wrong
    echo curl_getinfo($ch);
}

curl_close($ch);
?>

Payment notification

This payment notification method does not require any authentication and cannot notify cost. It is recommended to use the Secure payment notification.

Web API v2
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace payment
{
    class PaymentExample
    {
        static void Main(string[] args) {
            SendAsync().Wait();
        }
        static async Task SendAsync()
        {
            String url = "https://{cluster-id}.api.esales.apptus.cloud/api/v2/notifications/payment";
            // Query parameters
            String customerKey = "{customer_key}";
            String sessionKey = "{session_key}";
            String market = "{market}";

            // Payment information
            String content = 
                @"{
                    'lines':[{ 
                    'productKey': '{product_key_1}',
                    'variantKey': '{variant_key_1}',
                    'sellingPrice': 99.0,
                    'quantity': 2 }]
                }";
                // Add new lines for each different item in the order

            using (HttpClient client = new HttpClient())
            {
                using(HttpRequestMessage request = new HttpRequestMessage() {
                    RequestUri = new Uri(String.Format("{0}?esales.customerKey={1}&esales.sessionKey={2}&esales.market={3}",url, customerKey, sessionKey, market)),
                    Method = HttpMethod.Post
                }) {
                    request.Content = new StringContent(content, Encoding.UTF8);
                    HttpResponseMessage response = await client.SendAsync(request);

                    if(Math.Floor((int)response.StatusCode / 100.0) != 2) {
                        // Return error information if things go wrong
                        Console.WriteLine(await response.Content.ReadAsStringAsync());
                    }
                }
            }
        }
    }
}
// This example uses the Jersey Client for RESTful Web Services 
// Any HTTP or REST client library can be used
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

public class PaymentExample {
    public static void main(String[] args) {
        Client client = ClientBuilder.newClient();

        WebTarget target = client
                .target("https://{cluster-id}.api.esales.apptus.cloud")
                .path("/api/v2/notifications/payment")
                // Query parameters
                .queryParam("esales.customerKey", "{customer_key}")
                .queryParam("esales.sessionKey", "{session_key}")
                .queryParam("esales.market", "{market}");

        Response response = target.request()
                                  // Payment information
                                  .post(Entity.entity(
                                          "{"
                                          + "'lines':[{ "
                                          + "'productKey': '{product_key_1}',"
                                          + "'variantKey': '{variant_key_1}',"
                                          + "'sellingPrice': 99.0,"
                                          + "'quantity': 2 }]"
                                          // Add new lines for each different item in the order
                                          + "}", MediaType.TEXT_PLAIN
                                  ));

        int responseCode = response.getStatus();

        if (Math.floor(responseCode / 100) != 2) {
            // Return error information if things go wrong
            System.out.println(response.readEntity(String.class));
        }
    }
}
<?php
// Query parameters
$customerKey = '{customer_key}';
$sessionKey = '{session_key}';
$market = '{market}';

// Payment information
$paymentInformation = json_encode([
    'lines' => [
        ['productKey' => '{product_key_1}',
        'variantKey' => '{variant_key_1}',
        'sellingPrice' => 99.0,
        'quantity' => 2]
    ]
    // Add new lines for each different item in the order
]);

$headers = array('Content-Type: application/json');

$url = 'https://{cluster-id}.api.esales.apptus.cloud/api/v2/notifications/payment';

$ch = curl_init($url . '?esales.customerKey=' . $customerKey . '&esales.sessionKey=' . $sessionKey . '&esales.market=' . $market);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $paymentInformation);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$response = curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if (floor($responseCode / 100) !=  2) {
    // Return error information if things go wrong
    echo curl_getinfo($ch);
}

curl_close($ch);
?>

Best practice

The following are recommendations when implementing notifications to a site with Elevate.

Recommendation Reason
Always instantiate the API object. Instantiation of the API object enables automatic inclusions of attributes for market, customerKey, and sessionKey.
Always include market in a notification Behavior data is grouped by market. Notifications will fail without the market attribute. Instantiate the API object to include it in every notification.
Always send notifications when clicks are made on Elevate content. Clicks are used for things such as statistics and to improve Elevate algorithms.
Always send a notification when a product is added to cart. Use the Adding to cart notification with Elevate content. Products added to carts affect statistics, algorithms, and what products that are displayed in various panels.
Always notify purchased carts as they happen using the Secure payment notification. Purchased products affect statistics, algorithms, and what products that are displayed in various panels.
Always notify quantity, sellingPrice, and cost for each purchased item in a cart. Correct notifications for purchased items are needed for statistics for conversion, revenue, and profit. If the cost of an item is not available, do not include the cost in the notifications.

The following are common issues that are related to implementing notifications to a site with Elevate.

Issue Probable cause Solution suggestion
There is a large amount of untraceable conversions in the Business app. Can be different causes. Caching of data such as sessionKey and customerKey may be present all the way through to the check out page and the payment notification. The purchase origin may come from an area where the product data is not generated by Elevate, or the purchase may also take place over several sessions. Look into how caching is configured and make sure sessionKey and customerKey is not cached. Make sure that Elevate generates product data wherever possible.
Profit cannot be calculated. Profit requires both sellingPrice and cost to be present in a payment notification. Use the Secure payment notification and include both sellingPrice and cost together with productKey and/or variantKey in the notification.
Panel statistics show zero or a very low amount of clicks. Click notifications have not been implemented correctly for all panels. Verify that all Elevate content that supports click notifications have click notifications.
×
Copyright

This online publication is intellectual property of Voyado Lund AB. Its contents can be duplicated in part or whole, provided that a copyright label is visibly located on each copy and the copy is used in conjunction with the product described within this document.

All information found in these documents has been compiled with utmost attention to detail. However, this does not guarantee complete accuracy. Neither Voyado Lund AB nor the authors shall be held liable for possible errors or the consequences thereof.

Software and hardware descriptions cited in these documents might be registered trademarks. All trade names are subject to copyright restrictions and may be registered trademarks. Voyado Lund AB essentially adheres to the manufacturer’s spelling. Names of products and trademarks appearing in this document, with or without specific notation, are likewise subject to trademark and trade protection laws and may thus fall under copyright restrictions.

CLOSE