Developer

App lifecycle and offline behaviour

How the App SDK queues events offline, sends them when the app goes to the background, refreshes assignments in the foreground, and handles sessions.

The SDK stores events on the device and sends them in batches. It sends the queue when the app goes to the background and refreshes assignments when the app returns to the foreground.

Offline queue

Every track(), trackPurchase() and exposure goes into a queue in device storage. The SDK sends the queue every flushIntervalSeconds (default 5 seconds), in batches of up to 20 events.

  • When track() resolves, the event is in device storage. It stays there until Apex confirms it, so a crash or a closed app does not lose it.
  • When the app is offline, the SDK retries with a growing delay: 5, 10, 20, 40, then 60 seconds.
  • The queue holds up to 2,000 events. When it is full, the SDK removes the oldest events first.
  • Unsent events expire after 47 hours.
  • Each event keeps the same event ID on every retry, so Apex counts it once.

To send the queue now, for example before a planned app close:

ts
await Apex.flush();

flush() resolves when the SDK finishes its local work. It does not wait for delivery.

Background and foreground

The SDK listens for app state changes from these sources:

  • Browser visibilitychange events.
  • Cordova pause and resume events.
  • Capacitor App appStateChange events, when the App plugin is available on window.Capacitor.Plugins.

You do not need to install a plugin for this. When the app goes to the background, the SDK first finishes any pending storage write. Then it sends the queue.

When the app returns to the foreground, the SDK refreshes assignments after a short random delay (0 to 10 seconds by default). It also sends any queued events.

Forward lifecycle events yourself

Some Capacitor versions expose App only as an imported module. Forward its state to the SDK:

ts
import { App } from '@capacitor/app';
import { Apex } from '@drip-apex/app-sdk';
 
App.addListener('appStateChange', ({ isActive }) => {
  Apex.setAppState(isActive ? 'foreground' : 'background');
});

You can also call Apex.setAppState('background') and Apex.setAppState('foreground') from your own shell hooks. Repeated signals within one second count as one change.

Assignment refresh

The SDK requests assignments at these times only:

  • On configure().
  • On identify().
  • When the app returns to the foreground.
  • When you call Apex.refresh().

There is no periodic polling. A value older than 60 seconds reports reason: 'stale', but the SDK does not refresh it on a timer. To refresh in a long foreground session, call Apex.refresh().

Sessions

Each cold launch starts a new session. After 30 minutes in the background, the SDK also starts a new session when the app returns. A new session allows a new exposure for each assignment.

Shut down

Call Apex.shutdown() when the app no longer needs the SDK. It stops networking and waits for pending storage writes. A second configure() call shuts down the previous context for you.

To run a separate context, create new ApexClient(options) and await its ready promise. Do not run two clients with the same storage, shop and environment at the same time.