Enable removed-from-cart signals in a native Android app
The removed-from-cart signal captures when a user removes an item from their cart or selection — for example, a product, a flight, or a hotel room. It helps identify friction points in the buying journey and can trigger targeted re-engagement campaigns.
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 Remove. 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 removed. Ensures accuracy but may miss failed attempts.
For most implementations, firing on tap is recommended.
Multiple removal flows
Your app may have more than one path to remove an item from the cart:
- Cart screen
- Mini-cart or cart drawer
- Swipe-to-delete gesture on a cart item
Each flow may need separate signal calls if product data is structured differently. Make sure all flows are covered.
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 removed from 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: "removedFromCart" |
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, "removedFromCart from cart screen"). 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 associated with this product |
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 "removedFromCart",
"productId" to "SKU-12345",
"productName" to "Wireless Headphones",
"itemQuantity" to "1",
"unitPrice" to "299.99"
)
Connect.logSignal(data)Complete example
This example fires a removed-from-cart signal when a user removes an item from the cart screen, with dynamic product data and optional contact mapping.
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
private fun removeFromCart(product: Product, quantity: Int) {
CartStore.remove(product = product, quantity = quantity)
// Fields with schema type Number must be passed as strings
val data = hashMapOf<String?, Any?>(
"signalType" to "removedFromCart",
"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.
