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

# Userpilot and Subtext: From a Flow Drop to the Session

> Attach the Subtext session URL to Userpilot, then jump from any onboarding drop or flow-step leak straight into the user's real session.

Userpilot tells you *that* a user fell out of a flow or stalled in onboarding. It can't show you *what* they saw when they left. Subtext can. Attach the Subtext session URL to your Userpilot users and every drop becomes a jumping-off point — your agent reads the `subtext_url`, opens that person's real session, and walks the decisive moments with screenshots, the component tree, network, and console. Userpilot detects; Subtext diagnoses.

<Note>
  This guide assumes the [Subtext capture snippet](/docs/install/overview) is installed and capturing sessions, and the Userpilot SDK (`userpilot`) is initialized.
</Note>

## Attach the session URL

Store the current Subtext session URL as a Userpilot user property so it rides along with the user into every flow, segment, and analytics view. Attach it with `userpilot.identify`, wherever your app already identifies the user — on auth resolution, not at module top level.

<CodeGroup>
  ```js analytics.js theme={null}
  const subtextUrl = FS('getSession', { format: 'url.now' })
  if (subtextUrl) {
    userpilot.identify(user.id, { subtext_url: subtextUrl })
  }
  ```

  ```tsx React theme={null}
  useEffect(() => {
    if (!user) return
    FS('setIdentity', { uid: user.id, properties: { email: user.email } })
    const subtextUrl = FS('getSession', { format: 'url.now' })
    if (subtextUrl) {
      userpilot.identify(user.id, {
        email: user.email,
        subtext_url: subtextUrl,
      })
    }
  }, [user])
  ```
</CodeGroup>

Call `userpilot.reload()` on route changes as usual; identified properties persist across reloads within the session.

<Warning>
  Don't read `FS('getSession')` at module top level — it returns `null` until the session has started. Don't call `userpilot.identify` before the SDK is initialized with your app token, and don't identify anonymous users with a throwaway id — attach the URL once the user is known so it reconciles to the right profile. The session URL also changes on a new session and when `FS('setIdentity')` is called with a different `uid`, so re-call `userpilot.identify` on every re-identify; the property stays frozen until the next identify.
</Warning>

## From signal to session

However you first hear about a leak in Userpilot — an activation drop, a churn-risk flag, or a single flow step bleeding users — the path is the same: get to the `subtext_url`, then hand it to your agent for a Detect-vs-Diagnose read.

<AccordionGroup>
  <Accordion title="An activation dashboard drop">
    Your Userpilot activation dashboard shows new users completing onboarding at a lower rate than usual.

    Build a segment of users who didn't complete onboarding, open their user records, go to the **Properties** tab, and copy `subtext_url`. Grab several, then hand them to your agent:

    ```text theme={null}
    Userpilot shows our onboarding completion rate dropping. Here are sessions from users who didn't
    finish:
    <PASTE 3-4 subtext_urls>

    Review them and find where activation leaks. At which step do they stall, did each step render
    correctly, and is it broken / confusing / too long? Detect-vs-Diagnose: the data says they
    dropped — what does the session show caused it? One synthesized hypothesis + the moments.
    ```
  </Accordion>

  <Accordion title="A churn-risk or low-engagement signal">
    A Userpilot segment surfaces an account or user flagged as low-engagement or churn-risk after a rough onboarding.

    Open the flagged user, go to the **Properties** tab, and copy `subtext_url`.

    ```text theme={null}
    Userpilot flagged this user as churn-risk after a weak onboarding. Session: <PASTE subtext_url>

    Open it and tell me what their early experience was actually like — where they struggled, what
    they never discovered, and whether a bug or confusion soured them. I want to know if this is
    salvageable with a nudge or if the product failed them.
    ```
  </Accordion>

  <Accordion title="A single flow step leaking">
    Userpilot flow analytics show a single step with a large drop.

    Segment the users who dropped at that step and copy `subtext_url` from each.

    ```text theme={null}
    This Userpilot flow loses a lot of users at the <step name> step. Here are sessions from users
    who dropped there:
    <PASTE subtext_urls>

    Walk each one to that step. When it appeared, did it render correctly and target the right element,
    or was it mis-positioned / mistimed / unclear? Tell me the common reason they bail, with evidence.
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  For a flow redesign, ask your agent to capture a proof document (`doc-create`) showing the step as the droppers saw it, then paste it into your Userpilot flow notes so the completion number carries its cause. A "step mis-renders or mistargets" verdict is the high-leverage find: invisible in the completion rate, obvious in the session, usually a quick fix.
</Tip>

## For agents

An autonomous agent can run the same loop against Userpilot, with one honest caveat. Userpilot's real-time HTTP API is write-only — `identify` and `track` on `analytex.userpilot.io` — so there is no per-user GET to fetch a single visitor's attributes on demand. But Userpilot also documents a Bulk Data Export API (`POST appex.userpilot.io/api/v1/analytics/exports`, token auth) that exports raw events — including `identify_user` events carrying custom metadata like `subtext_url` — as JSON/CSV export jobs. You write `subtext_url` in via identify; reading it back over HTTP means an asynchronous bulk export, not a point lookup. Userpilot does ship an official MCP server (`userpilot.com/ai/mcp-server/`), but its endpoint, transport, auth model, and tool names aren't publicly documented, and whether it can read an individual visitor's custom attribute is unconfirmed. Confirm those before you depend on the round-trip, and for reliable extraction store `subtext_url` somewhere readable too — your warehouse, or another tool's user property.

<Steps>
  <Step title="Discover who is affected">
    Use the Userpilot MCP server to surface the friction: adoption and retention drops, low-completion flows, NPS detractors, and survey sentiment. The real-time HTTP API cannot query friction data on demand, but Userpilot's Bulk Data Export API (Enterprise plan, or an add-on to Growth) can deliver it as async export jobs — raw JSON/CSV events including flow, checklist, survey, and NPS `interaction` events. Without that plan, fall back to a warehouse or reverse-ETL export you can query directly.
  </Step>

  <Step title="Extract the session URL">
    There is no per-user read API. Get `subtext_url` from an MCP attribute tool if one exists (verify first), from an analytics or warehouse export where Userpilot data lands, or from another store that captured it at the same moment.
  </Step>

  <Step title="Hand off to Subtext">
    For each URL, call `review-open(session_url=<subtext_url>)` on the Subtext MCP, then walk the flow step where the user dropped for a Detect-vs-Diagnose read.
  </Step>
</Steps>

<Note>
  `subtext_url` only round-trips if it was attached at capture time (see [Attach the session URL](#attach-the-session-url)). Because Userpilot has no per-user attribute read — only asynchronous bulk exports (Enterprise plan, or a Growth add-on) — plan a readable secondary store from the start; the MCP discovery surface and the export API are more dependable than any per-user attribute read.
</Note>

## Related

* [Session Review overview](/docs/session-review/overview) — what your agent does once a session is open.
* [Install the capture snippet](/docs/install/overview) — required before any session URL exists to attach.
