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

# Amplitude and Subtext: From a Signal to the Session

> Attach the Subtext session URL to Amplitude, then jump from any Amplitude signal — an anomaly alert, a dashboard email, a funnel drop — straight into the user's real session.

Amplitude tells you *that* a metric moved and *who* it moved for: an onboarding rate slipped, activation dropped, a funnel leaks at one step. It can't show you the moment one specific person got stuck. Subtext can. Attach the Subtext session URL to your Amplitude data and every Amplitude signal 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. Amplitude detects; Subtext diagnoses.

<Note>
  This guide assumes the [Subtext capture snippet](/docs/install/overview) is installed and the Amplitude Browser SDK (`@amplitude/analytics-browser`) is initialized.
</Note>

## Attach the session URL

Store the current Subtext session URL on your Amplitude data so it travels with the signal. There are two places to attach it, depending on how precise the link needs to be.

### On the user profile

Attach the URL to the Amplitude user profile with the `Identify` class. Call it wherever your app already identifies the user — on auth resolution, not at module top level. Amplitude typically uses snake\_case for property names, but match whatever convention your project already uses.

<CodeGroup>
  ```js analytics.js theme={null}
  import { identify, Identify } from '@amplitude/analytics-browser'

  const subtextUrl = FS('getSession', { format: 'url.now' })
  if (subtextUrl) {
    const identifyObj = new Identify()
    identifyObj.set('subtext_url', subtextUrl)
    identify(identifyObj)
  }
  ```

  ```tsx React theme={null}
  import { identify, Identify } from '@amplitude/analytics-browser'

  useEffect(() => {
    if (!user) return
    FS('setIdentity', { uid: user.id, properties: { email: user.email } })
    const subtextUrl = FS('getSession', { format: 'url.now' })
    if (subtextUrl) {
      const identifyObj = new Identify()
      identifyObj.set('subtext_url', subtextUrl)
      identify(identifyObj)
    }
  }, [user])
  ```
</CodeGroup>

### On every event

An Amplitude enrichment plugin runs on every event, reading the URL fresh each time. Because `url.now` carries a timestamp, the link deep-links to the moment each event fired. Register the plugin once at initialization, before any `track` calls.

```js theme={null}
amplitude.add({
  name: 'subtext-url',
  type: 'enrichment',
  execute: async (event) => {
    const url = FS('getSession', { format: 'url.now' })
    if (url) event.event_properties = { ...event.event_properties, subtext_url: url }
    return event
  },
})
```

<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-run the user-level linkage on re-identify. Don't use `amplitude.setUserProperties()` — that method belongs to the legacy Amplitude JS SDK; `@amplitude/analytics-browser` v2 requires the `Identify` class above. Don't register the enrichment plugin inside a component render — register it once at the Amplitude initialization point.
</Warning>

## From signal to session

Amplitude shows you that a metric moved and who it moved for; the session shows the confusion, error, or broken state behind it. However you first hear about a problem in Amplitude, 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 anomaly alert on a key metric">
    An Amplitude alert fires by email or Slack: "`Onboarding Completed` is anomalously low — 25% below forecast."

    From the alert, open the chart and segment to users who started but didn't complete in the window. Open a user, go to **User Properties**, and copy `subtext_url`. Grab several, then hand them to your agent:

    ```text theme={null}
    Amplitude says Onboarding Completed is 25% below forecast. Here are sessions from users who
    started onboarding but didn't finish in that window:
    <paste 3–4 subtext_urls>

    Review them and find the common stall point. Detect-vs-Diagnose: Amplitude flagged the drop —
    what does each session actually show at that step? Is it broken, slow, or confusing? Give me
    one hypothesis and the exact moments backing it.
    ```
  </Accordion>

  <Accordion title="A scheduled dashboard email">
    Your scheduled Amplitude dashboard email shows activation down versus last week.

    Click into the offending chart, drill into the down segment, open the affected users, and copy `subtext_url`.

    ```text theme={null}
    This week's Amplitude dashboard shows activation down. Here are sessions from users in the
    under-performing segment:
    <paste subtext_urls>

    Walk each one. Where do they fall out of the activation flow, and is it the same place every
    time? Tell me whether this is a product regression or normal variance, and point to evidence.
    ```
  </Accordion>

  <Accordion title="A live funnel or retention drill-down">
    You build a funnel in Amplitude, see a sharp drop at one step, and click into the users who didn't advance.

    Open a non-converting user's profile, go to **User Properties**, and copy `subtext_url`.

    ```text theme={null}
    I'm drilling into an Amplitude funnel. There's a sharp drop at the <step name> step. Here's a
    user who didn't advance: <paste subtext_url>

    Open the session and tell me exactly what happened at that step — what they saw, what they
    clicked, and why they stopped. Is this fixable in the product or is it intent (they just left)?
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  For a drop-off across several users, ask your agent to assemble one proof document (`doc-create`) with a screenshot per user and a single shared link — then paste that back into the Amplitude chart's notes or a Notebook so the metric carries its explanation. If the review shows the drop is intent rather than a defect, record that too — it stops the team from "fixing" a step that isn't broken.
</Tip>

## For agents

An autonomous agent can run the whole loop against Amplitude directly: discover the friction, extract the `subtext_url`, and hand each session to the Subtext MCP. Amplitude ships an official MCP server at `https://mcp.amplitude.com/mcp` (EU: `https://mcp.eu.amplitude.com/mcp`) over streaming HTTP, authenticated with OAuth 2.0.

<Steps>
  <Step title="Discover who is affected">
    The MCP is best for discovery: drive funnel, segmentation, and retention queries in natural language to find the drop steps. Its tool registry is dynamic, so discover tools at runtime via the meta-tools `get_amplitude_context`, `list_tool_categories`, `get_category_tools`, and `describe_tool`, plus `query_chart`.

    For deterministic work, use the Dashboard REST API instead — base `https://amplitude.com/api/2/...` (US) or `https://analytics.eu.amplitude.com/api/2/...` (EU), HTTP Basic `-u {api_key}:{secret_key}`:

    ```
    GET /api/2/funnels?e={"event_type":"Step 1"}&e={"event_type":"Step 2"}&start=YYYYMMDD&end=YYYYMMDD
    # the step with the largest count delta is the worst drop-off
    ```

    `GET /api/2/events/segmentation` finds low-converting slices, and the Behavioral Cohorts API (`/api/3/cohorts`) defines or exports at-risk user groups.
  </Step>

  <Step title="Extract the session URL">
    Read `subtext_url` per user from the User Profile REST API:

    ```
    GET https://profile-api.amplitude.com/v1/userprofile?user_id=<USER_ID>&get_amp_props=true
    # Authorization: Api-Key <SECRET KEY>   (literal, not base64)
    # → response.userData.amp_props.subtext_url
    ```

    <Warning>
      EU residency gap: the User Profile API is not available in Amplitude's EU region and there is no EU endpoint. For EU orgs, fall back to the MCP "user properties" capability, a chart or export, or read the link from another store.
    </Warning>
  </Step>

  <Step title="Hand off to Subtext">
    For each URL, call `review-open(session_url=<subtext_url>)` on the Subtext MCP. Event-level URLs are moment-precise, so the review opens exactly when the signal fired.
  </Step>
</Steps>

<Note>
  `subtext_url` only round-trips if it was attached at capture time (see [Attach the session URL](#attach-the-session-url)) — as a user property, and optionally an event property via the enrichment plugin. For autonomous or headless runs, prefer the API-key Basic-auth REST path over the MCP's OAuth browser flow. Match your region (US vs EU) for the MCP and Dashboard API endpoints; the User Profile API is US-only.
</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.
