> ## Documentation Index
> Fetch the complete documentation index at: https://developers.autoplay.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Step 1 — Connect real-time events

> Connect Intercom Fin to a user's recent in-app activity via the Autoplay MCP server — one MCP connection, one tool, with Messenger JWT identity verification.

## ⚡ Add this skill

<CardGroup cols={2}>
  <Card title="One command" icon="terminal">
    Add the Autoplay Intercom Fin skill for an existing Intercom Fin AI support agent setup.

    <CodeGroup>
      ```bash CLI theme={null}
      uvx --from autoplay-sdk autoplay-install-skills --chatbot intercom
      ```
    </CodeGroup>

    <a className="skill-card-link" href="/recipes/intercom-tutorial/step-1-connect-real-time-events">View the docs →</a>
  </Card>

  <Card title="Agent onboarding" icon="robot">
    Fetch this skill when a customer already uses Intercom Fin and wants its AI support agent to consume Autoplay live user activity.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -s https://developers.autoplay.ai/chatbot-intercom/SKILL.md
      ```
    </CodeGroup>

    <a className="skill-card-link" href="https://developers.autoplay.ai/chatbot-intercom/SKILL.md" target="_blank">View the skill →</a>
  </Card>
</CardGroup>

**Intercom Fin** pulls a user's recent in-app activity on demand via the **Autoplay MCP server** — Fin calls it the moment it needs context to answer. One MCP connection, one tool (`Get Live User Activity`), and a verified identity so Fin asks for the right user.

## 🎬 Watch the walkthrough

Prefer to watch first? This short Loom walks through the entire setup end to end — adding the MCP server, the tool, identity, and testing the full loop.

<Frame>
  <iframe src="https://www.loom.com/embed/166ff566caf7434b8770efc6428dc948" title="Connect Intercom Fin to live user activity" frameBorder="0" allowFullScreen style={{ width: "100%", aspectRatio: "16 / 9", borderRadius: "12px" }} />
</Frame>

<Note>
  **Prerequisite:** Intercom's MCP connectors require a **US-hosted** Intercom workspace.
</Note>

## 🔌 Add the Autoplay MCP server

In **Intercom:** Settings → **Integrations** → **Data connectors**. Click the **Custom MCP** tile (or **New** → **Custom MCP**) and enter:

* **Name:** `Autoplay live activity`
* **URL:** `https://mcp.autoplay.ai/mcp`

Click **Create / Add MCP Server**. The server appears in your connectors list showing **"(0)"** — connected, but no tools added yet.

## 🧰 Add the Get Live User Activity tool

Click **+ New** under the **Autoplay live activity** server. In the **Add Autoplay live activity connectors** modal, check **Get Live User Activity** and click **Add connectors**. The tool is added and the count updates to **"(1)"**.

## 📝 Open the tool and edit it

Click the **Get Live User Activity** tool in the list to open it (it opens in **Draft**). Click **Edit** to configure it.

The tool opens with tabs across the top — **API** (the endpoint, its inputs, and authentication) and **Fin** (the prompt that tells Fin *when* to use the tool). Set up the **API** tab first (inputs, then authentication), then the **Fin** tab (the prompt).

## 🎛️ Configure the data inputs (on the API tab)

On the **API** tab, the tool has three inputs — **product\_id**, **user\_id**, **limit**. Set each:

* **product\_id** → set **Data source** to **Custom value** and enter **your** product id (the same one from your Autoplay SDK setup). Also set the **Fallback value** to that **same** product id — so the connector always receives it even if the custom value is ever missing.
* **user\_id** → choose **Use an attribute** and select the **User ID** people attribute. This is the verified id from the Messenger JWT (set up under *Verify identity with a Messenger JWT* below) — it must equal the stable user id your activity source identifies the user with (e.g. the `posthog.identify(...)` id, or the Amplitude `user_id`).
* **limit** → optional; leave as **Let Fin decide** (or ignore it).

