---
updatedAt: 2026-08-11T15:52:39.000Z
---

# Enable wishlist-item-removed signals in an Android app

The wishlist-item-removed signal fires when a user removes a product from their wishlist or list of saved items. Use this signal to track changes in saved product lists, compare wishlist adds and removes and identify patterns in how contacts manage their saved items.

**Availability:** Pro, Premium and Ultimate

**Languages:** Kotlin and Java

***

# Implementation considerations

## When to fire the signal

Decide when to send the signal based on your app's behavior:

* **On tap** - fire as soon as the user taps to remove or un-save the item. Captures intent even if the action fails.
* **After confirmation** - fire after confirming the item was removed. Ensures accuracy but may miss failed attempts.

For most implementations, firing on tap is recommended.

## Multiple removal flows

Users can remove items from a favorites list from different screens in your app:

* Product detail screen - tapping a filled heart button to un-save
* Favorites or saved items screen - a dedicated remove button per item
* Product listing - an un-save icon on a product card

Each screen may have access to different amounts of product data. Make sure all flows are covered and fire one signal per item - including when a user clears all favorites at once.

## Contact mapping

Use the `audience` field to map this signal to a contact in Connect. Commonly used identifiers are email address, phone number and customer ID.

<Callout icon="📘" theme="info">
  ### 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.
</Callout>

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

```kotlin Kotlin
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

| Field        | Schema type | Description                                                     |
| ------------ | ----------- | --------------------------------------------------------------- |
| `productId`  | String      | Unique product identifier. If missing, the signal is discarded. |
| `signalType` | String      | Signal type. Value: `"wishlistItemRemoved"`.                    |

### 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.                                                                                                                                   |
| `effect`            | String       | Describes the effect of the signal on engagement.                                                                                                              |
| `externalVariantId` | String       | Identifier for the specific product variant removed, such as a size or color.                                                                                  |
| `name`              | String       | A label to differentiate this signal from others (for example, `"wishlistItemRemoved from favorites screen"`). Max 256 characters.                             |
| `price`             | Number       | Price of the product at the time it was removed. Pass as a string (for example, `price.toPlainString()`).                                                      |
| `productCategory`   | String       | Category or department the product belongs to.                                                                                                                 |
| `productName`       | String       | Display name of the product.                                                                                                                                   |
| `wishlistId`        | String       | Identifier for the specific wishlist the item was removed from, useful if a contact can maintain more than one list.                                           |

<Callout icon="✅" theme="okay">
  ### Things to know

  - `price` has schema type Number but must be passed as a string - use `price.toPlainString()`. 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.

  - Capture product data before the removal action - after removal the product may no longer be easily accessible.

  - Optional fields enhance the signal but do not prevent processing if omitted.
</Callout>

### Required import

```kotlin Kotlin
import org.json.JSONObject
```

## Basic example

```kotlin Kotlin
val data = hashMapOf<String?, Any?>(
    "signalType" to "wishlistItemRemoved",
    "productId" to "SKU-12345",
    "productName" to "Linen Throw",
    "price" to "89.99",
    "currency" to "USD"
)
Connect.logSignal(data)
```

## Complete example

This example fires a wishlist item removed signal when the user taps a filled heart button to un-save the product. The signal fires only when the item is being removed, determined by the return value of the toggle function.

```kotlin Kotlin
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect

private fun toggleWishlist(product: Product) {
    val isNowFaved = FavoritesStore.toggle(product.id)

    if (!isNowFaved) {
        // Item was just removed from favorites
        val data = hashMapOf<String?, Any?>(
            "signalType" to "wishlistItemRemoved",
            "productId" to product.id,
            "productName" to product.name,
            "price" to product.price.toPlainString(),
            "productCategory" to product.categoryName,
            "currency" to "USD",
            "category" to "Behavior",
            "name" to "wishlistItemRemoved from product detail"
        )

        // 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`.
* Capture the return value and check that it is `true`: `val accepted = Connect.logSignal(data)`. A `false` return indicates the SDK rejected the call - no additional configuration is required to use the return value.
* Confirm `productId` is present - it is required and its absence discards the entire signal.
* Verify the `appKey` and `postMessageUrl` match the Connect org you're checking.

**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.

***

# Related pages

* [Wishlist item added signal in the Connect Android SDK](https://developer.goacoustic.com/acoustic-connect/docs/wishlist-item-added-signal-android)
* [How behavior signals are processed in Connect](https://developer.goacoustic.com/acoustic-connect/docs/how-behavior-signals-are-processed-in-connect)