The embed widget · Phase 22

One script tag. Chat inside any PM tool.

Drop a Web Component into Jira, Linear, Productboard, or your own admin dashboard. ContextBrain chat opens in-place, scoped to whichever project the user is already looking at. HMAC user-identity for staff, per-project share-token for client-facing pages.

app.example.com/proj-kyc
PROJ-KYC · KYC Portal

Live preview unavailable

Run npm run db:migrate && npm run db:seed to mint a demo embed token.

The 30-second integration

Paste once, ship.

<script
  src="https://app.contextbrain.io/embed.js"
  data-key="cb_pub_yourpublishablekey"
  data-position="right"
  data-theme="cb-dark"
></script>

No PM-side backend. Client-facing pages only. Token clamps role to client.

<contextbrain-chat
  embed-key="cb_pub_yourpublishablekey"
  share-token="cb_chat_abc12345_…"
  position="right"
></contextbrain-chat>
<script src="https://app.contextbrain.io/embed.js"></script>

What you control

Whitelisted theming, sanitized slots.

The widget exposes 18 preset themes, 15 CSS-variable knobs, and 3 sanitized HTML slots. No arbitrary CSS injection, no JS expressions — paste safely from your own templating engine.

18 preset themes

cb-dark, cb-light, plus the 16 Zed-ported themes from Phase 21's registry. Set via thedata-theme attribute or the Web Component's theme prop.

15 named CSS variables

Override on the host element via style="…": --cb-accent, --cb-radius, --cb-bg, --cb-text, font knobs, FAB size + offset.

3 sanitized HTML slots

header-slot, empty-slot, footer-slot. Allowlist: <b> <i> <em> <strong> <a> <br>. Links auto-get rel="noopener noreferrer".

Procurement reads this first

Security boilerplate, surfaced.

Origin allowlist

Every key carries a list of origins. Off-list pages get refused at three layers: CSP frame-ancestors, HTTP Origin header on /api/v1/embed/*, and postMessage origin checks.

JWT with HS256 only

alg=none and RS* rejected before signature check. 5-minute TTL ceiling. Redis jti replay cache. ~30 LOC against node:crypto, no third-party JWT lib in the verify path.

Privilege ceiling

Even an org owner has their effective role clamped inside the embed surface. The embed session cookie is Path=/embed and refused on /admin/* by the proxy middleware.

Loader < 8 KB gzipped

Handwritten DOM, no React/Preact, esbuild IIFE. Current build sits at ~2.8 KB. CI fails on size regression.

Use cases

Where teams already drop the widget.

Inside Jira / Linear

Staff opens a project; the embed shows context-aware chat for that exact ticket / issue. HMAC user-identity flow.

Client portal

Embed inside your white-labeled client portal; chat clamped to audience='client'. Per-project share token.

Internal docs hub

Drop it into Notion / Confluence via the embed JS; ContextBrain becomes the search bar across your knowledge base.

Standalone client iframe

Already have a chat slot (Intercom-style)? Swap in ContextBrain by changing one <script> tag.

Drop a script tag, ship a surface.

Mint a publishable key in /admin/settings/embed and paste the snippet — your users will never know you didn't build it.