Skip to content

Working with Notifications

Notifications can be described as data containing visitor interactions that is sent into eSales during a visitor session. Notifications are used to gather statistics, enable personalisation, and improve eSales 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 eSales performs at its best and delivers the best possible content to visitors.

Set-up

To be able to send notifications into eSales 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 eSales content with tickets, the most common thing to include in a notification.

What to notify

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

Always notify eSales when clicks are made on eSales 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 eSales entity.

Notification type Description
Click To be sent when the visitor clicks on eSales entities with tickets in panels, e.g. ads and products. The category entities have tickets but it is not necessary to notify clicks on them.
Non-eSales click To be sent when the visitor clicks on a product or variant not returned by eSales (i.e. not having a ticket).
Adding-to-cart To be sent when the visitor adds a product or variant to their cart.
Non-eSales adding-to-cart To be sent when the visitor adds a product or variant not returned by eSales (i.e. not having a ticket) to their cart.
Secure payment To be sent when the visitor has placed and paid for an order. This is the recommended payment notification to use.
Payment To be sent when the visitor has placed and paid for an order. The Secure payment notification is recommended to use.
End session To be sent when the visitor signs out or the session times out. The level of personalisation affects the actions performed when a session ends.

Tickets

All content that is rendered by eSales, such as products and ads, have a unique string identifying them called a ticket. Tickets are generated automatically by eSales 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
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.

Apptus 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}");

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 Apptus Support if there is a need to enable non-authenticated 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. Apptus eSales 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 eSales. The attribute cost is important for both statistics as well as for Exposure Strategies.

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 eSales.

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 Behaviour 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 eSales content. Clicks are used for things such as statistics and to improve eSales algorithms.
Always send a notification when a product is added to cart. Use the Adding to cart notification with eSales 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.

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

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 eSales, 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 eSales 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 eSales content that supports click notifications have click notifications.
×