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

# Intercom and Subtext: From a Conversation to the Session

> Attach the Subtext session URL to your Intercom contacts, then jump from any support conversation — a ticket, an escalation, a bad CSAT — straight into the user's real session.

A support conversation is the user's *description* of what went wrong — secondhand, often vague ("the button doesn't work"). Intercom tells you *that* someone is stuck. It can't show you *what actually happened* on their screen. Subtext can. Attach the Subtext session URL to the Intercom contact and every conversation 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. Intercom detects; Subtext diagnoses.

<Note>
  This guide assumes the [Subtext capture snippet](/docs/install/overview) is installed and capturing, and the Intercom Messenger is installed — either via the JavaScript snippet or the `@intercom/messenger-js-sdk` npm package. Each code tab below is written for one install method. It also assumes a custom data attribute named `subtext_url` exists in **Intercom → Settings → Data → People** — custom attributes must be created before the Messenger can write them.
</Note>

## Attach the session URL

Store the current Subtext session URL on the Intercom contact as the `subtext_url` custom attribute so it travels with the conversation and shows in the inbox sidebar. Attach it through the `update` call — or pass it at boot with the modern SDK.

<CodeGroup>
  ```js analytics.js theme={null}
  // JavaScript snippet install
  const subtextUrl = FS('getSession', { format: 'url.now' })
  if (subtextUrl) {
    window.Intercom('update', { subtext_url: subtextUrl })
  }
  ```

  ```tsx React theme={null}
  // npm SDK install
  import { update } from '@intercom/messenger-js-sdk'

  useEffect(() => {
    if (!user) return
    FS('setIdentity', { uid: user.id, properties: { email: user.email } })
    const subtextUrl = FS('getSession', { format: 'url.now' })
    if (subtextUrl) {
      update({ subtext_url: subtextUrl })
    }
  }, [user])
  ```

  ```js boot.js theme={null}
  // npm SDK install
  import Intercom from '@intercom/messenger-js-sdk'

  const settings = { app_id: '<APP_ID>', user_id: user.id }
  const subtextUrl = FS('getSession', { format: 'url.now' })
  if (subtextUrl) settings.subtext_url = subtextUrl
  // getSession usually returns null this early — the update-on-identify
  // path above is the reliable way to attach.
  Intercom(settings)
  ```
</CodeGroup>

The session URL changes on a new session and when `FS('setIdentity')` is called with a different `uid`, so re-call `update(…)` (or `window.Intercom('update', …)` for snippet installs) whenever you re-identify the user — the attribute is frozen until the next update.

<Warning>
  Don't read `FS('getSession')` at module top level — it returns `null` until the session has started. Don't skip creating the `subtext_url` custom attribute in Intercom settings first — undeclared attributes are silently dropped. And don't spam the update call: Intercom throttles the Messenger to 20 `update` calls per 30 minutes, so attach on identify, not on every render.
</Warning>

## From signal to session

However you first hear about a problem in Intercom, the path is the same: get to the `subtext_url`, then hand it to your agent for a Detect-vs-Diagnose read. The ticket says X is broken; the session shows whether it reproduces, what the user really clicked, and where it failed — so you can answer (or escalate) from evidence instead of guessing.

