The fail-safe resolution chain
Every present and prefetch resolves a placement through the same ordered chain. Each tier is tried until one yields a presentable flow:| Tier | Source | Network | When it wins |
|---|---|---|---|
| 0 | Fresh cache hit | none | A cached flow is still within its freshness TTL. Presented instantly. |
| 1 | Live resolve | yes | No fresh cache. Bounded by resolveTimeout (default 4s). On success, validated and cached. |
| 2 | Stale cache (last-known-good) | none | The live resolve failed or timed out, but an older cached flow exists (TTL ignored). |
| 3 | Bundled default flow | none | Everything above missed. Renders a flow you shipped in the app. See Offline and bundled flows. |
resolveSession returns null, or the presenter fallback renders).
Every analytics event carries the tier it was served from as delivery_source (network, cache, stale_cache, bundled_default), so offline and fallback renders are distinguishable in the dashboard. See Analytics.
The resolve deadline does not strand the cache
A live resolve that hitsresolveTimeout degrades the current caller to a fallback tier, but it does not cancel the in-flight request. The resolve keeps running to populate the cache, so the next caller hits a warm Tier 0. A slow network therefore never hangs onboarding, and the cost of a slow first present is not wasted. Concurrent resolves for the same key are also coalesced into one round-trip, so a prefetch and a present that race share a single request.
Cache freshness (TTL)
A cached flow is “fresh” for a number of seconds, after which Tier 0 misses and the SDK re-resolves (falling back to the same entry as stale cache if the network fails). The TTL comes from the resolve response’scacheTtlSeconds; when the backend omits it, the SDK uses the environment default:
| Environment | Default TTL |
|---|---|
development | 0 (a fresh entry expires immediately, so effectively no caching) |
staging | 60 seconds |
production | 300 seconds |
Because
development defaults to a 0 TTL, prefetching and “fast repeat present” have no visible effect there. Test caching behavior against staging or production. See Configuration.Identity-scoped cache keys
Cached flows are keyed by an identity fingerprint, a hash of the per-install user ID and any targeting attributes the resolve was personalized by. This guarantees a flow cached for one user (or one A/B variant) is never served to another after an identity change. The stale-cache tier keeps a fingerprint-agnostic last-known-good alias, so a previously-seen flow can still render offline even right after the identity changes.Enabling and disabling caching
Caching is on by default. Turn it off withcachingEnabled: false:
Clearing the cache
clearCache() is the lever to pull during testing when you have published a new flow version and want to bypass the TTL. In production, prefer attaching the new version in the dashboard and letting the TTL expire.
Common mistakes
- Testing caching against
development. The0default TTL means nothing stays fresh. Usestaging/production. - Disabling caching and expecting prefetch to work. Prefetch is a no-op with caching off.
- Expecting a republished flow to appear instantly. A fresh cached copy is served until its TTL expires, and the placement must point at the new version. Clear the cache or attach the new version. See Troubleshooting.
- Assuming offline always works. Offline rendering needs either a prior cache entry or a bundled default. Ship a bundled default for guaranteed offline onboarding.
Troubleshooting
- Old flow still showing after republish. The cache is fresh, or the placement still points at the old version. Attach the new version, then
clearCache()or wait out the TTL. - First present is slow on a poor network. Expected on a cold cache. Ship a bundled default and prefetch at launch so Tier 0/Tier 3 cover the first present. See Prefetching.
- A flow renders offline that you did not expect. It came from stale cache or a bundled default. Check the
delivery_sourcein debug logs.