<Warning>
  For **user\_id**, pick the **User ID** attribute — **not Contact ID** and **not email**. *Contact ID* is Intercom's internal `integer` id; email isn't the stable key. Activity is stored under your activity source's stable user id (e.g. the `posthog.identify` id), so anything else reads an empty bucket.
</Warning>

## 🔑 Add the authentication token (on the API tab)

Still on the **API** tab, find the **Authentication** section. The tool needs your `mcp_key`, so click **New token** (**Authentication tokens** → **Custom**) and fill in:

* **Type:** Text
* **Token value:** `YOUR_MCP_KEY`
* **Token prefix:** `Bearer`
* **Key for request header:** `Authorization`

Save, then back in the connector's **Authentication** dropdown, select the token you just created.

<Note>
  The **Token prefix** field is why you do **not** type `Bearer ` into the token value — Intercom prepends the prefix for you. The final header sent is `Authorization: Bearer YOUR_MCP_KEY`. The token's `external_id` must equal your `product_id`, or calls return **403**.
</Note>

## 💬 Set the Fin prompt (on the Fin tab)

Now switch to the **Fin** tab (next to **API** at the top of the tool). This is where you tell Fin **when** to use the tool — the field that actually drives Fin's decision to call it. (The **API** tab also has a technical description, but the **Fin** tab's prompt is the one that matters here.) Replace the default with a clear, Fin-facing trigger description. Recommended:

```text theme={null}
Use this when a customer references their recent in-app behavior or when understanding their recent actions would help resolve their issue. Specific triggers include:

- Customer asks "what was I just doing?" or "where was I?" or refers to a recent action they took
- Customer mentions encountering an error, bug, or unexpected behavior and you need to see what steps led to it
- Customer is stuck in a flow and needs help figuring out where they are or what to do next
- Customer says "I just clicked something" or "I submitted a form" but is unsure what happened
- You need context about the customer's recent navigation path to troubleshoot or guide them

No input is required from the customer — call this action directly.

This returns a chronological list of the customer's recent in-app activity (oldest to newest), including pages they viewed, buttons they clicked, and forms they submitted.

Do NOT use this when:
- The customer is asking about account details, billing, or subscription information
- The customer is asking about product features or general how-to questions that don't require knowing their recent activity
- The question can be answered without needing to know what the customer recently did in the app
```

<Tip>
  The **Fin prompt** is the single biggest factor in whether Fin reliably calls the tool. Make it about **when to use it**, not how it works internally.
</Tip>

## 🔐 Verify identity with a Messenger JWT

**What this is, in plain terms:** Fin should only fetch the *logged-in* user's activity, so Intercom needs proof of who that user is. A **Messenger JWT** is a short, signed token your app creates that tells Intercom *"this visitor is user `X`."* You sign it on **your server** (using a secret from Intercom), then hand it to the Intercom **Messenger** in **your frontend** — the same place you already boot Intercom today.

The `user_id` you put in that token **must equal** the id activity is stored under — the stable user id your **activity source** identifies the user with (e.g. the one you pass to `posthog.identify(...)`, or the Amplitude `user_id`). That match is the whole point (see **[Identity](/activity/identity)**).

<Note>
  **How the pieces fit:** your frontend asks *your* server for a token → your server signs it with the Intercom secret → your frontend hands it to Intercom on boot → Intercom trusts the `user_id` and passes it to Fin.
</Note>

<Warning>
  For **logged-in** users, Intercom will **not** give Fin a trusted identity until Messenger JWT verification is set up **and enforced** (step 4). Until then, lookups come back empty.
</Warning>

### 1. Get your Unified Secret — in Intercom

**Settings → Channels → Messenger → Security.** Copy the **secret** used for identity verification.

<Warning>
  This secret is **server-side only**. Never ship it to the browser, never put it in your frontend bundle, and never commit it — anyone with it can forge any user's identity. Store it as an env var (e.g. `INTERCOM_IDENTITY_SECRET`).
</Warning>

### 2. Sign the token — on your backend

