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.

📘

Note

A 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)
  • SharedPreferences for 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.

📘

Note

We 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?>?): Boolean

Sends 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

FieldSchema typeDescription
itemQuantityNumberQuantity of items removed from the cart. Pass as a string (for example, quantity.toString())
productIdStringUnique product identifier (may match SKU)
productNameStringName of the product
signalTypeStringSignal type. Value: "removedFromCart"
unitPriceNumberUnit price of the product. Pass as a string (for example, price.toPlainString())

Optional

FieldSchema typeDescription
audienceJSONObjectKey-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
categoryStringSignal category. Value: "Behavior"
currencyStringISO 4217 currency code (for example, "USD", "EUR"). Defaults to the currency set for your Connect subscription
descriptionStringA description of the signal
discountNumberDiscount amount applied to the item. Pass as a string
nameStringA label to differentiate this signal from others (for example, "removedFromCart from cart screen"). Max 256 characters
productCategoryStringProduct category from your catalog (useful for segmentation)
productCategoryIdStringProduct category identifier
productDescriptionStringDescription of the product
promotionIdStringID from a marketing campaign associated with this product
shoppingCartUrlStringURL or deep link to the shopping cart
virtualCategoryStringCategory 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 audience as a JSONObject, not a HashMap. A HashMap value 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.JSONObject

Basic 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 before logSignal.
  • Check that logSignal returns true. A false return indicates the SDK rejected the call.
  • Verify the appKey and postMessageUrl match 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 — use quantity.toString() and price.toPlainString().

Contact not created or updated?

  • Confirm audience is a JSONObject, not a HashMap.
  • Verify attribute key names match exactly how they appear in Connect — including capitalization and spacing.

Product data missing from the signal?

  • Use Log.i to log the return value of logSignal and 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