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

# Features

> Every FirstFlow capability in-chat experiences, server-side targeting, conversation analytics, two SDKs, and an MCP server and how they fit together.

FirstFlow is the onboarding and activation layer for AI agent and chat products.
You author **experiences** guides, tours, surveys, announcements that render
**inside the conversation**, decide who sees them and when on the server, and ship
them with two SDKs plus an MCP server. This page is the full catalog: read it
top-to-bottom for the mental model, or jump to the category you need.

The capabilities below are not independent toggles they form one runtime loop.
Your server SDK observes a conversation turn and tags it; the backend evaluates
eligibility and composes a widget; the browser SDK renders what arrives; user
interaction flows back and drives the next step. Understanding that loop (the
[mechanism](#how-the-pieces-fit) below) is what makes the rest of the catalog
read as a system rather than a feature list.

<Note>
  Every capability on this page is included in **both** FirstFlow Cloud and the
  open-source self-hosted build no edition split, no feature gating, no usage
  limits. See [Self-hosting](/self-hosting/overview).
</Note>

## Where most people start

Pick the entry point that matches what you are doing right now. Everything else
on this page is reachable through inline links in the relevant section.

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Wrap your LLM client, mount the provider, and see a widget in minutes.
  </Card>

  <Card title="How it works" icon="diagram-project" href="/how-it-works">
    The server-decides / browser-renders runtime loop, end to end.
  </Card>

  <Card title="Browser SDK" icon="react" href="/react/overview">
    `@firstflow/react` render pushed experiences in your chat UI.
  </Card>

  <Card title="Server SDK" icon="server" href="/server/overview">
    `@firstflow/sdk` wrap your LLM client to observe and power targeting.
  </Card>
</CardGroup>

## How the pieces fit

Eligibility triggers, audience, schedule, frequency, and the LLM classifier is
evaluated **server-side**. When a user qualifies, FirstFlow composes the widget
(for guides, Anthropic `claude-sonnet-4-6` renders a `WidgetTree`) and **pushes the
finished tree over Socket.IO**. The browser SDK is a passive consumer: it renders
what arrives and reports activity back. You cannot trigger a widget purely from the
client your server SDK observes the turn, and the server decides.

The diagram below traces one turn from the user's message to a rendered widget and
back. Note that flow navigation (`flow.next` / `flow.back`) is resolved on the
server too the browser only emits the intent.

```mermaid theme={null}
flowchart LR
  U([User message]) --> H[Host chat app]
  H -->|"wrapped LLM call<br/>tagged with agent/session/user"| S["@firstflow/sdk<br/>(your server)"]
  S -->|observe turn| B[FirstFlow backend]
  B -->|"evaluate triggers,<br/>audience, classifier"| E{Eligible?}
  E -->|no| X([nothing shown])
  E -->|yes| W["compose WidgetTree<br/>claude-sonnet-4-6"]
  W -->|push over Socket.IO| R["@firstflow/react<br/>(browser)"]
  R -->|render blocks| D([Widget in chat])
  D -->|"widget.action /<br/>flow.next"| B

  classDef srv fill:#1f6f54,stroke:#0c3a2c,color:#fff;
  classDef cli fill:#7a3b9e,stroke:#3f1d52,color:#fff;
  classDef be fill:#b5651d,stroke:#5e340f,color:#fff;
  class S,B,W,E srv;
  class R,D cli;
  class H be;
```

This is why instrumentation matters: the server can only target and analyze what
it observes. Tag every observed LLM call with all three identifiers
(`firstflowAgentId`, `sessionId`, `userId`) or the call passes through unobserved.
The rest of this catalog is the surface area on top of that loop.

## In-chat experiences

An [experience](/concepts/experiences) is one thing you deliver to users inside the
chat no popups, no second surface to maintain. Its `type` is chosen at creation
and is immutable, and it determines both how the experience renders and which node
types the editor offers. There are four:

* **Guide** a single **AI-composed** widget. The backend walks a flow graph to a
  result node, then composes a rich widget from the live conversation context. Best
  for in-context answers, dynamic CTAs, and walkthroughs that adapt to the user.
* **Tour** a multi-step authored sequence of styled message cards, for guided
  feature walkthroughs.
* **Survey** structured data collection answered natively in chat: NPS, opinion
  scales, multiple choice, checklists, and open questions.
* **Announcement** a one-shot in-chat notification or feature banner.

Tours, surveys, and announcements are authored step-by-step; only guides are
AI-composed at runtime. See [Experiences](/concepts/experiences) for the type model
and statuses (`draft` / `active` / `paused`).

Two cross-cutting capabilities sit alongside the four types. [Slash
commands](/react/commands) are agent-configured shortcuts a user runs from the
composer each command either triggers an experience (the backend pushes it) or
emits an app action your code handles. The renderable surface itself is the
[`WidgetTree`](/concepts/widgets-and-blocks): a small declarative document of block
primitives layout (`stack`, `row`, `card`), content (`title`, `text`, `media`),
interactive (`button`, `text_input`, `slider`, `rating`), and compound (`carousel`,
`checklist`). Text and inputs bind to widget state with a `ref`, and buttons fire
local, host, or remote actions.

A command is just data on the agent, read from `useFirstflow().commands`:

```ts theme={null}
type AgentCommand = {
  id: string;
  name: string;
  description?: string;
  icon?: string; // Lucide name, https:// image URL, or a single emoji
  action:
    | { type: "experience"; experienceId: string }
    | { type: "action"; key: string };
};
```

## Authoring

You build the [flow](/concepts/flows-and-nodes) behind an experience three ways: by
hand in the visual editor, by **AI generation** (describe it in plain language and
FirstFlow generates the flow, streamed live as it builds), or by **importing from a
URL** (point at a help article or feature page and FirstFlow extracts it into a
flow). All three produce the same artifact a `{ nodes, edges }` graph the backend
walks at runtime.

A flow branches and acts. **Classify** nodes route the flow with an LLM, using a
provider/model, custom instructions, a confidence floor, a resolution mode, and a
fallback branch for low confidence or errors. **Decision** nodes branch on rules
against `traits.*` and `answers.*` (AND within a branch, OR across branches; first
match wins). Action nodes call external systems mid-flow see
[API calls](/integrations/api-calls), [Webhooks](/integrations/webhooks), and
[Slack](/integrations/slack). For guides, a terminal **Result** node holds the
instruction the backend composes into a widget.

The editor graph you touch is `flow` (it carries UI chrome). On every save the
backend derives a normalized `flowRuntime` from it chrome stripped, edges
validated and that is what runs. You only ever edit `flow`. Match the widget to
your product with design tokens in [Theming](/react/theming).

## Targeting

[Triggers and audience](/concepts/triggers-and-audience) decide **when** an
experience appears and **who** sees it both evaluated entirely server-side, so the
browser cannot force a widget to show. Triggers are events: `chat_open`,
`after_user_message`, `after_idle`, `on_custom_event`, and the LLM
`conversation_classifier` gate (with guides also supporting
`after_user_and_agent_message`). A classifier trigger runs an LLM gate before
showing you configure instructions, provider/model, a confidence floor, a TTL, a
resolution mode, the context window, and signal masking for intent-driven
experiences like "offer help when the user seems stuck."

[Audience](/concepts/audience) decides who is eligible: **all** users, or only those
in a named **segment** computed from trait rules. Targeting needs data to match
against, so pass user traits via the browser [`user`](/react/identity) prop or the
server [`identify()`](/server/analytics) helper. Experience settings also carry
schedule (start/expire), frequency (`once`, `limited`, or `always` guides default
to `always`), priority when multiple experiences qualify, device, and placement.

## Analytics & sessions

Once your conversations are observed by the [server SDK](/server/overview), the
dashboard turns them into product understanding see
[Analytics & sessions](/features/analytics). The richer your instrumentation
([`observe()`](/server/observe) and [`trace()`](/server/traces)), the more these
surfaces can show.

* **Conversation analytics** volume, generations, total cost, latency, and error
  rate over a date range.
* **Sessions** every conversation's full transcript side-by-side with the LLM
  trace waterfall (model, tokens, latency, cost), plus tags and notes for review.
* **Session KPIs** LLM-graded quality evaluators scored per session: task
  completion, user friction, agent confusion, response quality, and user
  satisfaction, plus your own custom evaluators.
* **Topics & sentiment** automatic topic, intent, and sentiment classification
  against a taxonomy you curate.

Classification and KPI scoring run on the [AI provider](/integrations/ai-providers)
you configure. Survey responses are analytics-only there is no separate
transactional response store.

## Developer platform

FirstFlow ships two SDKs, a realtime widget, and an MCP server. The
[browser SDK](/react/overview) (`@firstflow/react`) opens the realtime connection,
renders pushed widgets, and handles end-user identity, client analytics, slash
commands, and theming. Mount the [provider](/react/provider) once and drop in the
[widget](/react/widget):

```tsx theme={null}
import { FirstflowProvider, FirstflowWidget } from "@firstflow/react";

<FirstflowProvider
  agentId="agt_…"
  publishableKey="pk_live_…"
  user={{ id: user.id, traits: { plan: user.plan } }}
  conversationId={conversationId}
>
  <YourChat />
  <FirstflowWidget />
</FirstflowProvider>;
```

The [server SDK](/server/overview) (`@firstflow/sdk`) wraps your existing LLM client
so every turn, trace, token count, and cost flows to FirstFlow which is also what
powers user-message triggers and classifier context. Wrap once and tag each call
with the three required identifiers; the wrapper strips them before the request
reaches OpenAI or Anthropic:

```ts theme={null}
import OpenAI from "openai";
import { wrapOpenAI } from "@firstflow/sdk/openai"; // reads FIRSTFLOW_API_KEY

const openai = wrapOpenAI(new OpenAI());

await openai.chat.completions.create({
  model: "gpt-4o",
  messages,
  firstflowAgentId: "agt_…",
  sessionId: conversationId, // must equal the browser's conversationId
  userId: user.id,
});
```

Subpaths cover [OpenAI, Anthropic, and any OpenAI-compatible
endpoint](/server/wrap-llm-client) (Ollama, vLLM, LM Studio via
`@firstflow/sdk/aiclient`), plus [LangChain / LangGraph](/server/langchain). The
fire-and-forget helpers [`observe()`](/server/observe),
[`trace()`](/server/traces), [`outcome()`](/server/outcomes), and
[`track()` / `identify()`](/server/analytics) never throw and never block the
request. For Next.js, [`@firstflow/nextjs`](/react/nextjs) re-exports the React
client and exposes `/server` subpaths.

Beyond the SDKs, [AI Connect (MCP)](/mcp/overview) lets any MCP-compatible coding
agent Claude Code, Cursor, Claude Desktop read your product context and build
experiences as tools, over OAuth 2.0 + PKCE. The [realtime
widget](/react/widget) is the server-pushed surface itself, authenticated with a
browser-safe publishable key.

<Warning>
  Tag every observed call with **all three** of `firstflowAgentId`, `sessionId`,
  and `userId`. Partial tagging means the call passes through to your provider
  **unobserved** (with a one-time warning) so it never appears in targeting,
  sessions, or analytics.
</Warning>

## Integrations

Flows reach outside FirstFlow through action nodes, and the platform connects to
LLM providers and your tools:

* **[Slack](/integrations/slack)** post messages and DMs from a flow.
* **[Webhooks](/integrations/webhooks)** deliver flow events to your endpoints,
  signed and retried with exponential backoff.
* **[API calls](/integrations/api-calls)** fetch external data inside a flow and
  feed it to downstream nodes.
* **[AI providers](/integrations/ai-providers)** Anthropic, OpenAI, Cloudflare
  Workers AI, or any OpenAI-compatible endpoint; assign which model powers each AI
  feature.

## Open source & self-hosting

The entire platform dashboard, API, and SDKs is MIT licensed and self-hostable
on your own infrastructure with no lock-in; start at
[Self-hosting](/self-hosting/overview). When you read or write these docs with a
coding agent, the [AI-friendly docs](/use-docs-with-ai) (`llms.txt`, per-page
Markdown, and Ask-AI) keep your agent grounded in current API surface.

## Next

If you are integrating, follow the [Quickstart](/quickstart); if you want the model
first, read [How it works](/how-it-works) and [Concepts](/concepts), then dive into
the [Browser SDK](/react/overview) or [Server SDK](/server/overview).