This runs in **your server code** (where the secret is safe). Add an endpoint your frontend can call to get a token for the currently logged-in user. Node/Express is shown, but any backend works — only the claims (`user_id`, `email`, `exp`) and the HS256 signature matter:

```javascript theme={null}
// BACKEND — runs on your server, where INTERCOM_IDENTITY_SECRET is safe.
import jwt from "jsonwebtoken";

// e.g. an Express route your frontend calls after login:
app.get("/intercom-jwt", requireAuth, (req, res) => {
  const token = jwt.sign(
    {
      user_id: req.user.id,   // MUST equal the id you pass to posthog.identify(...)
      email: req.user.email,
      exp: Math.floor(Date.now() / 1000) + 60 * 60, // expires in 1 hour
    },
    process.env.INTERCOM_IDENTITY_SECRET, // the Unified Secret from step 1
    { algorithm: "HS256" }
  );
  res.json({ token });
});
```

### 3. Boot the Messenger with the token — in your frontend

Wherever you **already initialize the Intercom Messenger** (your app's frontend, after the user logs in), fetch the token from the endpoint above and pass it as the **sole** identity source:

```javascript theme={null}
// FRONTEND — the same place you already boot the Intercom Messenger.
const { token } = await fetch("/intercom-jwt").then((r) => r.json());

window.Intercom("boot", {
  app_id: "YOUR_INTERCOM_APP_ID",
  intercom_user_jwt: token, // the SOLE identity source — do NOT also set user_id/email here
});
```

<Tip>
  Test before enforcing: paste a freshly signed token into a JWT decoder (e.g. jwt.io) and confirm the `user_id` claim is **exactly** your activity source's stable user id (e.g. the value you pass to `posthog.identify(...)`). A mismatch here is the #1 cause of "Fin sees no activity."
</Tip>

### 4. Enforce Messenger Security — in Intercom

Back in **Settings → Channels → Messenger → Security**, turn on **enforcement** for the web Messenger. Enforcement is what makes Intercom **trust and forward** the verified identity to Fin — do this **only after** step 3 works and your tokens decode correctly.

<Warning>
  Use a **stable user id** for the `user_id` claim — your internal user primary key, the same one your activity source identifies the user with. Do **not** use **email**: emails change, and activity is keyed by the stable id, so an email claim reads the wrong (or empty) bucket.
</Warning>

## 🧪 Test the connection

On the tool's **Test** tab, set test values: **product\_id** (your product) and **user\_id** (a real user you've identified and browsed as). Run the **live test** — you want a **200** with a populated `actions` array.

* **401** → the auth token isn't selected/configured — revisit *Add the authentication token* above.
* **200 with empty `actions`** → identity is fine but that user has no recent activity yet (browse as them first).

## 🚀 Set live

Click **Set live**. The tool flips from **Draft** to **Live** and Fin will call it in real conversations.

<Note>
  On the **Fin** tab, ensure **"Enable Fin to use this connector directly"** is checked so Fin triggers it automatically based on the description.
</Note>

## ✅ Test the full loop

1. **Log in** to your app as a test user (fires your activity source's identify — e.g. `posthog.identify(...)` — with that user's stable id).
2. **Click around** — visit a couple of pages, click a button, submit a form.
3. **Open the Messenger** as that same logged-in user (the JWT boots with the matching `user_id`).
4. **Ask Fin:** *"What have I been doing in the app recently?"*
5. Fin calls **Get Live User Activity** and answers with **what you actually just did**.

<Note>
  **"No recent activity" = identity mismatch.** Confirm the **same** value in all three:

  1. the id your activity source identifies the user with (e.g. `posthog.identify`),
  2. the `user_id` claim in the Messenger JWT,
  3. the **User ID** attribute you bound on the API tab.

  If they don't match, activity is stored under one key and fetched with another, and the lookup comes back empty.
</Note>

Once it's answering correctly, jump into our [Discord](https://discord.gg/jCbR2tQA5) and say hi — we'll confirm Fin is pulling activity cleanly and help you tune the trigger description.
