In-App Messaging (API Pull) — Android Overview
Paylisher can deliver in-app messages to your Android app in two independent ways:
| Delivery mode | Transport | When the message reaches the device |
|---|---|---|
| FCM push | A silent data push through Firebase | Server-initiated; can reach the device even in the background. |
| API pull (this section) | The SDK polls Engage over HTTPS | The SDK asks "is there anything for me?" and Engage answers with the currently-matching campaigns. No Firebase dependency. |
This section is about the API-pull mode — in-app messages that do not depend on push infrastructure, that appear while the user is actively using the app, and that you can target to specific screens. The behavior is identical to the iOS track — same config, same triggers, same render pipeline.
The pipeline
┌──────────────────────────── Engage ────────────────────────────┐
App is foreground │ resolves your project/source from the public sdkKey │
or a screen changes │ → matches LIVE, API-pull in-app campaigns for this person │
│ │ → applies audience / screen target / time window / de-dup │
▼ │ │
SDK POST ──────────┼──▶ {host}/v1/push/inapp/fetch (X-SDK-Key header) │
SDK ◀──────────────┼── { "messages": [ { "payload": { … } } ] } │
│ └────────────── ───────────────────────────────────────────────────┘
▼
shouldDisplay? (time window) → de-dup (1h per pushId) → queue
▼
render (banner / modal / fullscreen / carousel / native) — skips excluded screens
▼
POST {host}/v1/push/inapp/ack status = DELIVERED → later SEEN / CLICKED / DISMISSED
The SDK sends only a public sdkKey (by default your SDK apiKey). Engage reverse-resolves the team / project / source server-side, so the app never embeds those IDs.
The request
POST {host}/v1/push/inapp/fetch
{
"distinctId": "<current distinct id>",
"sdkKey": "<public sdk key>",
"platform": "android",
"maxMessages": 1,
"target": "wallet"
}
Header: X-SDK-Key: <public sdk key>. A successful response is 201 with a messages array (possibly empty). Acknowledgements go to the sibling path …/inapp/ack.
The default endpoint is derived from your SDK host as {host}/v1/push/inapp/fetch. In most deployments Engage lives on a different host and path prefix than analytics ingestion (for example https://api-eu.paylisher.com/engage/v1/push/inapp/fetch). In that case set fetchEndpoint explicitly — see Integration.
When does the SDK fetch? (default behavior)
With the default config (autoFetchOnForeground = true), the SDK fetches automatically on:
| Trigger | Behavior |
|---|---|
| App comes to the foreground | ~2s after onResume |
| The user changes screen inside the app | on Activity / Fragment change (debounced 15s) |
| Manual | PaylisherAndroid.refreshEngageInAppMessages(context, target) |
The screen-change fetch lets a campaign published while the user is browsing appear after one navigation, without a background→foreground cycle. Both automatic triggers send target = null; the manual call lets you pass the current screen — see Screen targeting.
On Android the entire fetch lifecycle is wired only on API level 29 (Android 10) and above. On API 24–28 the pull flow is inert even with a correct config.
A single-Activity Compose app (no Fragments) does not fire the Activity/Fragment screen-change hook, so the automatic screen-change fetch won't trigger on Compose route changes. Use a manual refreshEngageInAppMessages(context, target) on route change — see Scenarios.
What happens to a returned message
- Time window —
condition.displayTime(60s tolerance) andcondition.expireDategate whether it shows now. - De-duplication — the same
pushIdis not shown twice within a 1-hour window; a campaign already delivered to adistinctIdis not returned again. - Queue & render — rendered on the main thread. If the current Activity is in
excludedActivities(default["Splash"]), rendering is deferred to the next non-excluded screen. - Delay — render is delayed by
max(condition.delay minutes, displayTime − now). - Acknowledge —
DELIVEREDon enqueue;SEEN/CLICKED/DISMISSEDfollow interaction.
Next steps
- Integration — enable the feature and set the config.
- Scenarios & Recommended Configs — pick the config for your use case.
- Campaign Setup (Dashboard) — author a pull campaign.
- Troubleshooting — empty fetch,
401, or nothing renders.