Offline Fallback
Bundle resolved placements with the app so a first launch with no network still opens its funnel.
Two caches stand between the device and an empty screen: the last-known placement response on disk, and — for a first launch with no network and no cache — a fallback file bundled with the app. This page is the fallback file. For the disk cache, see The native path.
Export the fallback file
In the dashboard, open SDK → Offline fallback and click Download. You
get rovenue-fallback.json: every active placement, resolved anonymously —
empty attributes, no locale: the honest approximation of what a first-launch
device with no network and no cache would get.
Whatever a placement targets rides along — a funnel, or an experiment over
funnels — because the export shares resolvePlacement with the live
endpoint, so both share exactly the same targeting semantics. One file and
one setFallbackPlacements call keeps placements resolving offline.
Funnels are the case that matters most — a first-run onboarding that
cannot open offline is the whole first impression.
The file is a JSON object, not an array — placements keyed by identifier,
each value exactly the data envelope a live GET /v1/placements/:identifier
returns:
{
"formatVersion": 1,
"generatedAt": 1758300000000,
"projectId": "proj_123",
"placements": {
"onboarding": {
"placement": { "identifier": "onboarding", "revision": 7 },
"funnel": { "...": "the resolved native funnel" },
"experiment": null
}
}
}formatVersion must be literally 1, or the SDK throws
(packages/core-rs/src/librovenue.udl:266-274). Regenerate the file
whenever you publish — it is a snapshot, and the SDK only reaches for it
when it has nothing fresher.
Load it per platform
Load once at launch, replacing any previously-loaded set. An individual
placement entry that fails to decode is skipped, not fatal, and does not
count toward the returned total
(packages/core-rs/src/librovenue.udl:266-274).
On Swift, from a bundled asset or a JSON string
(packages/sdk-swift/Sources/Rovenue/Rovenue.swift:769-793); on Kotlin,
from an Android asset or a JSON string
(packages/sdk-kotlin/src/main/kotlin/dev/rovenue/sdk/Rovenue.kt:719-734);
on React Native, from a JSON string via Rovenue.setFallbackPlacements
(packages/sdk-rn/src/index.ts:99); on Flutter, from a JSON string via
Rovenue.instance.setFallbackPlacements
(packages/sdk-flutter/rovenue_flutter/lib/src/rovenue.dart:169).
When getFunnel runs it tries network first, then the disk cache, then the
fallback: the resolved funnel carries servedFromFallback, true only when
the bundled file answered
(packages/sdk-swift/Sources/Rovenue/FunnelUI/ResolvedFunnel.swift:18-21).
A/B variant selection stays deterministic from the fallback — the same
subscriber plus the same experiment key draws the same variant offline as
online.
A stale export means an offline device keeps resolving whatever the placement pointed to when the file was generated. Re-export whenever you publish, and whenever you start, stop, or retarget an experiment on a placement you ship offline coverage for.