| read_when |
|
|---|
ClickClack exposes a minimal thread-only page for docking a conversation in an iframe. It contains the root message, replies, the normal thread composer, and live updates, but none of the workspace rail, sidebar, or full-app top bar.
It also exposes a channel embed with the shared message renderer, paginated history, nonce-idempotent composer, and realtime cursor recovery. Its slim header names the channel and links back to the canonical full ClickClack view. Authenticated users can edit their own thread roots, replies, and channel messages inline; the embeds use the same draft, error, and realtime reconciliation behavior as the full app.
Use the public route IDs from a normal ClickClack thread URL:
https://chat.example.com/embed/thread/{workspace_route_id}/{message_route_id}
For a whole channel, use the workspace and channel public route IDs:
https://chat.example.com/embed/channel/{workspace_route_id}/{channel_route_id}
For example:
https://chat.example.com/embed/thread/T01KR3EXAMPLE1234/M01KR3EXAMPLE1234
The message route ID must identify a thread-root message. The viewer resolves both public IDs through the normal route API, then uses the existing thread and realtime endpoints. Humans authenticate with their normal ClickClack session cookie. A signed-out frame offers a link that opens ClickClack in a new tab and automatically retries when focus returns after sign-in.
The channel route ID must be a public C... channel route. The channel embed
uses the same membership and guest-channel visibility checks as the full app;
archiving a channel does not invalidate its embed URL.
An embedding application can select the initial color mode without changing the user's standalone ClickClack appearance:
https://chat.example.com/embed/channel/T01/C01?theme=dark&hostOrigin=https%3A%2F%2Fcontrol.example.com
theme accepts light or dark. hostOrigin must be the exact HTTP(S) origin
of the parent window, without a path or trailing slash. The color mode applies
before the first paint and continues to take precedence when ClickClack loads the
user's account preferences.
For a custom palette, add themeTokens containing the JSON-encoded semantic
token object shown below. Set the parameter with
url.searchParams.set("themeTokens", JSON.stringify(tokens)) so it is encoded
correctly. ClickClack validates each initial CSS value and applies its colors,
surfaces, borders, and corner radius before the first paint; snapshots larger
than 16 KiB are ignored.
After the iframe loads, the host can keep its full palette synchronized by
sending a complete openclaw:widget-theme snapshot to the ClickClack origin:
iframe.contentWindow?.postMessage(
{
type: "openclaw:widget-theme",
mode: "dark",
tokens: {
surface: "#0e1015",
card: "#161920",
text: "#d4d4d8",
accent: "#ff5c5c",
},
},
"https://chat.example.com",
);ClickClack accepts these messages only from the parent window at hostOrigin.
Tokens update the embedded document only; they are not written to local storage
or the user's account. Send another full snapshot whenever the host theme
changes. Omitted tokens return to ClickClack's own theme defaults.
Only /embed/* HTML responses receive a frame policy. With no configuration,
the response is restricted to:
Content-Security-Policy: frame-ancestors 'self'Add the exact HTTP(S) origins that may host the iframe with the environment variable or serve flag:
CLICKCLACK_EMBED_FRAME_ANCESTORS=https://control.example.com,https://ops.example.comclickclack serve \
--embed-frame-ancestors https://control.example.com,https://ops.example.comThe JSON config-file equivalent is:
{
"embed_frame_ancestors": [
"https://control.example.com",
"https://ops.example.com"
]
}ClickClack validates each value as an origin without credentials, a path,
query, or fragment. The resulting policy always retains 'self'. Other SPA,
API, upload, and asset responses keep their existing frame behavior.
An iframe is authenticated only when the browser sends the ClickClack session
cookie in that embedding context. ClickClack's cookie SameSite mode follows the
configured CLICKCLACK_PUBLIC_URL and CLICKCLACK_PUBLIC_API_URL: same-host
deployments use SameSite=Lax, while different HTTPS frontend/API hostnames
use SameSite=None; Secure. Browser third-party-cookie controls can still
block cookies in an unrelated-site iframe even when the cookie uses
SameSite=None. Allowing an unrelated origin in frame-ancestors does not
change this cookie setting; an embed on an unrelated site will not authenticate
when the session cookie is SameSite=Lax.
The recommended deployment keeps ClickClack and the host application under the
same parent domain, such as chat.example.com and control.example.com. That
topology is same-site, avoids depending on third-party-cookie exceptions, and
still allows each service to keep its own origin. Do not loosen CORS, cookie,
or global frame policy for embedding; configure only the host origins that need
the /embed/* view.