# Mobile (RN / iOS / Android) (https://www.getfounderhq.com/docs/journeys/mobile)

Render a published Journey inside your Expo, React Native, iOS, or Android
app, with the same screens your web embed shows.

<Callout type="info" title="Before you start">
You need a published Journey in FounderHQ, its Journey ID, and a
publishable key (`fhq_pk_XXXX`). See [Journeys](/journeys) for how
keys work, and [Embed on the web](/journeys/embed-on-the-web) for the
props the native SDKs mirror.
</Callout>

## How the native SDKs work

Every platform SDK hosts the same Journey renderer and wraps it in a native
view. Config fetching and event capture stay in the platform's own
networking layer. Your app never puts a FounderHQ key in a URL.

Because the renderer is shared, a screen you publish once looks and behaves
the same on web and on device. Haptics run natively, not inside the web
view. Links are handed to your app to route.

Every SDK connects to `https://app.getfounderhq.com` by default and calls
`/api/v1/journeys/{journeyId}` for preparation, the published config,
capture, and completion. Set `baseUrl` (`baseURL` on iOS) only to point at
a local FounderHQ while you develop. The native SDKs accept any HTTPS
origin there and reject plain `http://` unless the host is local, so a bad
value fails loudly instead of leaking responses.

Native apps send no `Origin` header, so a key's allowed-origin list does
not gate them. It is still required when you create the key.

## Prepare before presenting

For an immediate opening, prepare the first screen while your app is visible,
then present it when the user chooses to continue. Preparation does not count
as a Journey view or start animations, media, or haptics. Each host retains one
web view and checks for updates while foregrounded.

- [Expo and React Native preparation](/journeys/mobile-preparation-react-native) — `@founderhq/journeys-react-native` 0.7.0 and later.
- [SwiftUI and UIKit preparation](/journeys/mobile-preparation-ios) — `FounderHQJourneys` 0.7.0 and later.
- [Android View and Compose preparation](/journeys/mobile-preparation-android) — Journeys 0.7.0 and later.

The direct `JourneyView` integrations below remain supported. For custom
clients, see the [preparation API](/journeys/api-reference/prepareJourney)
and [Limits and reliability](/journeys#limits-and-reliability).

## Expo and React Native

```sh
npx expo install react-native-webview react-native-safe-area-context expo-haptics
npm install @founderhq/journeys-react-native@^0.8.1
```

`react-native-webview` ships with Expo Go, so this SDK needs no custom
native module.

```tsx
import {
  JourneyView,
  type JourneyViewRef,
} from "@founderhq/journeys-react-native/expo";
import { useRef } from "react";

export function OnboardingJourney() {
  const journey = useRef<JourneyViewRef>(null);

  return (
    <JourneyView
      ref={journey}
      apiKey={process.env.EXPO_PUBLIC_FOUNDERHQ_KEY!}
      journeyId="journey_123"
      identity={{ externalId: "usr_1042" }}
      onEvent={(event) => {
        if (event.type === "complete") {
          // Continue into the app.
        }
      }}
      onOpenURL={(url) => {
        // Route through Expo Router or Linking.
      }}
      style={{ flex: 1 }}
    />
  );
}
```

Bare React Native imports `JourneyView` from the package root instead of
`/expo`.

Haptics differ by entry point. The Expo entry point maps every Journey
haptic to `expo-haptics`. The bare entry point uses React Native's
`Vibration` module, and you can pass `haptics={(type) => ...}` to route it
to your own haptics library without changing the Journey.

## iOS

`FounderHQJourneys` is a Swift Package for SwiftUI and UIKit. It supports
iOS 15 and later.

```swift
import FounderHQJourneys

struct OnboardingView: View {
    private let controller = JourneyController()

    var body: some View {
        JourneyView(
            configuration: JourneyConfiguration(
                apiKey: "fhq_pk_XXXX",
                journeyID: "journey_123",
                identity: JourneyIdentity(externalID: "usr_1042")
            ),
            controller: controller,
            onEvent: { event in
                if event.type == .complete {
                    // Continue into the app.
                }
            }
        )
    }
}
```

UIKit apps present `JourneyViewController` instead. `JourneyController`
publishes `canGoBack`, `currentStepID`, and `currentStepIndex`. Both entry
points accept your own loading and error views.

In Xcode, add `https://github.com/FounderHQ/founderhq-journeys-ios` using
Swift Package Manager, version **0.8.0** or later.

CocoaPods consumers can use:

```ruby
pod 'FounderHQJourneys', '~> 0.8.0'
```

Or install directly from the Git release:

```ruby
pod 'FounderHQJourneys', :git => 'https://github.com/FounderHQ/founderhq-journeys-ios.git', :tag => 'v0.8.0'
```

## Android

The Android SDK is a core View artifact plus an optional Jetpack Compose
adapter. It supports Android API 24 and later.

```kotlin
val journey = JourneyView(context)
journey.load(
    JourneyConfiguration(
        apiKey = "fhq_pk_XXXX",
        journeyId = "journey_123",
        identity = JourneyIdentity(externalId = "usr_1042"),
    ),
    object : JourneyListener {
        override fun onEvent(event: JourneyEvent) {
            if (event.type == JourneyEventType.COMPLETE) {
                // Continue into the native app.
            }
        }
    },
)
```

Compose apps use `com.founderhq.journeys.compose.JourneyView` and configure
the underlying View with `configureView`. The core View exposes
`loadingViewFactory`, `errorViewFactory`, `hapticHandler`,
`handleBackPressed()`, and the current navigation state.

Add `mavenCentral()` to your repositories and install:

```kotlin
implementation("com.getfounderhq:journeys:0.8.1")
// Optional Jetpack Compose integration:
implementation("com.getfounderhq:journeys-compose:0.8.1")
```

## What every platform gives you

| Capability | Expo / RN | iOS | Android |
| --- | --- | --- | --- |
| `goNext`, `goBack`, `goToStep`, `setAnswer`, `flushCapture`, `reload` | Yes | Yes | Yes |
| Typed events and discount callbacks | Yes | Yes | Yes |
| Native haptics | Yes | Yes | Yes |
| First-paint loading, custom loading and error views | Yes | Yes | Yes |
| Capture flushing on app lifecycle changes | Yes | Yes | Yes |
| Deep links and external links handed to your app | Yes | Yes | Yes |
| Local test configs and custom capture transports | Yes | Yes | Yes |
| Hardware Back handled | Yes | n/a | Yes |

## Verify

1. Run the app and open the screen that hosts the Journey. The first
   screen renders inside your native view.
2. Answer a screen and continue. The native back gesture or button walks
   you back one screen, not out of the flow.
3. Finish the flow, then open the Journey in FounderHQ. The response is
   listed with the contact you passed in `identity`.

## A note on `@founderhq/journeys-bridge`

`@founderhq/journeys-bridge` holds the message types the renderer and the
native hosts speak. Install a platform SDK instead. You only need the
bridge package if you are building a host of your own.
