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

# In-chat experiences

> The four experience types FirstFlow delivers inside the conversation guides, tours, surveys, and announcements and how the server composes and pushes them.

An **experience** is one thing FirstFlow delivers to a user inside your chat: an AI guide that answers a stuck user, a multi-step product tour, an NPS survey, or a one-shot announcement. Every experience renders in the same place the [`FirstflowWidget`](/react/widget) anchored to your composer so users are never pulled into a popup, a separate panel, or an email. You author each experience once in the dashboard, and the server decides when to show it and to whom.

The catalog below is the menu of what you can build. Each experience has a single `type`, chosen at creation and **immutable**, that determines which nodes are available in the editor and how the experience renders. Read this page to pick the right type for a goal; follow the inline links into [Authoring](/features/authoring) to build one and into [Targeting](/features/targeting) to control who sees it.

## How an experience reaches the user

The browser SDK is a **passive consumer**. It does not decide what to show it renders what arrives and reports activity back. Eligibility (triggers, audience, schedule, frequency, and any classifier gate) is evaluated **server-side**; when a user qualifies, the server walks the experience's flow graph, composes the finished [`WidgetTree`](/concepts/widgets-and-blocks), and **pushes it over Socket.IO**. That is why you cannot trigger a widget purely from the client: you report activity by sending the conversation's messages through the wrapped LLM client (or `notifyActivity()`), and the server makes the decision.

```mermaid theme={null}
flowchart TD
  A["User / assistant message<br/>in your chat"] -->|observed by @firstflow/sdk| B["Backend<br/>ConversationRouter"]
  B --> C{"Eligible?<br/>trigger · audience ·<br/>schedule · frequency"}
  C -->|no| Z["Nothing shown"]
  C -->|maybe| D["Classifier gate<br/>(LLM, if configured)"]
  D -->|qualifies| E["Walk flow graph<br/>to a Result node"]
  E --> F["Compose WidgetTree<br/>Anthropic claude-sonnet-4-6"]
  F -->|push over Socket.IO| G["FirstflowWidget<br/>renders the tree"]
  G -->|user interacts| H["widget.action<br/>flow.next / flow.back"]
  H -->|server-side nav| E

  classDef srv fill:#1f2937,stroke:#f59e0b,color:#fff;
  classDef cli fill:#0e7490,stroke:#22d3ee,color:#fff;
  classDef gate fill:#7c3aed,stroke:#c4b5fd,color:#fff;
  class B,D,E,F srv;
  class A,G,H cli;
  class C gate;
```

Two consequences follow from this model. First, **flow navigation is server-side**: when a user taps a "Next" button, the widget emits a `flow.next` action, the backend advances the walker and composes the next step, then pushes it down the browser never holds the whole flow. Second, **guides are composed at runtime** by Anthropic (`claude-sonnet-4-6`) from live conversation context, while tours, surveys, and announcements are authored step-by-step and rendered largely as written.

## The four experience types

The `type` you choose at creation is fixed for the life of the experience and gates everything downstream available node types in the editor, available triggers, and how the result renders.

### Guide

A guide is a single **AI-composed** widget. The backend walks the experience's flow graph to a terminal **Result** node, then hands the node's instruction plus the live conversation context to Anthropic, which composes a rich [`WidgetTree`](/concepts/widgets-and-blocks) headings, text, dynamic CTAs, inputs tailored to what the user is actually doing. Guides are the right choice for in-context answers, walkthroughs that adapt to the conversation, and "offer help when the user seems stuck" flows. They are typically fired by an LLM [classifier trigger](/concepts/triggers-and-audience) and default to a frequency of `always`. See [Experiences (concept)](/concepts/experiences) and [Flows & nodes](/concepts/flows-and-nodes) for the graph that drives them.

### Tour

A tour is a multi-step authored sequence of styled message cards that walks a user through a feature. Unlike a guide, the content is fixed at authoring time you compose **message**, **card**, **rich card**, **quick replies**, and **carousel** nodes in the editor, and the user steps through them with `flow.next` / `flow.back`. Use a tour when you want predictable, designed copy rather than AI-generated content. See [Flows & nodes](/concepts/flows-and-nodes) for the node types available in a tour.

### Survey

