Offline & Batching
The Datafly mobile SDKs are designed offline-first. Events are always persisted to a local SQLite database before any network request is attempted. This ensures zero data loss even when the device has no connectivity.
How it works
Event captured
↓
Written to SQLite (immediate, synchronous)
↓
Flush triggered? ─── No ──→ Wait for next trigger
│
Yes
↓
Network available? ─── No ──→ Wait for connectivity
│
Yes
↓
Batch events (up to 500, max 500KB)
↓
POST to /v1/batch
↓
Success? ─── No ──→ Retry with exponential backoff
│
Yes
↓
Delete events from SQLiteFlush triggers
Events are uploaded when any of these conditions are met:
| Trigger | Default | Configurable |
|---|---|---|
| Timer | Every 30 seconds | flushInterval / flushIntervalSeconds |
| Threshold | 20 events queued | flushThreshold |
| Manual | Call flush() | — |
| Network restored | Automatic | — |
Offline queue
- Storage: SQLite database (WAL mode on iOS for concurrent access)
- Maximum size: 1000 events (configurable via
maxQueueSize) - Overflow behaviour: When the queue is full, the oldest events are dropped to make room for new ones
- Crash recovery: On SDK init, any events left in “uploading” state are reset to “pending”
Batch transport
Events are uploaded in batches to the /v1/batch endpoint:
- Maximum batch size: 500 events
- Maximum payload size: 500 KB
- Large batch splitting: If a batch exceeds 500 KB, it is automatically split into smaller batches
- Authentication: Bearer token using the pipeline key
- Deduplication: The server deduplicates events by
messageId(UUID per event) via Redis
Retry policy
Failed uploads are retried with exponential backoff and jitter:
| Attempt | Base delay | With jitter (0-50%) |
|---|---|---|
| 1 | 1s | 1.0 — 1.5s |
| 2 | 2s | 2.0 — 3.0s |
| 3 | 4s | 4.0 — 6.0s |
| 4 | 8s | 8.0 — 12.0s |
| 5 | 16s | 16.0 — 24.0s |
| 6 | 32s | 32.0 — 48.0s |
Non-retryable status codes
The SDK does not retry requests that return:
| Status code | Reason |
|---|---|
200 | Success (no retry needed) |
400 | Bad request (payload issue, retrying won’t help) |
401 | Unauthorised (invalid pipeline key) |
403 | Forbidden (pipeline disabled or IP blocked) |
All other status codes (including 429 Too Many Requests and 5xx Server Error) are retried.
Network monitoring
The SDK monitors network connectivity using platform APIs:
- iOS:
NWPathMonitor(Network.framework) - Android:
ConnectivityManagerwithNetworkCallback
When connectivity is lost, upload attempts are paused. When connectivity is restored, a flush is triggered immediately.
Force flush
Call flush() to immediately upload all queued events:
// iOS
Datafly.shared.flush()
// Android
Datafly.flush()Common use cases for force flush:
- Before app termination or backgrounding (for critical events)
- After a purchase or conversion event
- When the user explicitly logs out
App lifecycle events (Application Backgrounded) are tracked automatically. The SDK does not automatically flush on background — events remain safely queued in SQLite and are sent on the next foreground or flush trigger.
Configuration
let config = DataflyConfig(
pipelineKey: "dk_live_abc123",
endpoint: "https://data.example.com",
flushInterval: 15, // Flush every 15 seconds
flushThreshold: 10, // Flush after 10 events
maxQueueSize: 5000 // Store up to 5000 events offline
)