Enable order signals in the Connect web library
You can enable the Connect library to send order signals each time a visitor places an order on your website.
An order represents a transaction placed by a user within an application. Here are some typical examples from different business domains:
- Retail: an order confirmation
- Travel: a booking confirmation
- Banking/insurance: an application confirmation
Availability
The order signal is included in all Connect subscriptions (Pro, Premium and Ultimate).
Configuration
The Connect library provides a method, TLT.logSignal()
with which to send the signal to the Acoustic Connect endpoint, as a JSON object. The Connect library must be initialized before the method is called.
The order signal is probably the most advanced in terms of implementation. This is mainly because you will rarely find all order details on the order confirmation page. Usually, some of them are only available earlier in the checkout process but you cannot fire the signal from there because an order ID hasn't been generated yet. In such a situation we recommend saving the data points in the session storage of the browser until the user confirms their order and the signal can be sent.
Required fields
You must populate the required fields before sending the signal: the order ID and the currency. Without them, the signal will be ignored.
Field | Values | Definition |
---|---|---|
category | String. Valid value - Behavior . | The category of the signal. Do not edit. |
currency | String. Valid values - ISO 4217 currency codes. | The currency used for the order |
effect | String. Valid values: - negative - positive | Describes the effect of the signal on engagement. It is intended to be used for engagement index scoring. We suggest sending positive for all order signals. |
name | String, up to 256 characters | Assign a name to the signal to differentiate it from other signals. |
orderId | String | An identifier assigned to the order. You can usually scrape it from the URL or from the page. |
signalType | String. Valid value -order . | The type of signal to enable. Do not edit. |
Optional fields
Field | Values | Definition |
---|---|---|
orderDiscount | Number | Discount from the original price. If the exact amount is not provided, you could calculate the difference between the original and the current price. |
orderedItems | Array of objects | The list of products in the order. You need a separate object for each product, but not each instance of the same product - three identical items would result in one object, with a quantity of 3. |
orderShippingHandling | Number | The shipping and handling amount for the order |
orderSubtotal | Number | The subtotal amount for the order (net of discount) |
orderTax | Number | The tax amount for the order |
orderValue | Number | The total value of the order |
signalCustomAttributes | Array of objects | Allows for additional custom attributes. For each custom attribute, add an object with two string fields:name and value . |
Fields supported by objects within the orderedItems
array
Field | Values | Required? | Definition |
---|---|---|---|
actionState | String | Optional | Placeholder to support future functionality |
currency | String. Valid values - ISO 4217 currency codes. | Optional | The currency in which the price of the product is represented |
discount | Number | Optional | Discount from the original price. If the exact amount is not provided, you could calculate the difference between the original and the current price. |
productCategory | String | Optional | The category that the product falls in based on the product catalog |
productDescription | String | Optional | The description of the product |
productId | String | Required | The identifier of the product. It may coincide with the SKU. |
productImageUrl | String | Optional | The URL of the product image |
productName | String | Required | The name of the product |
productUrl | String | Optional | The URL of the product page |
promotionId | String | Optional | For the use case of on-site marketing like hero images and other calls-to-action, those calls-to-action would have a promotion ID that would "stick" to the behaviors after it. |
quantity | Integer | Optional | Captures the quantity of the product purchased. |
resumedCartItem | String | Optional | Placeholder to support future functionality |
shoppingCartUrl | String | Optional | The URL of the shopping cart |
unitPrice | Number | Required | Indicates how much the client paid for the product. |
virtualCategory | String | Optional | The category is based on how the visitor got to the product page, for example from "New arrivals" or "Sale". |
Example
// Utility function to write partial signal to session storage
function store(key, value) {
var acoStore;
if (!sessionStorage) {
console.warn("session storage unavailable");
return false;
}
acoStore = sessionStorage.getItem("aco-store") || "{}";
acoStore = JSON.parse(acoStore);
// If a signal is being passed in
if (typeof key === "object" && key.signalType && value === undefined) {
// If a key for this signalType exists
if (acoStore[key.signalType]) {
acoStore[key.signalType].push(key);
} else {
acoStore[key.signalType] = [key];
}
}
if (key && value !== undefined) {
acoStore[key] = value;
}
sessionStorage.setItem("aco-store", JSON.stringify(acoStore));
return true;
}
// Utility function to retrieve signal from session storage
function retrieve(key, del) {
var acoStore,
value;
if (!sessionStorage) {
console.warn("session storage unavailable");
return false;
}
acoStore = sessionStorage.getItem("aco-store") || "{}";
acoStore = JSON.parse(acoStore);
value = acoStore[key] || "";
if (del && del === "delete") {
delete acoStore[key];
if (Object.keys(acoStore).length === 0) {
sessionStorage.removeItem("aco-store");
} else {
sessionStorage.setItem("aco-store", JSON.stringify(acoStore));
}
}
return value;
}
// Check that the Connect SDK is present
if (window.TLT && window.TLT.isInitialized()) {
const signal = {
signalType: "order",
name: "order generated by web site",
category: "Behavior",
orderId: "", // Required
orderSubtotal: 0,
orderValue: 0,
currency: "USD", // Required
orderShippingHandling: 0,
orderTax: 0,
orderDiscount: 0,
orderedItems: [],
effect: "positive", // Required
signalCustomAttributes: []
},
href = window.location.href;
// On the "Place Order" screen, before the order is placed and the booking confirmation page shown
if (href.includes("/place-order")) {
const rows = document.querySelectorAll("tr.lineItem");
// Iterate over the table of products and populate orderedItems array
rows.forEach((row) => {
const orderedItem = {
productId: "", // Required
productName: "", // Required
productDescription: "",
quantity: 0,
unitPrice: 0, // Required
currency: "USD", // Required
discount: 0,
productCategory: "",
productUrl: "",
productImageUrl: "",
shoppingCartUrl: "https://" + window.location.host + "/shopping-cart",
promotionId: "",
virtualCategory: "",
actionState: "",
resumedCartItem: ""
};
orderedItem.productId = row.querySelector(".lineItem_sku").innerText || "";
orderedItem.productName = row.querySelector(".lineItem_name").innerText || "";
orderedItem.quantity = Number(row.querySelector(".lineItem_qty").innerText) || 0;
orderedItem.productUrl = row.querySelector(".lineItem_nameLink").innerText || "";
orderedItem.productImageUrl = row.querySelector(".lineItem_image > img").src.split("?")[0] || "";
const discountedPrice = Number(row.querySelector(".price_sale").innerText) || 0;
const regularPrice = Number(row.querySelector(".price_defautl").innerText) || 0;
if (discountedPrice) {
orderedItem.unitPrice = discountedPrice;
orderedItem.discount = Math.round((regularPrice - discountedPrice) * 100) / 100;
} else {
orderedItem.unitPrice = regularPrice;
}
signal.orderedItems.push(orderedItem);
});
// Scrape the total prices from below the table
signal.orderSubtotal = Number(document.querySelector("div.orderSummary_subtotal").innerText) || 0;
signal.orderValue = Number(document.querySelector("div.orderSummary_total").innerText) || 0;
signal.orderShippingHandling = Number(document.querySelector("div.orderSummary_shipping").innerText) || 0;
// Don't send the signal now, store it until we have the order confirmation number on the next page
store(signal);
}
// On the "Order Confirmation" screen, retrieve the signal from storage, add the orderId, and send it
if (href.includes("OrderConfirmation/?OrderNumber=")) {
const orderSignal = retrieve("order", "delete"); // Delete the signal from storage after retrieving
orderSignal.orderId = href.split("OrderConfirmation/?OrderNumber=")[1];
// If we have a stored signal, an orderId, and an orderedItems array, log signal
if (orderSignal && orderSignal.orderId && orderSignal.orderedItems.length) {
window.TLT.logSignal(orderSignal);
}
}
}
Updated 11 days ago