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.

dart
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

ParameterTypeDefaultDescription
flowKeyStringPositional. The flow's key (slug) from the dashboard.
onCompletedvoid Function(UpliftFunnelFlowResult)?Called exactly once when the flow ends — whether completed, skipped, or abandoned. Inspect endReason to tell them apart.
unsupportedBuilderWidgetBuilder?nothing renderedWhat 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.
userVariablesMap<String, Object?>?Values injected into the flow session, available to screens as {{variable}} placeholders and to branching rules.
forceRefreshboolfalseSkip 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:

dart
UpliftFunnelFlow.experiment(
  'onboarding-test',               // experiment key, not a flow key
  onCompleted: (result) {
    final exp = result.experiment; // (experimentId, variantId) — or null
    _finish(result);
  },
)

The result

FieldTypeDescription
endReasonStringHow the flow ended: completed, abandoned, skipped, or a custom end:<reason> defined in the editor.
variablesMap<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.
sourceStringWhere 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

dart
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.