A survey collects structured data natively in chat no redirect to a survey tool. You build it from question nodes: **scale** (NPS, slider, or opinion scale via `scaleQuestionType`), **multiple choice**, **open question**, **checklist**, and **interview prompt**, with **text block** and **thank you** steps in between. Responses are **analytics-only**: each completed survey emits a `survey_completed` event to ClickHouse, and there is no separate transactional response store read results through [Analytics](/features/analytics). Prior answers are addressable as `answers.<questionId>` in later [conditions](/concepts/triggers-and-audience#condition-operators), so a survey can branch on what the user just said.

### Announcement

An announcement is a one-shot in-chat notification or feature banner a single piece of content the user acknowledges and dismisses. It is the lightest type: an **announcement** node holds the content, optionally preceded by **message** nodes or branching. Use it for changelog highlights, maintenance notices, and feature launches. Pair it with a `once` or `limited` [frequency](/concepts/triggers-and-audience) so a user does not see the same banner repeatedly.

## Where experiences surface

Every type renders through the same [`FirstflowWidget`](/react/widget), but two surfaces change *how* an experience starts and where it appears.

**Placement** is an experience setting that controls where the rendered widget sits: `overlay`, `inline`, `above-composer`, or `full-page`. It is configured per experience in the dashboard alongside triggers and audience see [Triggers & audience](/concepts/triggers-and-audience) not as a browser prop.

**Slash commands** give users an explicit way to start an experience. A command is an [`AgentCommand`](/react/commands) configured per agent whose `action` either triggers an experience (`{ type: "experience", experienceId }`) or emits an app action your code handles (`{ type: "action", key }`). Commands arrive over the realtime connection; read them from `useFirstflow().commands` and trigger one programmatically:

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

function HelpButton() {
  const ff = useFirstflow();
  // Find the command, then trigger it in the current conversation.
  const onboarding = ff.commands.find((c) => c.name === "Get started");
  return (
    <button onClick={() => onboarding && ff.triggerCommand(onboarding.id)}>
      Get started
    </button>
  );
}
```

To get the built-in `/` palette instead, pass your chat input's ref to the widget see [Slash commands](/react/commands) for the full setup. Selecting an `experience` command tells the backend to push the linked experience; selecting an `action` command delivers an `app.event` to your [`onAppEvent`](/react/widget) handler.

## Authoring and rendering

You build any experience three ways: by hand in the visual flow editor, by describing it in plain language for AI to generate (streamed live as it builds), or by importing a help article or feature page from a URL. Branching comes from rule-based **decision** nodes and LLM-based **classify** nodes, and mid-flow side-effects come from [API call](/integrations/api-calls), [webhook](/integrations/webhooks), and [Slack](/integrations/slack) nodes. The full toolkit lives in [Authoring](/features/authoring).

Whatever the type, the runtime artifact is a `WidgetTree` of declarative [blocks](/concepts/widgets-and-blocks) layout (`stack`, `row`, `card`), content (`title`, `text`, `media`), and interactive (`button`, `text_input`, `rating`, `slider`) primitives. The same tree renders identically in FirstFlow Cloud and in a [self-hosted](/self-hosting/overview) deployment because the schema lives in [`@firstflow/widget-kit`](/widget-kit/overview).

## Specific cases & limitations

<AccordionGroup>
  <Accordion title="Type is immutable after creation">
    An experience's `type` is chosen at creation and cannot be changed. To turn a
    tour into a guide, create a new experience. The type gates the node registry,
    so the editor only ever offers nodes valid for that type.
  </Accordion>

  <Accordion title="You can't force a widget from the browser">
    The browser SDK reports activity; the server decides eligibility. Calling
    `notifyActivity()` or sending messages through the wrapped LLM client does not
    guarantee a widget triggers, audience, schedule, and frequency are all
    evaluated server-side. A `triggerCommand` for an `experience` command is a
    request the backend still resolves against the experience's rules.
  </Accordion>

  <Accordion title="Survey responses are analytics-only">
    A completed survey emits a `survey_completed` event to ClickHouse. There is no
    transactional response table to query for raw answers surface results through
    [Analytics](/features/analytics). Within a flow, prior answers are available as
    `answers.<questionId>` for [conditions](/concepts/triggers-and-audience#condition-operators).
  </Accordion>

  <Accordion title="Guide content is non-deterministic">
    A guide's widget is composed at runtime by Anthropic from conversation context,
    so two users in different states see different content. Use a tour or
    announcement when you need exact, fixed copy.
  </Accordion>
</AccordionGroup>

## Next

To build an experience, start in [Authoring](/features/authoring); to control when and to whom it shows, see [Targeting](/features/targeting). For the underlying model, read the [Experiences concept](/concepts/experiences) and the [WidgetTree and blocks](/concepts/widgets-and-blocks) that every type renders into.
