Enable order signals in an Android app
The order signal captures when a user completes a transaction in your app — for example, a retail purchase, a flight booking, or an insurance application. It is essential for tracking conversions, calculating revenue, and triggering post-purchase campaigns.
Availability: Pro, Premium and Ultimate
Implementation considerations
When to fire the signal
Fire the order signal after the order is confirmed by your backend — not when the user taps the purchase button. At that point you have the order ID and all order data from the API response, so no intermediate storage is needed.
checkoutService.placeOrder(cart) { result ->
when (result) {
is Success -> {
sendOrderSignal(result.order)
navigateToConfirmation(result.order)
}
is Failure -> showError(result.error)
}
}Ordered items
Each item in the order is represented as a JSONObject inside a JSONArray. Pass the JSONArray as the value of orderedItems in the signal HashMap. If orderedItems fails validation — for example, due to a missing required item field — the entire signal is discarded.
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
- Checkout form fields — the user's email or phone number entered during checkout, if collected
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.
The order signal is also a good opportunity to enrich the contact record with details collected during checkout — for example, a shipping postal code or city. Include any additional attributes as extra key-value pairs in the same audience object alongside the identifier.
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 order-level fields as a flat HashMap. Pass orderedItems as a JSONArray of JSONObjects, and audience as a JSONObject.
Signal fields
Order-level required
| Field | Schema type | Description |
|---|---|---|
orderId | String | Unique order identifier returned by your backend |
signalType | String | Signal type. Value: "order". |
Order-level 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 |
name | String | A label to differentiate this signal from others (for example, "order from Android app"). Max 256 characters. |
orderDiscount | Number | Total discount applied to the order Pass as a string |
orderedItems | JSONArray | List of ordered items. Each item is a JSONObject — see item-level fields below |
orderShippingHandling | Number | Shipping and handling cost. Pass as a string |
orderSubtotal | Number | Subtotal amount before tax and shipping. Pass as a string |
orderTax | Number | Tax amount. Pass as a string |
orderValue | Number | Total order value including tax and shipping. Pass as a string |
Item-level required
| Field | Schema type | Description |
|---|---|---|
itemQuantity | Number | Quantity of this product purchased. Pass as a string |
productId | String | Unique product identifier (may match SKU) |
productName | String | Name of the product |
unitPrice | Number | Price the customer paid for one unit. Pass as a string |
Item-level optional
| Field | Schema type | Description |
|---|---|---|
discount | Number | Discount amount per unit. Pass as a string. |
productCategory | String | Product category from your catalog |
productCategoryId | String | Product category identifier |
productDescription | String | Description of the product |
promotionId | String | ID from a marketing campaign that influenced the purchase |
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.Pass
orderedItemsas aJSONArrayofJSONObjects. IforderedItemsfails validation, the entire signal is discarded.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 imports
import org.json.JSONArray
import org.json.JSONObjectBasic example
val item = JSONObject().apply {
put("productId", "SKU-12345")
put("productName", "Wireless Headphones")
put("itemQuantity", "1")
put("unitPrice", "299.99")
}
val data = hashMapOf<String?, Any?>(
"signalType" to "order",
"orderId" to "ORD-98765",
"orderValue" to "299.99",
"currency" to "USD",
"orderedItems" to JSONArray().put(item)
)
Connect.logSignal(data)Complete example
This example fires an order signal from the confirmation screen after the backend confirms the order. It includes multiple ordered items, order totals, and optional contact mapping.
import org.json.JSONArray
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
private fun sendOrderSignal(order: Order) {
// Build ordered items — one JSONObject per line item
val orderedItems = JSONArray()
for (item in order.items) {
val orderedItem = JSONObject().apply {
// Fields with schema type Number must be passed as strings
put("productId", item.id)
put("productName", item.name)
put("itemQuantity", item.quantity.toString())
put("unitPrice", item.unitPrice.toPlainString())
put("productCategory", item.category.displayName)
put("currency", "USD")
}
orderedItems.put(orderedItem)
}
val data = hashMapOf<String?, Any?>(
"signalType" to "order",
"orderId" to order.id,
"orderValue" to order.total.toPlainString(),
"orderSubtotal" to order.subtotal.toPlainString(),
"orderTax" to order.tax.toPlainString(),
"orderShippingHandling" to order.shipping.toPlainString(),
"currency" to "USD",
"orderedItems" to orderedItems
)
// audience must be JSONObject — HashMap values are silently dropped
val audience = JSONObject()
UserSession.email?.let { email -> audience.put("Email Address", email) }
order.shippingPostalCode?.let { postal -> audience.put("Postal Code", postal) }
if (audience.length() > 0) {
data["audience"] = audience
}
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:
signalTypeandorderId. - Confirm each item in
orderedItemshas all required fields:productId,productName,itemQuantity,unitPrice. - Verify that Number fields are passed as strings — use
quantity.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.
Order items missing from the signal?
- Confirm
orderedItemsis aJSONArrayofJSONObjects, not aListor nestedHashMap. - Check for numeric values in item fields not passed as strings — they are silently dropped.
Related pages
- Enable add-to-cart signals in the Connect Android SDK
- Connect Android SDK: event and data logging
- How behavior signals are processed in Connect
