Embed a Space — one line, still sealed
Drop a Space into any page with one script tag. It runs in its own origin, in an iframe: your page and the scripts on it cannot reach into the frame to read its state or the messages it decrypts. Your page and the Space talk over a narrow bridge, and your page's functions can become the assistant's tools.
See it: witbitz.chat/demo — ask the embedded assistant to restyle the page, and it calls
the page's own set_site_color tool.
Before you start. Embedding is off by default. The Spaces viewer must allow your site's origin — today, ask us at hello@witbitz.chat to add it (who may embed). Once it does, embedding a room is this markup:
<script src="https://witbitz.chat/embed.js"></script>
<witbitz-space link="https://witbitz.chat/space#<your link>"></witbitz-space>Or from script:
const space = Witbitz.embed('#slot', { link })
space.on('message', (m) => …) // someone posted (metadata only)
space.on('turn', (t) => …) // an assistant turn finished
space.signIn(token) // a room that needs sign-in: admit the userWitbitz.embed(target, opts) returns a controller: on(type, cb) / off, signIn(token), navigate(to),
setTheme(theme), destroy(), and iframe. <witbitz-space> exposes the same controller as el.space.
What the iframe protects, and what it doesn't
The Space runs in a cross-origin iframe, not in your page's DOM. If it ran inside your page, your page and its trackers would become part of what has to be trusted; in its own origin, the verified client is out of their reach. The browser keeps your page out of the frame's memory, storage and DOM, so nothing on your page can read the messages the frame decrypts.
It does not hide the room from a page that holds its link. A room's link carries its key. A page that passes the full link to the embed already knows that key, so the iframe protects the room from your page's other scripts — and keeps Witbitz unable to read it — but your app itself is not blind to that room. A room your app should not be able to read must never pass through your page as a full link: let the person open it from their own invite, or keep the keys out of your page entirely with vault mode.
The bridge
The only channel across the boundary is postMessage, carrying a small JSON-RPC protocol. It is a narrow set of
messages, not shared memory:
| Direction | Message | Meaning |
|---|---|---|
| Space → host | ready |
the bridge is open |
| Space → host | message |
someone posted — metadata only ({id, self, sys}), never the content |
| Space → host | turn |
an assistant turn finished |
| Space → host | member |
a member event |
| Space → host | resize |
the content's height changed (the iframe sizes itself) |
| host → Space | signIn |
a sign-in token from your identity provider, or a signed grant |
| host → Space | navigate / theme |
deep-link or theme, within limits |
Both sides check the other's origin, nothing is posted to '*', and the room key never crosses the bridge: it rides in
the iframe's URL fragment, which never reaches a server. A sign-in token is checked against the room's sealed list.
Who may embed
Embedding is off by default, and two things decide whether a page may embed a room:
- The viewer's list — for the whole app. The browser checks the viewer's
frame-ancestorsbefore any script runs, when the room is not yet known, so it lists the origins that may embed any of the app's rooms; the room page opens its bridge only to an origin on the same list. On the hosted viewer, Witbitz keeps that list — ask us to add your origin. A page on one of your tenant's declared origins can already frame a room whose link names your tenant (?tid=t_…), but the bridge — events, sign-in, theme — opens only for a listed origin. - The room's own policy — for an owner-governed room. A room whose owner signed a policy can narrow the list with
embedOrigins: the client reads the sealed policy with the room key and closes the bridge if the embedding page is not on it, and the server never sees it. Owner-governed rooms are Implemented, not yet enabled in production; an ordinary room has no per-room step.
Read next
- The assistant — your page's functions as the assistant's tools.
- Verifying the client — why the code in the iframe can be trusted.
- Identity and admission — who may enter a room.
Machine-readable source: embed.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)