> For the complete documentation index, see [llms.txt](https://docs.supademo.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.supademo.com/share/embed/embed-events-api.md).

# Embed Events API

Supademo's Embed Events API sends postMessage events from embedded demos so your page can track loads, slide changes, progress, completion, and close.

The Supademo Embed Events API is a `postMessage` interface that lets your page listen to what viewers do inside an embedded demo. When a Supademo is embedded in your application via iframe — inline, popup, or in-app — the demo emits events to the parent window so you can track user progress and trigger actions in your own application, with no extra SDK required.

Every event is a `postMessage` with the shape `{ source: "Supademo", type, payload }`, so a single `message` listener on your page can handle all of them. The Embed Events API shipped in December 2025 and works with any embed type, since all Supademo embeds render the demo in an iframe.

## What can you do with embed events?

Supademo emits `postMessage` events to the parent window, allowing you to:

* Detect when a demo starts, progresses, or completes
* Track which slide the user is viewing
* Close modals or trigger navigation when a demo finishes
* Build custom progress indicators
* Fire analytics events or advance onboarding checklists from demo activity

## Quick start: listen for Supademo events

Add this listener to your parent page — the page that contains the iframe:

```javascript
window.addEventListener('message', (event) => {
  // Only handle Supademo events
  if (event.data?.source !== 'Supademo') return;

  console.log('Supademo event:', event.data.type, event.data.payload);
});
```

Always check `event.data?.source !== 'Supademo'` first, because browsers deliver `message` events from every iframe and script on the page — the `source` field is how you filter to Supademo's.

## Event reference

These six events are the complete set emitted by embedded Supademo demos:

| Event                  | Fires when                                      | Key payload fields                                                     |
| ---------------------- | ----------------------------------------------- | ---------------------------------------------------------------------- |
| `Supademo:load`        | The demo initially loads in the iframe          | `demoId`, `title`, `totalSlides`                                       |
| `Supademo:started`     | The user first interacts with the demo          | `demoId`, `title`                                                      |
| `Supademo:slideChange` | The user navigates to a different slide         | `demoId`, `currentSlide`, `totalSlides`, `isFirstSlide`, `isLastSlide` |
| `Supademo:progress`    | Alongside every slide change, with a percentage | `demoId`, `percentage`, `currentSlide`, `totalSlides`                  |
| `Supademo:completed`   | The user reaches the final slide                | `demoId`, `title`, `completedAt`                                       |
| `Supademo:close`       | The user presses ESC while viewing the demo     | None                                                                   |

\[VERIFY: whether embedded Showcases emit the same events — the event list above is confirmed for embedded demos]

## Event details

### `Supademo:load`

Fired when the demo initially loads in the iframe.

**Payload:**

| Field         | Type   | Description            |
| ------------- | ------ | ---------------------- |
| `demoId`      | string | Unique demo identifier |
| `title`       | string | Demo title             |
| `totalSlides` | number | Total number of slides |

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:load",
  payload: {
    demoId: "abc123",
    title: "Getting Started Guide",
    totalSlides: 5
  }
}
```

***

### `Supademo:started`

Fired when the user first interacts with the demo (clicks, navigates, etc.).

**Payload:**

| Field    | Type   | Description            |
| -------- | ------ | ---------------------- |
| `demoId` | string | Unique demo identifier |
| `title`  | string | Demo title             |

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:started",
  payload: {
    demoId: "abc123",
    title: "Getting Started Guide"
  }
}
```

***

### `Supademo:slideChange`

Fired whenever the user navigates to a different slide.

**Payload:**

