Witbitz docs HomeTrustAll docs

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:

html
<script src="https://witbitz.chat/embed.js"></script>
<witbitz-space link="https://witbitz.chat/space#<your link>"></witbitz-space>

Or from script:

javascript
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 user

Witbitz.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:

Machine-readable source: embed.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)