Concepts / Flows, screens & variables

Flows, screens & variables

A flow is a sequence of screens with rules between them. Screens collect answers; the answers decide what the user sees next and what your app is handed at the end.

Flows

A flow belongs to an app and is addressed by its flow key — a slug like welcome or summer-paywall. That key is the only thing your app knows about the funnel. It stays the same while the flow behind it is redesigned, reordered and republished, which is what lets you change the whole thing without an app release.

Screens

A screen is one thing the user sees: a welcome, a question, a loading step, a paywall. You build it in the editor by placing sections — plan pickers, quizzes, feature lists, footers — and editing them on the phone canvas. There is no screen "type" that limits what a screen can contain; a paywall is a screen that happens to have a plan picker on it.

Variables

Anything that collects an answer stores it under a name you choose — a question might write goal, a slider weekly_sessions, a plan picker plan. Those names are the vocabulary of the rest of the funnel.

  • Personalization. Any text can include {{goal}}and the screen will say the user's own answer back to them.
  • Branching.A rule between screens can read them, and so can a single element's visibility — so one screen can show a line only to the people it applies to, instead of becoming two screens.
  • Results. When the flow ends, your app is handed the whole set.
swift
// Everything the user answered, when the flow ends.
UpliftFunnelFlowView(flowKey: "onboarding") { result in
    result.variables["goal"]      // what they picked
    result.variables["plan"]      // which plan they chose
    result.endReason              // "completed" / "abandoned" / "skipped"
}

Values your app already knows

A flow should not ask for a name you already have. Pass values in and the screens can use them from the first frame — for personalization, and for branching a subscriber past the paywall.

swift
// Values your app already knows, available to the flow from the first screen.
UpliftFunnelFlowView(
    flowKey: "onboarding",
    onCompleted: handle,
    userVariables: [
        "first_name": .string(user.firstName),
        "is_subscriber": .bool(user.isSubscriber)
    ]
)

What comes next

Each screen carries an ordered list of rules, and the first one that matches wins. A rule with no condition is the fallback and belongs last. A rule can go to a specific screen, to the next one, back, or end the flow with a reason — which is what reaches your onCompleted as endReason.

The Map view draws the whole funnel, every branch included, and flags a screen the flow can enter and never leave.

Languages

Copy is not tied to the design. Every translatable string in a flow has an entry per language, which is why one flow serves all of them and why the Translate view can show the whole thing as a table and fill the gaps. Adding a language never touches the layout.

Versions

Editing a flow changes a draft only your team can see. Deploying publishes a version, and devices pick it up on their next fetch — so a user midway through onboarding is never swapped onto a different flow. Versions & caching →