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

# Sprig and Subtext: From a Survey Response to the Session

> Attach the Subtext session URL to your Sprig survey responses, then jump from any low score or open-text comment straight into the user's real session.

Sprig tells you *what* a user said: a low score, a detractor comment, a confusing open-text verbatim. It can't tell you *what actually happened* on their screen when they said it. Subtext can. Attach the Subtext session URL to your Sprig visitor attributes and every survey response carries a deep link back to the real session — your agent reads the `subtext_url`, opens that person's session, and walks the decisive moments with screenshots, the component tree, network, and console. Sprig detects; Subtext diagnoses.

<Note>
  This guide assumes the [Subtext capture snippet](/docs/install/overview) is installed and the Sprig browser SDK is initialized (via the Sprig HTML snippet, or via `@sprig-technologies/sprig-browser` using the equivalent method-call syntax, `Sprig.setAttributes(...)` / `Sprig.setUserId(...)`).
</Note>

## Attach the session URL

Attach the current Subtext session URL to the Sprig visitor with `setAttributes`. It rides along on the visitor and is stamped onto any survey responses they submit, so each response carries a deep link back to what the user was doing. Call it 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) {
    Sprig('setAttributes', { 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) {
      Sprig('setUserId', user.id)
      Sprig('setAttributes', { subtext_url: subtextUrl })
    }
  }, [user])
  ```
</CodeGroup>

Set the attribute before a survey is likely to trigger so an in-progress response captures it. Re-setting it later updates the value for subsequent responses.

<Warning>
  Don't read `FS('getSession')` at module top level — it returns `null` until the session has started. The session URL also changes on a new session and when `FS('setIdentity')` is called with a different `uid`, so re-call `Sprig('setAttributes', …)` whenever you re-identify the user. The attribute is frozen until the next call, and responses use whatever value was set when they were submitted. Keep the URL as an attribute — don't put it in the survey question text, so it stays queryable across responses.
</Warning>

## From signal to session

However you first hear about it in Sprig — a detractor notification, a vague verbatim, a recurring theme at study wrap-up — the path is the same: get to the `subtext_url`, then hand it to your agent for a Detect-vs-Diagnose read. A Sprig response is what the user *said*; the `subtext_url` stamped on it is what they *did*.

<AccordionGroup>
  <Accordion title="A detractor or low-score response notification">
    Sprig notifies you of a low-score response with a comment like *"couldn't find where to export."*

    Open the study, go to **Responses**, open the response, go to **Attributes**, and copy `subtext_url`. Then hand it to your agent:

    ```text theme={null}
    A Sprig respondent scored us low and wrote: "couldn't find where to export." Here's their
    session: <paste subtext_url>

    Open it and ground the feedback in reality. Did they actually go looking for export? Where did
    they look, what did they miss, and is the control genuinely hard to find or were they looking in
    the wrong place? Point me to the exact moments. Detect-vs-Diagnose: the survey says X — does the
    session confirm it?
    ```
  </Accordion>

  <Accordion title="A confusing open-text comment">
    A response says something ambiguous — *"it just didn't work"* — and the words alone are useless.

    Open that response, go to **Attributes**, and copy `subtext_url`.

    ```text theme={null}
    This Sprig comment is too vague to act on: "<paste response text>". Here's the respondent's
    session: <paste subtext_url>

    Open it and tell me what they're actually referring to. What were they doing when it "didn't
    work," what broke or confused them, and is it reproducible? Translate the vague feedback into a
    concrete, located problem.
    ```
  </Accordion>

  <Accordion title="A theme in negative feedback at study wrap-up">
    You're closing out a study and a recurring complaint shows up across several responses.

    Filter responses by the low score or theme and copy `subtext_url` from each (or export the responses — `subtext_url` is a column).

    ```text theme={null}
    At the end of this Sprig study, several people complained about <theme>. Here are their sessions:
    <paste 3–4 subtext_urls>

    Review them together and find the shared UX pattern behind the complaint. Is everyone hitting the
    same moment of friction, or different things they're describing similarly? Give me the one concrete
    problem to fix, with the moments that prove it across sessions.
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  For a study wrap-up, ask your agent to assemble a proof document (`doc-create`) with a screenshot of the friction moment per respondent, then attach it to your research synthesis — the verbatim now carries the behavior that explains it. The whole point is closing the say-do gap: a low score with a session attached shows not just that someone was unhappy, but exactly where and why, and whether it reproduces.
</Tip>

## For agents

An autonomous agent can run the whole loop against Sprig directly: find the low-score or themed feedback, extract the stored `subtext_url`, and hand each session to the Subtext MCP.

Sprig ships an official MCP server at `https://mcp.sprig.com/mcp`, authenticated with OAuth 2.0 (an admin enables it at **Settings → Agents → Sprig MCP**; members connect their own accounts, scoped to workspace permissions). It exposes three tools — Retrieve Surveys, Retrieve Responses, and Retrieve Themes — enough for the discovery loop below; use the Data Export API when you need bulk extraction.

<Steps>
  <Step title="Discover the friction">
    Start with the Sprig MCP: **Retrieve Surveys** lists the studies in the workspace, **Retrieve Responses** fetches a study's responses, and **Retrieve Themes** returns Sprig's AI-generated themes — its open-text analysis auto-clusters free-text feedback — with their associated responses. Filter by **score** (low CSAT/NPS) and theme to isolate the complaints worth reviewing. For bulk extraction, fall back to the **Data Export API** (`Authorization: Bearer <token>`) against the REST base `https://api.sprig.com`. (The **Public API v2**, `Authorization: API-Key <key>`, imports People, Events, and Attributes — and also reads them back: `GET /v2/users/{userId}` returns a visitor's attributes and events.)
  </Step>

  <Step title="Extract the session URL">
    `subtext_url` is a respondent attribute (imported via the Public API's People/Attributes) and appears alongside each response in the Data Export. You don't need a separate lookup to get it: pass `with_snapshots=true` on the Data Export request and each response includes a `visitorSnapshot` with the visitor's attributes (including `subtext_url`) as of survey delivery. Alternatively, for identified visitors, take the response's `externalUserId` and read attributes directly with `GET https://api.sprig.com/v2/users/{userId}` (`Authorization: API-Key <key>`) — note this returns *current* attributes (the snapshot preserves the value at survey time) and only works for visitors with user IDs; `externalUserId` is null for anonymous respondents.
  </Step>

  <Step title="Hand off to Subtext">
    For each URL, call `review-open(session_url=<subtext_url>)` on the Subtext MCP. Each review grounds the feedback in what actually happened — a Detect-vs-Diagnose read of what the respondent said versus what the session shows they did. For a theme, review several respondents' sessions together to find the shared pattern.
  </Step>
</Steps>

<Note>
  `subtext_url` only round-trips if it was stamped onto the response as a visitor attribute at capture time (see [Attach the session URL](#attach-the-session-url)).
</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.
