Offline-First Architecture
AppDNA SDKs are designed to deliver a fully functional experience even when the device has no internet connectivity. Every feature — onboarding flows, paywalls, experiment assignments, event tracking — works offline by default.Three-Tier Config Priority
When the SDK needs configuration, it resolves it using a strict fallback chain:The default config TTL is 1 hour. On app launch, the SDK attempts a remote fetch with a 3-second timeout. If the fetch fails or times out, the SDK immediately falls back to cached config. If no cache exists (e.g., first launch with no connectivity), the bundled config is used. Your app is never blocked waiting for a network response.
Config TTL and Refresh
The SDK checks whether the cached config has expired on every app launch and every return from background:1
App launches or returns to foreground
The SDK checks the age of the cached config against the configured TTL (default: 1 hour).
2
Remote fetch attempted
If the cache is stale (or does not exist), the SDK makes a background request to
GET /api/v1/sdk/config-bundle.3
Fallback on failure
If the remote fetch fails, the SDK continues using the cached config. If no cache exists, the bundled config is used.
4
Cache updated on success
If the remote fetch succeeds, the new config is written to disk and used immediately. UI components backed by config (paywalls, onboarding) update on the next presentation.
Event Queue
Events are never dropped. The SDK persists every event to disk before attempting delivery:- When
track()is called, the event is written to a persistent on-disk queue immediately. - The queue is auto-flushed every 30 seconds or when it reaches 20 events, whichever comes first.
- If the flush fails (no connectivity, server error, timeout), events remain in the queue and are retried on the next flush cycle with exponential backoff.
- Events are only removed from the queue after the server returns a successful acknowledgment.
Because events are persisted to disk, they survive app restarts, force-quits, and even device reboots. No event is ever lost due to a crash or connectivity issue.
Backoff Strategy
When a flush fails, the SDK backs off before retrying. The base delays are[1, 2, 4] seconds, each with ±25% random jitter, and the SDK makes at most 3 retries per flush cycle before giving up and waiting for the next cycle:
After the 3rd retry the flush is abandoned and retried on the next flush cycle. A server-supplied
Retry-After header, when present, overrides the computed delay. The retry counter resets after a successful flush.
Storage per Platform
Each platform uses native storage mechanisms for maximum reliability:The anonymous ID is stored in the most secure storage available on each platform (Keychain on iOS, Encrypted SharedPreferences on Android). This ensures the ID survives app reinstalls on iOS (as long as the Keychain entry is preserved) and is protected from unauthorized access.
Config Bundle Embedding
For zero-latency first launch, you can embed a config bundle JSON file in your app binary. The SDK automatically detects this file and uses it as the last-resort fallback when no remote or cached config is available.- iOS
- Android
- Flutter
- React Native
Add
appdna-config.json to your Xcode project as a bundle resource:- Drag
appdna-config.jsoninto your Xcode project navigator. - Ensure it is added to your app target under Build Phases > Copy Bundle Resources.
- The SDK automatically looks for this file in the main bundle on launch.
Offline Experiment Assignment
Experiments work fully offline because assignment is computed locally on-device using a deterministic hash function:getVariant() with zero network dependency.
Exposure events are still queued locally when offline and flushed to the server when connectivity returns. This means your experiment analytics remain accurate even when users interact with experiments while offline.

