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

> Give your Dify Agent live awareness of what each user is doing — the agent pulls it on demand via the Autoplay MCP server.

## ⚡ Add this skill

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

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

    <a className="skill-card-link" href="/recipes/dify-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 Dify and wants its AI support agent to consume Autoplay live user activity.

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

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

Your **Dify Agent** pulls a user's recent in-app activity on demand via the **Autoplay MCP server** — the agent calls it the moment it needs context to answer. One MCP connection, one tool (`get_live_user_activity`), and a user id wired through the agent's input variables so the right user's activity is always fetched.

## 🎬 End-to-end walkthrough

<div
  style={{
position: "relative",
paddingBottom: "calc(54.502% + 41px)",
height: 0,
width: "100%",
}}
>
  <iframe
    src="https://demo.arcade.software/iyt8HeenaGZcrcTAfTZ5?embed&embed_mobile=tab&embed_desktop=inline&show_copy_link=true"
    title="Dify Agent — connect live user activity via MCP"
    frameBorder={0}
    loading="lazy"
    allow="clipboard-write; fullscreen"
    style={{
  position: "absolute",
  top: 0,
  left: 0,
  width: "100%",
  height: "100%",
  colorScheme: "light",
}}
  />
</div>

***

## 🔌 Add the Autoplay MCP server

In your Dify workspace, go to **Tools** (top navigation) → **MCP** tab → **Add MCP Server (HTTP)**.

In the modal that appears, fill in:

* **Server URL:** `https://mcp.autoplay.ai/mcp`
* **Name & Icon:** `Autoplay live activity`
* **Server Identifier:** `autoplay-live-activity` *(lowercase letters, numbers, underscores, hyphens — up to 24 characters)*

Then click the **Headers** tab and click **+ Add Header** to add the Bearer token:

| Key             | Value                 |
| --------------- | --------------------- |
| `Authorization` | `Bearer YOUR_MCP_KEY` |

Click **Add & Authorize**. Dify connects to the server and shows it as **Authorized** with **1 tool included** — `get_live_user_activity`.

## 🤖 Create an Agent app

In **Studio**, click **Create from Blank** → select **Agent** as the app type. Give it a name (e.g. `Support Agent`) and create it.

Inside the Agent's **Orchestrate** view, find the **Tools** section and add **`get_live_user_activity`** from your `Autoplay live activity` MCP server. The tool's parameters (`product_id`, `user_id`, `limit`) come from the MCP server definition — no manual configuration needed.

## 💬 Set the Agent instructions

The **Instructions** field (the system prompt) is where you tell the agent when to call the tool and how to use the activity data. Replace or append with:

```text theme={null}
Always call get_live_user_activity before responding to any
user message. Use the returned activity data — features
visited, actions taken, workflows completed — to understand
what the user has already done and what they haven't.
Use this context to better answer their question, surface
context they didn't mention, and diagnose what they're
actually stuck on.

When calling get_live_user_activity:
- product_id is always: {{product_id}}
- user_id is: {{user_id}}
```

<Tip>
  Replace `YOUR_PRODUCT_ID` with your actual product id from
  your Activity provider dashboard. The `{{user_id}}` placeholder is
  a Dify input variable — see *Identity* below.
</Tip>

## 🔐 Identity — wire the user id into the agent

The agent needs the current user's stable id to pass as `user_id` to the MCP tool. In Dify, you do this with an **input variable**.

### 1. Add the input variable

In the Agent's **Orchestrate** view, find **Variables** (or **Inputs**) and add:

* **Variable name:** `user_id`
* **Type:** String

### 2. Reference it in the instructions

The `{{user_id}}` and `{{product_id}}` in the instructions above is how Dify substitutes the real value at runtime. The agent reads it and passes it as the `user_id` and `product_id` parameter when calling the tool. After that publish the agent.

### 3. Pass it when calling the Dify API

When your frontend calls the Dify API to start or continue a conversation, include `user_id` in the `inputs` object:

<Tabs>
  <Tab title="PostHog">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.dify.ai/v1/chat-messages",
      {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${DIFY_APP_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          inputs: {
            // Must equal the id passed to posthog.identify(...)
            user_id: posthog.get_distinct_id(),
          },
          query: userMessage,
          conversation_id: existingConversationId,
          user: currentUser.id,
        }),
      }
    );
    ```
  </Tab>

  <Tab title="Amplitude">
    ```javascript theme={null}
    const response = await fetch(
      "https://api.dify.ai/v1/chat-messages",
      {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${DIFY_APP_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          inputs: {
            // Must equal the id passed to amplitude.setUserId(...)
            user_id: currentUser.id,
          },
          query: userMessage,
          conversation_id: existingConversationId,
          user: currentUser.id,
        }),
      }
    );
    ```
  </Tab>
</Tabs>

The value in `inputs.user_id` **must exactly equal** the id your activity source identifies the user with:

<Note>
  **How the pieces fit:** your frontend identifies the user
  in your activity source → Autoplay stores activity under
  that id → your frontend passes that same id as
  `inputs.user_id` in the Dify API call → the agent reads
  `{{user_id}}` from inputs and passes it to the MCP tool
  → the buckets match.
</Note>

<Warning>
  Do not use email as `user_id` unless email is literally
  the stable id your activity source uses.
  Activity is stored under the stable id — a mismatch means
  the agent fetches an empty bucket.
</Warning>

## ✅ Test the full loop

1. **Log in** to your app as a test user — fires your activity source's identify call.
2. **Click around** — visit a couple of pages, click a button, submit a form.
3. **Open the Agent** (via your frontend or Dify's Preview panel) passing the matching `user_id` in `inputs`.
4. **Ask the agent:** *"What have I been doing in the app recently?"*
5. The agent calls **`get_live_user_activity`** and answers with **what you actually just did**.

Common issues:

* **401 / Unauthorized** → the `Authorization` header is missing or the token is wrong — revisit *Add the Autoplay MCP server* above.
* **Empty activity returned** → identity is working but that user has no recent activity yet. Browse around in your app first, then re-test.
* **Wrong user's activity** → the `user_id` in `inputs` doesn't match the id your activity source uses. Check both are identical.

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

  1. the stable id your activity source identifies the user
     with (PostHog: `posthog.identify(id)`,
     Amplitude: `amplitude.setUserId(id)`),
  2. the `user_id` passed in `inputs` when calling
     the Dify API,
  3. the `{{user_id}}` variable referenced in the
     agent instructions.

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

Once the agent is answering with real activity, jump into our [Discord](https://discord.gg/jCbR2tQA5) — we'll confirm the tool is pulling activity cleanly and help you tune the instructions.

***

**Next:** [Step 2 — Define proactive triggers](./step-2-define-proactive-triggers)
