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

# Embed navigation

> Host-page deeplinks from the web chat iframe

The widget runs in a sandboxed iframe and cannot change your site's URL directly. When a customer taps a **Navigation card**, the iframe sends a `postMessage` to the host page. **You must register a listener on the host page** to handle that intent.

## Embed the widget (iframe + optional listener)

Navigation deeplinks only work when **both** parts are on your page:

1. The **iframe**: loads the chat UI from Chatropic.
2. A **host script**: defines `setupChatropicNavigationListener` and wires it to your router or `location.assign`.

The **Embed** tab on **Deploy > Chat widget** currently copies the iframe setup only. If you are using Navigation cards, add the listener below manually in your host app.

### Full embed example

Use the iframe `src` from the **Embed** tab on **Deploy > Chat widget**. Current web snippets use `https://chatropic.com/embed/key/{publishable-key}`.

```html theme={null}
<!-- 1. Chatropic inline panel iframe -->
<iframe
  id="chatropic"
  src="https://chatropic.com/embed/key/cpk_live_..."
  width="400"
  height="620"
  style="border:none;border-radius:16px;box-shadow:0 8px 30px rgba(0,0,0,0.12)"
  allow="microphone"
  title="Support assistant"
></iframe>

<!-- 2. Host listener, required for Navigation card deeplinks -->
<script>
/**
 * Handle Navigation card deeplinks from the Chatropic embed iframe.
 * @param {string} widgetOrigin - Origin of your embed URL (scheme + host + port)
 * @param {(path: string) => void} [onNavigate] - Optional handler (e.g. router.push)
 */
function setupChatropicNavigationListener(widgetOrigin, onNavigate) {
  var ALLOW = /^\/[a-zA-Z0-9\-\/_?=&]*$/;
  window.addEventListener("message", function (e) {
    if (e.origin !== widgetOrigin) return;
    var d = e.data || {};
    if (d.type !== "chatropic:navigate") return;
    if (typeof d.path !== "string" || !ALLOW.test(d.path)) return;
    if (typeof onNavigate === "function") {
      onNavigate(d.path);
      return;
    }
    window.location.assign(d.path);
  });
}

// Default: full page navigation
setupChatropicNavigationListener("https://chatropic.com", function (path) {
  // SPA hosts: replace with router.push(path) or navigate(path)
  window.location.assign(path);
});
</script>
```

<Warning>
  If you paste **only the iframe** without the listener script, Navigation cards will appear in chat but **clicks will not navigate your site**. This applies to **both** the website widget and inline panel snippets.
</Warning>

## Website widget (floating launcher)

The snippet from **Copy website widget code** on the **Embed** tab includes `setupChatropicLauncherHostListener` and embed wake scripts. The iframe `src` includes `mode=launcher`.

When integrating manually, register one navigation listener per page. A single listener handles navigation messages from either embed layout.

### `setupChatropicLauncherHostListener`

The website widget posts `chatropic:launcher-state` messages when chat opens or closes on mobile. The host listener resizes the iframe between a compact closed footprint and full viewport when open.

| Argument       | Type                | Description                                          |
| -------------- | ------------------- | ---------------------------------------------------- |
| `widgetOrigin` | `string`            | Origin of your embed URL (scheme and host, no path)  |
| `iframeId`     | `string` (optional) | Host iframe element id, default `chatropic-launcher` |

Paste this from the copied website widget snippet rather than hand-rolling iframe sizing on mobile.

<Warning>
  If you paste **only the launcher iframe** without the host scripts, Navigation cards will not navigate your site and mobile chat may not expand correctly.
</Warning>

## `setupChatropicNavigationListener`

This is the function integrators install on the **host page** (the page that contains the iframe, not inside the iframe).

| Argument       | Type                                | Description                                                                  |
| -------------- | ----------------------------------- | ---------------------------------------------------------------------------- |
| `widgetOrigin` | `string`                            | Origin of your embed URL (scheme and host, no path)                          |
| `onNavigate`   | `(path: string) => void` (optional) | Called with a validated relative path when the user clicks a Navigation card |

### What it does

1. Subscribes to `window.message` on the host page.
2. Accepts messages only when `event.origin === widgetOrigin`.
3. Handles messages where `event.data.type === "chatropic:navigate"`.
4. Validates `event.data.path` is a relative URL (starts with `/`, no `javascript:` or `https://`).
5. Calls your `onNavigate(path)` callback, or falls back to `window.location.assign(path)`.

### Message protocol

When the user clicks a Navigation card inside the iframe, the widget posts to `window.parent`:

```json theme={null}
{
  "type": "chatropic:navigate",
  "path": "/account/billing"
}
```

Only **relative paths** from your tenant's navigation route registry are ever sent.

## SPA integration

Pass a custom `onNavigate` callback instead of relying on `location.assign`:

```js theme={null}
// Next.js App Router, host layout or page that renders the iframe
import { useRouter } from "next/navigation";

const router = useRouter();

setupChatropicNavigationListener("https://chatropic.com", function (path) {
  router.push(path);
});
```

```js theme={null}
// React Router v6
import { useNavigate } from "react-router-dom";

const navigate = useNavigate();

setupChatropicNavigationListener("https://chatropic.com", function (path) {
  navigate(path);
});
```

```js theme={null}
// Vue Router
setupChatropicNavigationListener("https://chatropic.com", function (path) {
  router.push(path);
});
```

### Reuse the listener on multiple pages

Define the function once in a shared bundle or layout, then call `setupChatropicNavigationListener` on every page that embeds the iframe:

```js theme={null}
// shared/chatropic-embed.js
export function initChatropicEmbedNavigation(widgetOrigin, navigate) {
  setupChatropicNavigationListener(widgetOrigin, navigate);
}
```

## Security

| Check                       | Purpose                                                                                    |
| --------------------------- | ------------------------------------------------------------------------------------------ |
| `e.origin === widgetOrigin` | Ignore messages from other sites                                                           |
| Path allowlist regex        | Reject `https://...`, `javascript:...`, and other non-relative paths                       |
| Server-side route registry  | The agent only offers paths stored in your tenant's `nav_routes`: never user-supplied URLs |

## UI payload shape

Sync responses and `agent:done` events may include:

```json theme={null}
{
  "component": "NavigationCard",
  "props": {
    "label": "Billing",
    "path": "/account/billing",
    "requiresAuth": true
  }
}
```

The default web embed renders this automatically. On mobile, the React Native SDK delivers the same payload through `onNavigate`; see [React Native SDK](/developer-guides/integration/react-native-sdk#navigation-deeplinks)On mobile, the React Native SDK delivers the same payload through `onNavigate`; see [React Native SDK](/developer-guides/integration/react-native-sdk#navigation-deeplinks).

## Click analytics (optional)

The widget dispatches `chatropic:nav-card-clicked` on the iframe `window` when the user taps the card. Listen from host instrumentation if needed:

```js theme={null}
// Optional, only if you inject listeners into the iframe context
window.addEventListener("chatropic:nav-card-clicked", function (e) {
  console.log("Nav card clicked", e.detail); // { path, label }
});
```

<CardGroup cols={2}>
  <Card title="Web embed" icon="globe" href="/user-guides/deploy/web-widget">
    Copy website widget or inline panel snippets from Deploy, Chat widget.
  </Card>

  <Card title="Navigation routes" icon="route" href="/developer-guides/navigation-routes/navigation-routes">
    Configure destinations for the agent.
  </Card>
</CardGroup>
