# Journeys (https://www.getfounderhq.com/docs/journeys)

A Journey is a guided flow you put in front of a person: onboarding, a
quiz, a survey, a pricing screen. You build it inside FounderHQ. You render
it inside your own product with the FounderHQ SDK, or
[share it without code](/journeys/share) as a public link, an embed, or a
QR code on your phone.

## What you get

- **One flow, every platform.** The same published Journey renders on the
  web, in Expo and React Native, in SwiftUI and UIKit, and in Android Views
  and Jetpack Compose.
- **Changes without a release.** The SDK fetches the published config at
  render time. You edit the flow in FounderHQ and the next render shows it.
  No app-store submission.
- **Answers tied to a contact.** Your app tells the SDK who the person is.
  FounderHQ links the response to that contact.
- **Branching without code.** Routing rules pick the next screen from the
  answers so far. Computed variables derive new values from those answers.

## How it fits together

1. You build and publish the Journey in FounderHQ.
2. You copy the Journey's ID and a publishable key.
3. You render `<Journey />` in your app with those two values.
4. Responses and step events show up back in FounderHQ.

## Keys

A Journey renders with a publishable key (`fhq_pk_XXXX`). The key belongs
to one brand. It is safe in browsers and in shipped mobile apps: every
config fetch, every access check, and every captured event is validated on
FounderHQ's servers. Never put a secret key (`fhq_sk_XXXX`) in a Journey.

Create the key in FounderHQ under **Settings → API keys** and pick the
**Journey embed** preset. It gives the key exactly two permissions:

| Permission | What it allows |
| --- | --- |
| `journeys:read_published` | Read the published config of a Journey in the key's brand. |
| `journeys:capture` | Record step events, answers, and completions. |

A Journey embed key needs at least one allowed origin. FounderHQ refuses to
create it without one, and refuses a request whose `Origin` is not on the
list. Add the origins your pages are served from — scheme, host, and port,
with no path:

```
https://your-domain.com
https://www.your-domain.com
http://localhost:3000
```

Native SDKs send no `Origin` header, so the list does not gate them.

Scope the key to one brand, and to specific Journeys when you can. Do not
reuse one key across brands: a key can only read Journeys in the brand it
was created for, so a shared key fails the moment you add a second brand.

## Where the SDKs connect

Every Journeys SDK talks to `https://app.getfounderhq.com`, the FounderHQ
app host. Analytics use a separate ingest host. You do not configure the
production Journey host.

Every SDK takes a base-URL override for local development, and each one
guards it:

| SDK | Option | What it accepts |
| --- | --- | --- |
| `@founderhq/journeys` (web) | `baseUrl` | A localhost address only. Every other value silently falls back to `https://app.getfounderhq.com`. |
| React Native, iOS, Android | `baseUrl` / `baseURL` | Any HTTPS origin. Plain `http://` only for a local host, and an invalid value throws. |

On the web that fallback means a mistyped `baseUrl` cannot quietly send
responses somewhere else. It also means you cannot point a web embed at a
proxy of your own.

## Limits and reliability

| Rule | Value |
| --- | --- |
| Events per capture batch | 50. A larger batch is refused with `400`. |
| Request body | Keep it under 256 KiB. |
| Over budget | `429` with a `Retry-After` header, in whole seconds. |

Budgets are counted per organization. Brands, keys, Journeys, and app
installations all spend from the same allowance, so adding a key does not
add capacity.

If you write your own client instead of using an SDK:

- Honor `Retry-After` on a `429`. Do not retry sooner, and do not retry in
  a tight loop.
- Give every event a stable `id` and reuse it on a retry. FounderHQ
  de-duplicates by event ID, so a replayed batch is safe.
- Send one `clientSessionId` for the whole presentation, and keep it on
  events you deliver late.
- You may send an `X-FounderHQ-Installation-Id` header on the load calls
  (`prepare`, the published-config `GET`, and `validate`). It identifies one
  app installation for per-client fairness. It is optional, allowed through
  CORS, and no shipped SDK sends it yet.

## Start here

- [Embed on the web](/journeys/embed-on-the-web) — install the
  package and render your first Journey.
- [Mobile (RN / iOS / Android)](/journeys/mobile) — the native SDKs
  and what each one exposes.
- [Steps and blocks reference](/journeys/steps-and-blocks-reference) —
  every screen type and every block you can place on an info page.
