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. |
Common notification related issues¶
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. |