> ## 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.

# FirstflowProvider

> The provider loads your experiences, runs the trigger engine, identifies the user, and holds runtime state. Mount it once above your app.

`FirstflowProvider` is the root of the browser SDK. It compiles the experiences you pass, runs the trigger engine, tracks the active run, and exposes everything through [`useFirstflow`](/react/use-firstflow). Mount it once, high in your tree.

```tsx theme={null}
import "@firstflow/runtime/styles.css";
import { FirstflowProvider, FirstflowWidget } from "@firstflow/runtime";

<FirstflowProvider
  user={{ id: user.id, traits: { plan: user.plan } }}
  experiences={experiences}
  persistence={persistence}
  onEvent={(e) => track(e)}
>
  <YourApp />
  <FirstflowWidget />
</FirstflowProvider>
```

## Props

<ParamField path="experiences" type="Experience[]" required>
  Your experiences in sequence form, typically imported from
  `firstflow/experiences.json`. Compiled to the internal graph form on receive.
  See [`SCHEMA.md`](https://github.com/firstflowdev/firstflow-oss/blob/main/packages/config-schema/SCHEMA.md).
</ParamField>

<ParamField path="user" type="FirstflowUser">
  The end user: `{ id, email?, createdAt?, traits? }`. **Optional** omit it and
  the runtime falls back to a stable per-browser [anonymous id](/react/identity).
  `traits` drive audience targeting and branching.
</ParamField>

<ParamField path="persistence" type="FirstflowPersistence">
  Where in-progress runs are stored and resumed. Pass
  `createSupabasePersistence(supabase)` from `@firstflow/runtime/supabase`, or
  implement the interface for another backend. Without it, the widget still
  renders but nothing persists or resumes.
</ParamField>

<ParamField path="onEvent" type="(event: FirstflowEvent) => void">
  Called for every runtime [event](/react/analytics) `experience.shown`,
  `step.entered`, `answer.submitted`, `action.triggered`, `experience.completed`,
  `experience.dismissed`. Route them to your own analytics.
</ParamField>

## Persistence

The default Supabase adapter is the fast path:

```tsx theme={null}
import { createSupabasePersistence } from "@firstflow/runtime/supabase";
import { createClient } from "@supabase/supabase-js";
import type { FirstflowDatabase } from "@firstflow/config-schema";

const supabase = createClient<FirstflowDatabase>(url, anonKey);
const persistence = createSupabasePersistence(supabase);
```

For another backend (your API, Mongo, Firestore), implement `FirstflowPersistence` directly `loadInProgress`, `hasCompleted`, `recordStart`, `recordProgress`, `recordEnd`. See [useFirstflow](/react/use-firstflow).

## Identity and resume

The provider reads `user.id` as the subject of `once_per_user` caps and in-progress resume. When `user` is absent it uses `getAnonymousId()`, so anonymous visitors still get caps and resume; their `traits.anonymous` is `true`. Pass a real id once the user signs in. See [Identity](/react/identity).

## Triggers

On mount the provider resumes any in-progress run (one read), then starts the trigger engine for `page_load`, `after_idle`, `custom_event`, and `url_match`. Fire a custom event from anywhere with `emit(name)` from the hook, or `emitCustomEvent(name)` standalone.

## Next

Render with [FirstflowWidget](/react/widget), drive it with [useFirstflow](/react/use-firstflow), or build a [custom shell](/widget-kit/overview).
