Enable add-to-cart signals in the Connect web library
The add-to-cart signal captures when a user selects a product, service, or offering for purchase. This signal helps track shopping behavior across your website and can be used for product recommendations and behavioral analytics.
Availability: Pro, Premium and Ultimate
Implementation considerations
Button variations
Different button styles may require different selectors or extraction logic. Consider:
- Buttons with different CSS classes or IDs
- Buttons that use different HTML structures
- Buttons that store product data in different attributes or locations

Two variations of the "Buy" button at Potgang.co.uk

Three variations of the "Buy" button at Amazon.com
You may need separate code paths to handle each variation.
Triggering the signal
Decide when to send the signal based on your site's behavior:
- Immediate (on click) - Fire the signal as soon as the user clicks Add to cart. Best for tracking intent, even if the action fails.
- Delayed (on cart update) - Fire the signal after confirming the item was added to the cart. Ensures accuracy but may miss failed attempts.
Multiple purchasing flows
You may need separate pieces of logic to support all available purchasing flows, such as:
- Adding from the product detail page
- Adding from the product listing page

The "Quick add" button in a product list at Beefcakeswimwear.com
- Adding from a product modal or quick view
- Bundle or group offers (you can send individual or bundled signals for them)

Product grouping at Amazon.com
Each flow may structure product data differently in the DOM.
Data layer
If your website uses a data layer (for example, Google Tag Manager), it will simplify extracting product information. Look for structured product objects that include ID, name, price and other relevant attributes.
Product catalog integration
Your company's product catalog in Connect is dynamically updated based on incoming add-to-cart signals from your website.
- If a signal contains a new product ID or category ID, Connect creates a new catalog entry based on the signal content.
- If a product ID is already present in the catalog, Connect makes sure the default product attributes in the catalog are up-to-date with the signal (name, unit price, category, description, currency, discount, product URLs).
- If a category ID is already present in the catalog, Connect makes sure its name matches the signal content.
Special handling:
- Null values in the signal do not overwrite existing catalog data.
- Blank values (“”) update the catalog to blank/null.
- Zero values update the related catalog field to zero.
Configuration
Method
TLT.logSignal(signalObject)
Sends the signal to the Acoustic Connect endpoint as a JSON object. The Connect library must be initialized before calling this method.
Signal structure
Top-level fields
category: String - Valid value -Behavior.description: String - Description of the signaleffect: String - Describes the effect of the signal on engagement. It is intended to be used for engagement index scoring. Valid values:negative,positive. Usepositivefor all add-to-cart signals.name: String - Name to differentiate this signal from others (example: "addToCart from quick-add" vs "addToCart from PDP"). Max length - 256 chars.signalType(required): String - Valid value -addToCart.
Signal content
-
currency(required): String - ISO 4217 currency code (for example, "USD", "EUR", "GBP"). If there is only one currency on your website, provide a static value. If there is a selection, use dynamic values. -
discount: Number - Discount amount or difference between original and current price -
imageUrls: Array of strings - The URLs of product images -
itemQuantity(required): Number - Quantity of items added to the cart -
productCategory: String - Product category from your catalog (useful for segmentation) -
productCategoryId: String - Product category identifier -
productDescription: String - Description of the product -
productId(required): String - Unique product identifier (may match SKU) -
productName(required): String - Name of the product -
productUrls: Array of strings - The URLs of product pages -
promotionId: String - ID from marketing campaigns (hero images, CTAs) that led to this action -
signalCustomAttributes: Array of objects - Additional custom attributes. Each object hasnameandvaluestring fields. -
shoppingCartUrl: String - URL of the shopping cart -
unitPrice(required): Number - Unit price of the product -
virtualCategory: String - Category based on navigation path (e.g., "New arrivals", "Sale")
Notes:
- If any required field is missing or invalid, the entire signal will be discarded.
- Optional fields enhance the signal but won't prevent processing if omitted or invalid.
- If a required field isn't applicable to your business, use a placeholder value.
Basic example
const signal = {
// Required fields
signalType: "addToCart",
name: "addToCart from product page",
category: "Behavior",
productId: "SKU-12345",
productName: "Wireless Headphones",
itemQuantity: 1,
unitPrice: 299.99,
currency: "USD",
effect: "positive",
// Optional but recommended fields
productDescription: "Premium noise-cancelling headphones",
discount: 30.00,
productCategory: "Electronics",
productUrls: ["https://example.com/products/headphones"],
imageUrls: ["https://example.com/images/headphones.jpg"],
shoppingCartUrl: "https://example.com/cart"
};
// Send the signal
TLT.logSignal(signal);
Complete implementation example
This example handles add-to-cart events from both product detail pages and quick-add buttons in product listings.
// Check that the Connect library is present
if (window.TLT && window.TLT.isInitialized()) {
// Define the signal template
const signal = {
// Required fields
signalType: "addToCart",
name: "addToCart generated by website",
category: "Behavior",
productId: "",
productName: "",
itemQuantity: 1,
unitPrice: 0,
currency: "USD",
effect: "positive",
// Optional fields
productDescription: "",
discount: 0,
productCategory: "",
productUrls: [],
imageUrls: [],
shoppingCartUrl: "https://" + window.location.host + "/shopping-cart",
virtualCategory: "",
promotionId: "",
actionState: "",
resumedCartItem: "",
signalCustomAttributes: [
{
name: "type",
value: ""
}
]
};
// Define selectors for different add-to-cart button types
const addToCartButtons = [
{ selector: "#add-to-cart", type: "Product details page" },
{ selector: ".quick-add-button-rounded", type: "Quick add button" }
];
// Attach click listeners to all matching elements
addToCartButtons.forEach((addToCartButton) => {
const elements = document.querySelectorAll(addToCartButton.selector);
if (!elements.length) return;
elements.forEach((element) => {
element.addEventListener("click", () => {
// Handle product details page button
if (addToCartButton.type === "Product details page") {
const article = document.querySelector(".product--detailPage");
if (article) {
signal.signalCustomAttributes[0].value = "Product details page";
signal.productId = article.getAttribute("data-sku");
signal.productName = article.getAttribute("data-name");
const productUrl = article.getAttribute("data-url");
if (productUrl) {
signal.productUrls.push(productUrl);
}
const imageUrl = article.getAttribute("data-image-url");
if (imageUrl) {
signal.imageUrls.push(imageUrl);
}
signal.itemQuantity = Number(article.querySelector(".cartItem--success").innerText) || 0;
const discountedPrice = Number(article.querySelector(".price-sale").innerText) || 0;
const regularPrice = Number(article.querySelector(".price-default").innerText) || 0;
if (discountedPrice) {
signal.unitPrice = discountedPrice;
signal.discount = Math.round((regularPrice - discountedPrice) * 100) / 100;
} else {
signal.unitPrice = regularPrice;
}
console.log("addToCart signal:", JSON.stringify(signal, undefined, 2));
TLT.logSignal(signal);
}
}
// Handle quick add button
if (addToCartButton.type === "Quick add button") {
const article = element.closest(".product-tile");
if (article) {
signal.signalCustomAttributes[0].value = "Quick add button";
signal.productId = article.querySelector(".thumbnail_code").innerText || "";
signal.productName = article.querySelector(".thumbnail_name").innerText || "";
signal.productUrls = [article.querySelector(".thumbnail_link").href || ""];
signal.imageUrls = [article.querySelector(".thumbnail_image").src.split("?")[0] || ""];
signal.itemQuantity = 1;
const discountedPrice = Number(article.querySelector(".price-sale").innerText) || 0;
const regularPrice = Number(article.querySelector(".price-default").innerText) || 0;
if (discountedPrice) {
signal.unitPrice = discountedPrice;
signal.discount = Math.round((regularPrice - discountedPrice) * 100) / 100;
} else {
signal.unitPrice = regularPrice;
}
console.log("addToCart signal:", JSON.stringify(signal, undefined, 2));
TLT.logSignal(signal);
}
}
});
});
});
}
Updated 4 days ago
