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

# How to trigger a User Tour

> Learn how to trigger any user tour provider from your backend using the Autoplay event stream.

If you already completed [Step 3 — Add the proactive layer](/quickstart#-step-3-—-add-the-proactive-layer), most of the wiring here is already done: Autoplay.js connects to the nudge stream and calls the right SDK for you the moment a `"tour"` nudge arrives. What's left is provider-specific:

1. Install and identify your tour provider's SDK in your frontend.
2. Build the flow in your tour provider's dashboard and note its Flow ID.
3. Set `tour_provider` in your onboarding config to match (e.g. `"appcues"`).

See the individual tutorials in this section for the exact SDK details per provider.

<Tip>
  Haven't connected Autoplay.js yet? [Do that first](/quickstart#-step-3-—-add-the-proactive-layer) — it's what actually fires the tour, and it also unlocks nudge cards. The rest of this page documents triggering a tour **without** Autoplay.js: wiring the event stream and session-matching yourself. Use that manual path only if you need direct control over the stream, or need to support a tour provider not yet covered by Autoplay.js.
</Tip>

## Prerequisites

* An Autoplay product ID.
* A registered Autoplay product with stream credentials.
* Your chosen user tour provider installed and initialized in your frontend.
* A way to identify the active browser session. Autoplay uses the PostHog session ID in the examples below.
* The flow ID you want to start (from your tour provider's dashboard).

For Registration of product, run the Registration Script. Create a Python file with the code below. Paste your Product ID from into the script and run it

```python theme={null}
import asyncio
from autoplay_sdk.admin import onboard_product

async def main() -> None:
    result = await onboard_product(
        "YOUR_AUTOPLAY_PRODUCT_ID",
        contact_email="you@yourcompany.com",
        print_operator_summary=True,
    )
    # result still has the same full fields if you need them in code

asyncio.run(main())
```

This will print the following fields:

* product\_id: `{issued_product_id}`
* webhook\_url: `https://{connecter-url}/webhook/{product_id}`
* stream\_url: `https://{connecter-url}/stream/{product_id}`
* webhook\_secret: `{secret}`
* stream key: `{secret}`

***

## Manual path: trigger without Autoplay.js

### 1. Proxy the Stream (Security)

To keep your stream key hidden from users, do not connect the browser directly to Autoplay.

Instead, create a server-side route. This acts as the bridge between Autoplay and your frontend while keeping your credentials secure.

```jsx theme={null}
export async function GET() {
  const upstream = await fetch(
    `https://event-connector-luda.onrender.com/stream/${PRODUCT_ID}`,
    {
      headers: {
        Authorization: `Bearer ${PROCESS_ENV_TOKEN}`,
        Accept: "text/event-stream",
      },
    }
  );

  return new Response(upstream.body, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    },
  });
}
```

### 2. Connect the Event Stream

Use the standard `EventSource` API to listen to your proxy route.

```jsx theme={null}
const events = new EventSource(`/api/your-proxy-path/${productId}`);

events.onmessage = (event) => {
  const payload = JSON.parse(event.data);
  // Handle the trigger here — see Step 3
};
```

### 3. Understanding the Payload

The "last mile" is handling the data that arrives through the stream. When a tour is triggered, your frontend receives a JSON object. You need to verify the `session_id` to ensure the tour starts for the correct user.

#### Payload structure

When a `usertour_trigger` event hits your stream, `event.data` looks like this:

```jsx theme={null}
{
  "type": "usertour_trigger",
  "product_id": "prod_123...",
  "session_id": "posthog_session_888...",
  "flow_id": "tour_abc_789"
}
```

**What to do with it:**

* **Check the type** — ensure `type === "usertour_trigger"`.
* **Match the session** — compare `payload.session_id` with the current user's session ID (e.g. from PostHog).
* **Trigger the tour** — if they match, pass `flow_id` to your tour provider's SDK.

The tour provider SDK call is the only thing that differs between providers. Each tutorial in this section covers exactly that one step.
