Enable error signals in an Android app
The error signal captures when users encounter errors during critical flows in your app — for example, payment failures, invalid promo codes, or form validation issues. It enables targeted outreach and recovery campaigns for users who hit obstacles on the path to conversion. In Connect, the signal enables segmentation by error type and error ID.
NoteThe error signal is for marketing segmentation, not error monitoring. Use it to identify users who experienced issues so your team can reach out with recovery messaging — not as a replacement for crash reporting or logging tools.
Availability: Premium and Ultimate
Languages: Kotlin and Java
Implementation considerations
Error types
Two error types are supported:
USER— caused by invalid user input: form validation failures, incorrect payment details, invalid promo codes, missing required fieldsAPPLICATION— generated by the app itself: network failures, server errors, API errors
When to fire the signal
Fire the signal immediately after the error is presented to the user. In Android apps, this is typically:
- After form validation runs and an error message is shown
- In the
catchblock of a network or API call when the error is surfaced in the UI - After receiving an error response from a payment or checkout service
Only fire the signal when the error is visible to the user — not for silent background failures.
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
- Form fields collected during the current flow — for example, the email address entered on a checkout screen
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 |
|---|---|---|
errorText | String | The error message shown to the user |
errorType | String | Type of error. Value: "USER" or "APPLICATION". |
signalType | String | Signal type. Value: "error". |
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". |
description | String | A description of the signal |
effect | String | Describes the effect of the signal on engagement. Use "negative" for error signals. |
errorIdentifier | String | A short identifier for the error type (for example, "payment", "promoCode", "registration"). Used for segmentation by Error ID. |
name | String | A label to differentiate this signal from others (for example, "checkout error"). Max 256 characters |
Things to know
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.
Required import
import org.json.JSONObjectBasic example
val data = hashMapOf<String?, Any?>(
"signalType" to "error",
"errorType" to "USER",
"errorText" to "Invalid promo code",
"errorIdentifier" to "promoCode",
"effect" to "negative"
)
Connect.logSignal(data)Complete examples
Checkout form validation
This example fires an error signal when checkout form validation fails. It validates all fields in one pass, fires a signal for each invalid field, and focuses the first one. If the user corrects the errors and places the order, the subsequent order signal in Connect captures the recovery — giving your team visibility into the full path from error to conversion. Users who experienced errors but did not complete the order are available for segmentation as a cart abandonment audience.
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
private fun validate(): Boolean {
var valid = true
var firstError: View? = null
val requiredFields = listOf(
binding.nameField to "name",
binding.streetField to "street",
binding.cityField to "city",
binding.postalField to "postalCode",
binding.cardNumberField to "cardNumber",
binding.expiryField to "expiry",
binding.cvcField to "cvc"
)
for ((field, identifier) in requiredFields) {
if (field.text.isNullOrBlank()) {
val errorText = getString(R.string.checkout_validate_required)
field.error = errorText
sendErrorSignal(errorText, identifier)
if (firstError == null) firstError = field
valid = false
}
}
if ((binding.cardNumberField.text?.toString().orEmpty()).length < 12) {
val errorText = getString(R.string.checkout_validate_card)
binding.cardNumberField.error = errorText
sendErrorSignal(errorText, "payment")
if (firstError == null) firstError = binding.cardNumberField
valid = false
}
firstError?.requestFocus()
return valid
}
private fun sendErrorSignal(errorText: String, errorIdentifier: String) {
val data = hashMapOf<String?, Any?>(
"signalType" to "error",
"errorType" to "USER",
"errorText" to errorText,
"errorIdentifier" to errorIdentifier,
"effect" to "negative"
)
// audience must be JSONObject — HashMap values are silently dropped
UserSession.email?.let { email ->
data["audience"] = JSONObject().put("Email Address", email)
}
Connect.logSignal(data)
}Invalid promo code
This example fires an error signal when a user enters an unrecognised promo code on the cart screen. It is a strong candidate for a recovery campaign — your team knows the user attempted a discount and can follow up with a working code if the user leaves without placing the order.
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
private fun applyPromo(code: String) {
val normalized = code.trim().uppercase()
if (normalized.isEmpty()) return
if (normalized == "HRN10") {
// valid — apply discount
} else {
val errorText = getString(R.string.cart_promo_unknown)
binding.totalsCard.promoStatusLabel.text = errorText
sendErrorSignal(errorText, "promoCode")
}
}
private fun sendErrorSignal(errorText: String, errorIdentifier: String) {
val data = hashMapOf<String?, Any?>(
"signalType" to "error",
"errorType" to "USER",
"errorText" to errorText,
"errorIdentifier" to errorIdentifier,
"effect" to "negative"
)
// 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. - Capture the return value and check that it is
true:val accepted = Connect.logSignal(data). Afalsereturn indicates the SDK rejected the call — no additional configuration is required to use the return value. - Verify the
appKeyandpostMessageUrlmatch the Connect org you're checking.
Signal marked as invalid in Connect?
- Confirm all required fields are present:
signalType,errorType,errorText. - Verify
errorTypeis exactly"USER"or"APPLICATION"— other values will cause the signal to be discarded.
Duplicate signals on retry?
- If the user retries and triggers the same validation error, a new signal fires. This is expected behavior. If you want to suppress duplicates within a session, track which errors have already been reported using a local flag.
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.
Related pages
- Behavior signals in a native Android app
- Connect Android SDK: event and data logging
- How behavior signals are processed in Connect
