Enable page view signals in a native Android app
The page view signal captures when users open screens in your app. You can instrument all screens for full navigation coverage, or target specific screens — such as category pages or account screens — to enrich navigation context alongside higher-value signals. For screens with dedicated signal types, such as product detail or order confirmation, use the appropriate signal instead.
Reasons to enable:
- Track navigation patterns across screens
- Understand which screens receive most traffic
- Identify drop-off points in user journeys
- Segment users based on content consumption
Availability: Premium and Ultimate
Implementation considerations
When to fire the signal
Fire the page view signal after the screen is visible to the user.
// Fragment: fire in onViewCreated(), after UI setup is complete.
// Activity: fire in onResume() to capture both initial display and back-stack returns.
// Avoid onCreate() or onStart() — the view may not be fully rendered yet.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Connect.logSignal(hashMapOf("signalType" to "pageView", "url" to "ProductScreen"))
}// Use LaunchedEffect(Unit) inside the composable.
// This fires once when the composable enters the composition.
@Composable
fun ProductScreen() {
LaunchedEffect(Unit) {
Connect.logSignal(hashMapOf("signalType" to "pageView", "url" to "ProductScreen"))
}
}Screen naming
Use a consistent naming strategy across your app. Options:
- Class name — use the Fragment or Activity class name (for example,
"ProductDetailBottomSheet"). Simple and consistent. - Logical name — use a human-readable label (for example,
"Product detail"). More meaningful in analytics but requires maintenance.
Whichever strategy you choose, apply it uniformly so navigation paths are comparable across sessions.
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) 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.
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?>?): BooleanSends the signal to the Acoustic Connect endpoint. The Connect SDK must be initialized via Connect.enable() before calling this method.
Pass all signal fields as a flat HashMap — the SDK handles the mapping to the backend signal structure automatically. The only exception is audience, which must be a JSONObject.
Signal fields
Required
| Field | Type | Description |
|---|---|---|
signalType | String | Signal type. Value: "pageView". |
url | String | The screen name or identifier for the screen the user has opened. Screen names are accepted as-is — there is no URL validation. |
Optional
| Field | 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 |
name | String | A label to differentiate this signal from others (for example, "pageView from Android app"). Max 256 characters |
pageCategory | String | The category the screen belongs to (for example, "clothing", "account") |
Note: Pass
audienceas aJSONObject, not aHashMap. AHashMapvalue is silently dropped by the SDK serializer and the contact will not be mapped.
Required import
import org.json.JSONObjectBasic example
val data = hashMapOf<String?, Any?>(
"signalType" to "pageView",
"url" to "ProductDetailBottomSheet"
)
Connect.logSignal(data)Complete example
This example fires a page view signal with optional contact mapping when a user is authenticated.
import org.json.JSONObject
import com.acoustic.connect.android.connectmod.Connect
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Set up UI ...
val data = hashMapOf<String?, Any?>(
"signalType" to "pageView",
"url" to "ProductDetailBottomSheet",
"pageCategory" to "home goods"
)
// audience must be JSONObject — HashMap values are silently dropped
UserSession.email?.let { email ->
data["audience"] = JSONObject().put("Email Address", email)
}
Connect.logSignal(data)
}import org.json.JSONObject
import androidx.compose.runtime.LaunchedEffect
import com.acoustic.connect.android.connectmod.Connect
@Composable
fun ProductDetailScreen(userEmail: String?) {
LaunchedEffect(Unit) {
val data = hashMapOf<String?, Any?>(
"signalType" to "pageView",
"url" to "ProductDetailScreen",
"pageCategory" to "home goods"
)
// audience must be JSONObject — HashMap values are silently dropped
userEmail?.let { email ->
data["audience"] = JSONObject().put("Email Address", email)
}
Connect.logSignal(data)
}
}Best practices
- Fire the signal consistently on every screen in your app.
- Use a single naming convention for
urlacross the team. - Attach an
audienceidentifier whenever the user is authenticated. - Avoid firing duplicate signals — check that the signal fires once per screen display, not on every layout pass or configuration change.
Troubleshooting
Signal not appearing in Connect?
- Confirm
Connect.enable()is called beforelogSignal. - Check that
logSignalreturnstrue. Afalsereturn indicates the SDK rejected the call (SDK not initialized or capture disabled). - Verify the
appKeyandpostMessageUrlmatch the Connect org you're checking.
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.
Duplicate signals on the same screen?
- Check that the signal call is not inside a method that runs on configuration changes (for example, screen rotation). Prefer
onViewCreatedoveronResumefor Fragments if back-stack returns should not re-fire.