<AccordionGroup>
  <Accordion title="A conversation lands in your inbox">
    A conversation is assigned to you: *"I clicked Pay and nothing happened. Tried three times."*

    Open the conversation, go to the **contact details sidebar**, find `subtext_url` under custom attributes, and copy it. Then hand it to your agent:

    ```text theme={null}
    A user opened a support ticket: "I clicked Pay and nothing happened, tried 3 times." Here's their
    session: <PASTE subtext_url>

    Open it, find the moment(s) they clicked Pay, and tell me what actually happened. Did the button
    respond? Was there an error or a failing request? Does it reproduce? Give me a plain-language
    explanation I can reply with, plus whether this needs to go to engineering.
    ```
  </Accordion>

  <Accordion title="Escalating from support to engineering">
    You've decided a ticket is a real bug and are about to open a Linear / Jira issue for the product team.

    Copy `subtext_url` from the contact sidebar so it travels into the engineering ticket alongside your summary.

    ```text theme={null}
    I'm escalating this support ticket to engineering and want a tight bug report. User session:
    <PASTE subtext_url>

    Produce a reproduction-grade write-up: the exact steps the user took, the UI state at failure, the
    relevant console/network errors, and a clear repro sequence. Format it so I can paste it straight
    into a Linear issue — engineers should be able to act without re-interviewing the user.
    ```
  </Accordion>

  <Accordion title="A wave of similar tickets">
    Several conversations come in within an hour all describing the same thing — *"export is failing."*

    Open each conversation and copy `subtext_url` from each contact sidebar, then review them together.

    ```text theme={null}
    We're getting a wave of "export is failing" tickets. Here are sessions from several of the users
    who reported it:
    <PASTE 3-4 subtext_urls>

    Review them together. Is it the same failure for everyone, or different problems that sound alike?
    Find the common trigger and tell me whether this is one bug, a regional/browser issue, or user
    error. I need to know if I should post a status banner.
    ```
  </Accordion>

  <Accordion title="A negative CSAT rating">
    A conversation gets a low CSAT rating and a comment like *"never actually got it working."*

    Open the rated conversation, go to the contact sidebar, and copy `subtext_url`.

    ```text theme={null}
    This conversation got a bad CSAT and the user said they never got it working. Session:
    <PASTE subtext_url>

    Open it and tell me what the user was actually up against — was this a product bug we couldn't
    have solved in chat, or a support miss? I want to know whether to fix the product or coach the team.
    ```
  </Accordion>
</AccordionGroup>

<Tip>
  Paste the agent's summary as an internal note on the conversation so the next rep inherits the diagnosis. When escalating, attach the agent's repro write-up (or a **proof document** via `doc-create`) to the engineering ticket — the `subtext_url` plus screenshots means engineers don't have to re-interview the customer.
</Tip>

## For agents

An autonomous agent can run the whole loop against Intercom directly: discover the friction, extract the `subtext_url`, and hand each session to the Subtext MCP. Intercom ships an official MCP server at `https://mcp.intercom.com/mcp` (Streamable HTTP; legacy SSE at `/sse`), authenticated with OAuth or a Bearer access token.

<Warning>
  The Intercom MCP server supports **US-hosted workspaces only** — EU and AU data regions are not supported yet. If your workspace is EU/AU, use the REST API instead.
</Warning>

<Steps>
  <Step title="Discover the friction">
    Surface the worst conversations — low CSAT, `bug` / `confusion` tags, topic spikes. Over MCP, `search_conversations` filters by source, author, state, assignment, and timing; `search` runs a universal query across conversations and contacts. Over REST:

    ```
    POST https://api.intercom.io/conversations/search
    # Authorization: Bearer <access_token>
    # filter by: tag_ids (IN), conversation_rating.score (CSAT), state, created_at / updated_at timing
    # nested AND/OR (max 2 nesting levels, 15 filters/group)
    ```

    Narrow to the affected users with `POST /contacts/search`.
  </Step>

  <Step title="Extract the session URL">
    Read `subtext_url` off the contact's custom attributes. Over MCP, `get_contact` returns complete contact info including custom attributes (`search_contacts` can also filter by them). Over REST:

    ```
    GET https://api.intercom.io/contacts/{contact_id}
    # Authorization: Bearer <access_token>
    # → response.custom_attributes.subtext_url
    ```
  </Step>

  <Step title="Hand off to Subtext">
    For each URL, call `review-open(session_url=<subtext_url>)` on the Subtext MCP to get a Detect-vs-Diagnose read: the ticket says X broke versus whether it reproduces in the session. For escalation, ask the review to produce reproduction-grade steps (and optionally a `doc-create` proof document) so the bug report carries evidence, not a paraphrase.
  </Step>
</Steps>

<Note>
  `subtext_url` only round-trips if it was stored as a contact custom attribute at capture time (see [Attach the session URL](#attach-the-session-url)). The Intercom MCP is US-region-only today — fall back to the REST API for EU/AU workspaces.
</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.
