# Show it in an iframe (/docs/embed/iframe)

Ask your endpoint for a fresh link every time the page opens, put it in the iframe, done.

<Tabs items={['HTML', 'React']}>
<Tab value="HTML">

```html
<iframe id="hl" title="Website visitors" style="width:100%;height:100%;border:0"></iframe>
<script>
  fetch('/api/leads-embed?view=auto')
    .then((r) => r.json())
    .then(({ url }) => { document.getElementById('hl').src = url; });
</script>
```

</Tab>
<Tab value="React">

```tsx
export function WebsiteVisitors({ view = 'auto' }: { view?: string }) {
  const [url, setUrl] = useState<string>();
  useEffect(() => {
    fetch(`/api/leads-embed?view=${view}`)
      .then((r) => r.json())
      .then((d) => setUrl(d.url));
  }, [view]);
  return url ? <iframe src={url} title="Website visitors" style={{ width: '100%', height: '100%', border: 0 }} /> : null;
}
```

</Tab>
</Tabs>

- **One iframe per screen**, each behind its own menu item: for example *Website visitors* (`view=auto`) and *Install tracking* (`view=install`).
- **Never reuse a link.** It works once; fetch a new one every time the screen is shown.
- Only the app addresses you saved in Embed settings can show it. Anywhere else the frame is blank.

## Try it [#try-it]

<EmbedPreview />

## Messages from the frame [#messages-from-the-frame]

The frame tells your page what happens with `postMessage`. They carry no secrets and no brand name. Always check the origin:

```js
const frameOrigin = new URL(url).origin;
let lastReload = 0;
window.addEventListener('message', (e) => {
  if (e.origin !== frameOrigin) return;
  if (e.data.type === 'session-ended' && Date.now() - lastReload > 30_000) {
    lastReload = Date.now();
    loadFreshLink(); // ask your endpoint again
  }
});
```

| `type` | Extra fields | When |
| --- | --- | --- |
| `ready` | `view`, `websiteId`, `expiresIn` | The session opened |
| `page` | `path` | The screen changed page inside the frame |
| `navigate` | `view` | The frame switched between `install` and `leads` (for example once the pixel works): update your own menu if you like |
| `session-expiring` | `inMs` | The session ends soon |
| `session-ended` | `reason` | The session ended (its length ran out, or the key was revoked or embedding switched off): load a fresh link |
| `error` | `message` | Something failed inside the frame (also an expired or already-used link) |

## Keep it white label [#keep-it-white-label]

Your users never see our name: the screen comes from your domain ([One-time setup](/docs/embed/setup)) and the messages carry no brand. Keep our name out of your own routes, page titles, iframe titles, menu items and error messages too; use your own words, such as *Website visitors*.

**Next:** [billing: start a trial](/docs/embed/start-trial).