| Field          | Type    | Description                      |
| -------------- | ------- | -------------------------------- |
| `demoId`       | string  | Unique demo identifier           |
| `currentSlide` | number  | Current slide number (1-indexed) |
| `totalSlides`  | number  | Total number of slides           |
| `isFirstSlide` | boolean | `true` if on the first slide     |
| `isLastSlide`  | boolean | `true` if on the last slide      |

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:slideChange",
  payload: {
    demoId: "abc123",
    currentSlide: 3,
    totalSlides: 5,
    isFirstSlide: false,
    isLastSlide: false
  }
}
```

***

### `Supademo:progress`

Fired alongside `slideChange` with a percentage value for building progress bars.

**Payload:**

| Field          | Type   | Description                      |
| -------------- | ------ | -------------------------------- |
| `demoId`       | string | Unique demo identifier           |
| `percentage`   | number | Completion percentage (0-100)    |
| `currentSlide` | number | Current slide number (1-indexed) |
| `totalSlides`  | number | Total number of slides           |

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:progress",
  payload: {
    demoId: "abc123",
    percentage: 60,  // Slide 3 of 5 = 60%
    currentSlide: 3,
    totalSlides: 5
  }
}
```

***

### `Supademo:completed`

Fired when the user reaches the final slide of the demo.

**Payload:**

| Field         | Type   | Description            |
| ------------- | ------ | ---------------------- |
| `demoId`      | string | Unique demo identifier |
| `title`       | string | Demo title             |
| `completedAt` | string | ISO 8601 timestamp     |

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:completed",
  payload: {
    demoId: "abc123",
    title: "Getting Started Guide",
    completedAt: "2025-01-15T10:30:00.000Z"
  }
}
```

***

### `Supademo:close`

Fired when the user presses the **ESC** key while viewing the demo.

**Payload:** None

**Example:**

```javascript
{
  source: "Supademo",
  type: "Supademo:close"
}
```

## Common use cases

### Fire analytics on demo engagement

Forward demo starts and completions to your analytics tool to measure how embedded demos convert:

```javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'Supademo') return;

  const { type, payload } = event.data;

  switch (type) {
    case 'Supademo:started':
      analytics.track('Demo Started', { demoId: payload.demoId });
      break;
    case 'Supademo:completed':
      analytics.track('Demo Completed', { demoId: payload.demoId });
      break;
  }
});
```

### Advance an onboarding checklist

If your product shows an onboarding checklist with a "Watch the tour" step, listen for `Supademo:completed` and mark that step done the moment the user finishes the embedded demo. This pairs naturally with [in-app product tours](https://docs.supademo.com/share/embed/in-app-product-tours), where demos run inside your own product.

### Close a modal on demo completion

```javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'Supademo') return;

  if (event.data.type === 'Supademo:completed') {
    // Wait 1 second then close the modal
    setTimeout(() => {
      closeModal();
    }, 1000);
  }
});
```

### Close a modal on ESC key

```javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'Supademo') return;

  if (event.data.type === 'Supademo:close') {
    closeModal();
  }
});
```

### Build a custom progress bar

```javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'Supademo') return;

  if (event.data.type === 'Supademo:progress') {
    const { percentage } = event.data.payload;
    document.getElementById('progress-bar').style.width = `${percentage}%`;
  }
});
```

### Show a slide counter

```javascript
window.addEventListener('message', (event) => {
  if (event.data?.source !== 'Supademo') return;

  if (event.data.type === 'Supademo:slideChange') {
    const { currentSlide, totalSlides } = event.data.payload;
    document.getElementById('slide-counter').textContent =
      `Step ${currentSlide} of ${totalSlides}`;
  }
});
```

## Notes

* Events are only emitted when the demo is embedded in an iframe
* Events work with every Supademo embed type — [inline embeds](https://docs.supademo.com/share/embed/website-embed), [popup embeds](https://docs.supademo.com/share/embed/popup-embed), and in-app product tours — because all of them render the demo in an iframe
* Every message has the shape `{ source: "Supademo", type, payload }`; filter on `event.data.source` before reading other fields
* The `percentage` in `Supademo:progress` represents slides viewed (e.g., slide 3 of 5 = 60%)
* `currentSlide` values are 1-indexed to match what the viewer sees in the demo UI
* Events are non-blocking and won't affect demo performance
