Skip to main content

Delivery and Retries

The SDK sends a request to Positive User for every ping, event and notification report. What happens when a request fails depends on the platform. This page explains what is retried, what is dropped and what your code sees.


What it is​

iOS puts pings, events, screen events, product events and notification reports in a queue on the device. The queue is saved, so requests created offline or right before the app closes are sent later. A request waiting for a retry does not hold back newer requests. The logout event, the removal of the token at logout and the anonymous ping after logout are sent directly, outside the queue.

Android and Flutter send each request straight away and save only the requests that fail. Android saves failed events, screen events, product events and notification reports, but not pings. Flutter saves requests that failed because of a network error.


How it works​

Results​

The table shows how the iOS SDK handles each answer. Android and Flutter differ in places, see Platform differences.

Server answerWhat the SDK does
Success (2xx)Removes the request from the queue.
Rejected (4xx other than 429), for example a wrong key or an invalid eventRemoves the request. It would fail again.
Server error (5xx) or no networkKeeps the request and retries it later.
Rate limit (429)Keeps the request and retries it no sooner than the server asks for in Retry-After. Before 1.3.0 the request was dropped.

A request rejected by the firewall (HTTP 403, for example for content that looks like an attack) is also a rejection. On iOS and Flutter it is not retried and the event is lost. Android keeps it and sends it again, and the firewall blocks it again.

Checked before sending​

On iOS from 1.3.0, some calls end with an error before any request: an event before the first successful ping, an invalid event or screen name, an empty product ID, and attribute values JSON cannot hold. Nothing is queued in these cases. See Errors.

Offline​

On iOS, while the device has no network, nothing is sent and nothing is counted as a failed attempt. The queue starts again when the network returns.

Partly accepted events​

The backend can accept an event and drop some of its attributes, for example an attribute with a value of the wrong type. The event is recorded and the request counts as a success.


Platform differences​

iOSAndroidFlutter
Saved on the deviceEvery queued requestFailed events, screen events, product events and notification reports. Pings are not saved.Requests that failed on network errors
Retries of server errorsUp to 4 attempts in total, also for 429, after about 30 s, 90 s and 210 s. Other requests keep going out in the meantime. The attempt count starts again after the app restarts.Resent on every UserCom.getInstance() call, with no attempt limitNot retried
Rejected requests (4xx)Dropped, except 429Kept on the device and resent on every UserCom.getInstance() call, never droppedNot retried
Result in your codeCompletion handler on the main thread: true on success, false with a UserSDKError on rejection or after the last retry. UserSDK.errorHandler receives every error, also from calls without a completionNo resultNo result

A request waiting in the queue is not an error: its result comes when it is sent or finally dropped. A request that is still waiting when the app closes is sent after the next launch. On iOS its completion handler is not called in that case.

On iOS, logout drops the pings still waiting in the queue, and their completion reports loggedOut. Events still waiting are sent for the contact who logged out.


Platform guides​