Enable add-to-cart signals in a native Android app
The add-to-cart signal captures when a user adds an item to their cart or selection — for example, a product, a flight, or a hotel room. It helps track shopping behavior across your app and can be used for product recommendations and behavioral analytics.
Availability: Pro, Premium and Ultimate
Implementation considerations
When to fire the signal
Decide when to send the signal based on your app's behavior:
- On button tap — fire immediately when the user taps Add to cart. Best for tracking intent, even if the action fails (for example, due to a network error).
- After cart update — fire after confirming the item was successfully added. Ensures accuracy but may miss failed attempts.
For most implementations, firing on tap is recommended.
Multiple purchasing flows
Your app may have more than one path to add a product to the cart:
- Product detail screen
- Product listing (quick add)
- Product modal or bottom sheet
Each flow may need separate signal calls if product data is structured differently. Make sure all flows are covered.
Product catalog
The add-to-cart signal automatically updates your product catalog in Connect:
- If the product ID is new, Connect creates a catalog entry from the signal data.
- If the product ID already exists, Connect updates the catalog attributes — name, unit price, category, description, currency, and discount — with the values from the signal.
- If the category ID is new, Connect creates a catalog category entry.
- If the category ID already exists, Connect updates the category name to match the signal.
Null values do not overwrite existing catalog data. Empty strings update the field to blank. Zero values update numeric fields to zero.
Contact mapping
Use the audience field to map the signal to a contact in Connect. Commonly used identifiers are email address, phone number, and customer ID.
NoteA customer ID mapped to the Contact key attribute in Connect is the most reliable identifier for known contacts. However, if no matching contact exists and the only attribute is a contact key, the signal is discarded — contact keys alone cannot create new contacts.
Sources of the identifier in an Android app:
- In-memory session object (for example,
UserSession.email) SharedPreferencesfor persisted login state- Room database or other local store
The value must be a JSONObject where each key is a contact attribute name as it appears in Connect (including capitalization and spacing) and each value is the attribute value. For phone number attributes, use the E.164 format: +[country code][area code][phone number] — no spaces, dashes, or special characters. If the + symbol is omitted, Connect adds it automatically.
NoteWe recommend attaching identifiers to as many signals as possible. If the user is not authenticated, omit
audience— Connect will attempt to identify the visitor using other signals from the same session.
Configuration
Method
Connect.logSignal(data: HashMap<String?, Any?>?): BooleanSends the signal to the Acoustic Connect endpoint. The Connect SDK must be initialized via Connect.enable() before calling this method.
Pass all fields as a flat HashMap. The SDK handles the signal structure automatically — you do not need to construct a nested object.
Signal fields
Required
| Field | Schema type | Description |
|---|---|---|
itemQuantity | Number | Quantity of items added to the cart. Pass as a string (for example, quantity.toString()) |
productId | String | Unique product identifier (may match SKU) |
productName | String | Name of the product |
signalType | String | Signal type. Value: "addToCart" |
unitPrice | Number | Unit price of the product. Pass as a string (for example, price.toPlainString()) |
Optional
| Field | Schema type | Description |
|---|---|---|
audience | JSONObject | Key-value pairs for contact mapping. Must be a flat JSONObject — not a HashMap. Keys must match contact attribute names exactly as they appear in Connect |
category | String | Signal category. Value: "Behavior" |
currency | String | ISO 4217 currency code (for example, "USD", "EUR"). Defaults to the currency set for your Connect subscription |
description | String | A description of the signal |
discount | Number | Discount amount applied to the item. Pass as a string |
name | String | A label to differentiate this signal from others (for example, "addToCart from product detail"). Max 256 characters |
productCategory | String | Product category from your catalog (useful for segmentation) |
productCategoryId | String | Product category identifier |
productDescription | String | Description of the product |
promotionId | String | ID from a marketing campaign that led to this action |
shoppingCartUrl | String | URL or deep link to the shopping cart |
virtualCategory | String | Category based on navigation path (for example, "New arrivals", "Sale") |
Things to know
Fields with schema type Number must be passed as strings. The SDK serializer silently drops numeric values.
Pass
audienceas aJSONObject, not aHashMap. AHashMapvalue is silently dropped by the SDK serializer and the contact will not be mapped.If a required field is missing or invalid, the entire signal is discarded. If a required field isn't applicable to your business, use a placeholder value.
Required import
import org.json.JSONObjectBasic example
val data = hashMapOf<String?, Any?>(
"signalType" to "addToCart",
"productId" to "SKU-12345",
"productName" to "Wireless Headphones",
"itemQuantity" to "1",
"unitPrice" to "299.99"
)
Connect.logSignal(data)Complete example
This example fires an add-to-cart signal from a product detail bottom sheet with dynamic product data and optional contact mapping.
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
private fun addToCart() {
CartStore.add(product = product, colorway = selectedColorway, quantity = quantity)
// Fields with schema type Number must be passed as strings
val data = hashMapOf<String?, Any?>(
"signalType" to "addToCart",
"productId" to product.id,
"productName" to product.name,
"itemQuantity" to quantity.toString(),
"unitPrice" to product.price.toPlainString(),
"productCategory" to product.category.displayName,
"currency" to "USD"
)
// audience must be JSONObject — HashMap values are silently dropped
UserSession.email?.let { email ->
data["audience"] = JSONObject().put("Email Address", email)
}
Connect.logSignal(data)
}Troubleshooting
Signal not appearing in Connect?
- Confirm
Connect.enable()is called beforelogSignal. - Check that
logSignalreturnstrue. Afalsereturn indicates the SDK rejected the call. - Verify the
appKeyandpostMessageUrlmatch the Connect org you're checking.
Signal marked as invalid in Connect?
- Confirm all required fields are present:
signalType,productId,productName,itemQuantity,unitPrice. - Verify that
itemQuantity,unitPrice, and any other Number fields are passed as strings — usequantity.toString()andprice.toPlainString().
Contact not created or updated?
- Confirm
audienceis aJSONObject, not aHashMap. - Verify attribute key names match exactly how they appear in Connect — including capitalization and spacing.
Product data missing from the signal?
- Use
Log.ito log the return value oflogSignaland inspect the raw session data in Connect to confirm which fields arrived. - Check for numeric values not passed as strings — they are silently dropped.
Related pages
- Enable page view signals in the Connect Android SDK
- Connect Android SDK: event and data logging
- How behavior signals are processed in Connect
