Getting started / Quickstart

Quickstart

From a fresh account to autopilot's first set of flows — written for your app, in your theme, waiting for you to look at them. About ten minutes of it is yours; the rest happens without you.

  1. Create an app

    Sign up at app.upliftfunnel.com and add your app with its bundle ID and App Store link. The listing is read straight away into a draft app profile; the bundle ID is what locks your public key to your app. No listing yet is fine — the profile fills from the interview instead.
  2. Copy your public key

    Settings ▸ SDK & API. Public keys start with fnl_pk_ and are safe to ship inside a binary — they can read flows and report events, nothing else. The full key is shown once, at creation. More on keys →
  3. Add the SDK

    Package.swift
    // Xcode: File ▸ Add Package Dependencies…
    // or, in Package.swift:
    // registerPresenter arrived in 0.10.0. Older releases
    // cannot complete setup — the gate measures a presenter that did not exist.
    .package(
        url: "https://github.com/uplift-funnel/uplift-funnel-swift",
        from: "0.10.1"
    )
  4. Configure it once, at startup

    MyApp.swift
    import SwiftUI
    import UpliftFunnel
    
    @main
    struct MyApp: App {
        init() {
            Task { await UpliftFunnel.configure(apiKey: "fnl_pk_…") }
        }
    
        var body: some Scene {
            WindowGroup { ContentView() }
        }
    }
  5. Register a presenter

    This is the step that makes autopilot possible: your app stops naming flows and instead offers to show whatever the server decides on. Until a presenter is registered the SDK never even asks.

    AppRoot.swift
    // Somewhere that owns your root view. The SDK holds this weakly.
    UpliftFunnel.registerPresenter(self)
    
    extension AppRoot: UpliftPresenter {
        func presentFullscreen(flowKey: String, dismissible: Bool) async -> Bool {
            guard canInterrupt else { return false }   // your call, always
            coverFlowKey = flowKey                     // drives a .fullScreenCover
            return true
        }
    
        func presentSheet(flowKey: String, dismissible: Bool) async -> Bool {
            guard canInterrupt else { return false }
            sheetFlowKey = flowKey                     // drives a .sheet
            return true
        }
    }

    Returning false is always allowed and costs nothing — the frequency cap is not spent on a screen nobody saw. See Triggers & presentation.

  6. Hand over purchases, and publish your products

    A paywall screen draws the plans and the button. It does not charge the card — your app does, through handlers you register before a flow is presented.

    swift
    UpliftFunnel.registerPurchaseHandler { request in
        await myBilling.buy(request.productId) ? .purchased : .cancelled
    }
    UpliftFunnel.registerRestoreHandler { await myBilling.restore() }
    UpliftFunnel.setProducts([
        UpliftFunnelProduct(id: "yearly_pro", price: "$59.99", period: .year)
    ])

    setProducts is also one of the three signals the server watches for when it verifies your integration, so do it even if no paywall exists yet.

  7. Connect revenue

    A RevenueCat or Adapty webhook, or App Store Server Notifications V2. No keys are asked for. Revenue integrations →
  8. Answer five questions

    In Autopilot ▸ Setup, press Answer for me — the system fills the five in from your listing, your screenshots and early behaviour — then correct what is wrong. Saving an answer promotes it from a guess to a statement. This is the step that unlocks I'm ready. Setup in detail →
  9. Press “I’m ready”

    At the bottom of the same page. It stays disabled until four facts are on record — what the app does, who it is for, its aha moment, and what the copy may say — and the panel above it names whichever one is missing.

Then stop

Autopilot builds your profile, plans which flows you are missing, writes them, renders them across devices and languages, repairs what breaks, and stops at the approval gate. You do nothing in between, and nothing reaches a user until you press the button.

If you would rather drive

You can still name a flow and present it yourself — the editor and the SDK have not gone anywhere. This is the escape hatch, not the main road.

OnboardingScreen.swift
// The escape hatch: present a flow you named yourself.
UpliftFunnelFlowView(flowKey: "welcome") { result in
    save(result.variables)     // every answer the user gave
}

Next