Flutter SDK / Rendering flows
Rendering flows
UpliftFunnelFlow is the whole integration in one widget: it fetches the flow by key, caches it, shows loading and error states, renders every screen natively, and hands you the result.
UpliftFunnelFlow(
'welcome', // flow key from the dashboard
onCompleted: (result) {
if (result.endReason == 'completed') {
// Persist answers, route into the app…
saveProfile(result.variables);
}
Navigator.of(context).pushReplacementNamed('/home');
},
)Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
| flowKey | String | — | Positional. The flow's key (slug) from the dashboard. |
| onCompleted | void Function(UpliftFunnelFlowResult)? | — | Called exactly once when the flow ends — whether completed, skipped, or abandoned. Inspect endReason to tell them apart. |
| unsupportedBuilder | WidgetBuilder? | nothing rendered | What to show where the engine does not run. The default is an empty box rather than a crash, but UpliftFunnel.isSupported is the honest way to branch. |
| userVariables | Map<String, Object?>? | — | Values injected into the flow session, available to screens as {{variable}} placeholders and to branching rules. |
| forceRefresh | bool | false | Skip the device cache and await a fresh fetch from the network. |
UpliftFunnelFlow.experiment(key, …) takes the same parameters but treats the key as an experiment key:
UpliftFunnelFlow.experiment(
'onboarding-test', // experiment key, not a flow key
onCompleted: (result) {
final exp = result.experiment; // (experimentId, variantId) — or null
_finish(result);
},
)The result
| Field | Type | Description |
|---|---|---|
| endReason | String | How the flow ended: completed, abandoned, skipped, or a custom end:<reason> defined in the editor. |
| variables | Map<String, String> | Every answer collected over the session — quiz answers, selected plan, text inputs. Values are strings: they cross the channel as the engine stored them, and a flow variable is text by the time it is saved. |
| source | String | Where the flow came from: network, cache, or cacheRevalidated. Useful for surfacing offline state. |
| experiment | ({String experimentId, String variantId})? | The A/B assignment the session ran under, as a record, or null for a plain flow. |
Custom loading & error states
if (!UpliftFunnel.isSupported) return const MyOwnOnboarding();
UpliftFunnelFlow(
'welcome',
userVariables: {'name': user.firstName}, // usable as {{name}} in screens
forceRefresh: false,
unsupportedBuilder: (context) => const MyOwnOnboarding(),
onCompleted: (result) => _finish(result),
)The loading and error states are the engine's own, rendered inside your widget tree, and the error one already offers a retry — there is nothing to pass for them. Caching, offline & errors covers how a failure is classified, and how often the cache means you never see one.