> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstflow.app/llms.txt
> Use this file to discover all available pages before exploring further.

# useFirstflow

> The hook exposes runtime state and the imperative API: start, advance, dismiss, emit events, run actions, and minimize.

`useFirstflow()` returns the current runtime state and the methods to drive it. Use it to trigger experiences from your own UI, build a [custom shell](/widget-kit/overview), or react to the active step. It must be called inside `FirstflowProvider`.

```tsx theme={null}
import { useFirstflow } from "@firstflow/runtime";

function Launcher() {
  const { startExperience, active } = useFirstflow();
  return (
    <button disabled={!!active} onClick={() => startExperience("exp_welcome")}>
      Show onboarding
    </button>
  );
}
```

## State

<ParamField path="active" type="ActiveExperienceState | null">
  The running experience and its position (`experience`, `currentNodeId`,
  `history`, `answers`), or `null` when nothing is showing.
</ParamField>

<ParamField path="user" type="FirstflowUser">
  The resolved user your `user`, or the anonymous fallback.
</ParamField>

<ParamField path="session" type="FirstflowSession">
  Auto-tracked session context (`url`, `locale`, `deviceType`, `startedAt`) used
  by audience conditions.
</ParamField>

<ParamField path="experiences" type="CompiledExperience[]">
  The compiled experiences the provider loaded.
</ParamField>

## Methods

<ParamField path="startExperience" type="(id: string) => void">
  Start an experience by id (bypasses triggers). No-op if the id is unknown.
</ParamField>

<ParamField path="advance" type="(answer?: { questionId, value }) => void">
  Advance the active run to the next visible node, optionally recording an answer.
</ParamField>

<ParamField path="dismiss" type="() => void">
  End the active run and record it dismissed.
</ParamField>

<ParamField path="emit" type="(eventName: string) => void">
  Fire a custom event triggers any experience with a matching
  `custom_event` trigger. The standalone `emitCustomEvent(name)` does the same
  from outside the provider.
</ParamField>

<ParamField path="executeAction" type="(action, ctx?) => void">
  Run a single compiled action (`next`, `submit`, `dismiss`, `link`, `event`,
  `prompt`, `minimize`). Used by the default blocks.
</ParamField>

<ParamField path="executeActions" type="(actions, ctx?) => void">
  Run an ordered list of actions for one interaction. Non-terminal actions
  (`link`/`event`/`prompt`/`minimize`) run in author order; the single terminal
  action (`next`/`submit`/`dismiss`) runs last.
</ParamField>

<ParamField path="minimize" type="() => void">
  Collapse the widget shell to its resting state without ending the run.
</ParamField>

<ParamField path="registerMinimizeHandler" type="(fn) => () => void">
  Register a collapse handler so the `minimize` action can reach a custom shell.
  Returns an unregister function.
</ParamField>

## Persistence interface

Pass any object implementing `FirstflowPersistence` to the provider. Implement it for a non-Supabase backend:

```ts theme={null}
interface FirstflowPersistence {
  loadInProgress(userId: string): Promise<InProgressRun[]>;
  hasCompleted(userId: string, experienceId: string): Promise<boolean>;
  recordStart(userId, experienceId, state): Promise<{ runId: string }>;
  recordProgress(runId: string, state): Promise<void>;
  recordEnd(runId: string, status: "completed" | "dismissed"): Promise<void>;
}
```

`loadInProgress` runs once on mount (for resume); `recordProgress` fires on every transition; `recordEnd` fires on completion or dismissal. All writes are fire-and-forget failures are logged, never thrown.

## Custom launcher with events

```tsx theme={null}
const { emit } = useFirstflow();
// elsewhere, after an LLM reply classifies the intent:
if (intent === "billing") emit("show_billing_help"); // fires the matching trigger
```

## Next

Build a [custom shell](/widget-kit/overview), handle [events](/react/analytics), or wire the [server SDK](/server/overview) classifier to drive `emit`.
