Skip to main content

In-App Messaging (API Pull) — Android Overview

Paylisher can deliver in-app messages to your Android app in two independent ways:

Delivery modeTransportWhen the message reaches the device
FCM pushA silent data push through FirebaseServer-initiated; can reach the device even in the background.
API pull (this section)The SDK polls Engage over HTTPSThe 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.

Endpoint host

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:

TriggerBehavior
App comes to the foreground~2s after onResume
The user changes screen inside the appon Activity / Fragment change (debounced 15s)
ManualPaylisherAndroid.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.

Minimum OS version

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.

Jetpack Compose

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

  1. Time windowcondition.displayTime (60s tolerance) and condition.expireDate gate whether it shows now.
  2. De-duplication — the same pushId is not shown twice within a 1-hour window; a campaign already delivered to a distinctId is not returned again.
  3. 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.
  4. Delay — render is delayed by max(condition.delay minutes, displayTime − now).
  5. AcknowledgeDELIVERED on enqueue; SEEN / CLICKED / DISMISSED follow interaction.

Next steps