Reference

Web chat widget

Embed a Cradle-backed chat widget on any website with a single script tag — history, typing indicator, and real-time replies.

The Cradle web widget is a full chat channel, not a contact form. A visitor sees a floating button, opens a chat window with message history, sends a message, and receives a reply from Cradle in real time.

Bundle size: ~49 KB gzipped.

Embed

Add one script tag to any page:

<script
  src="https://cradle.example.com:31415/widget.js"
  data-cradle-widget
  data-api-key="wk_..."
  data-accent="#10b981"
  data-position="bottom-right"
  async></script>

Replace the host and port with wherever your Cradle widget endpoint is reachable. For local testing this is http://localhost:31415/widget.js.

Configuration attributes

AttributeRequiredDescription
srcyesWidget bundle URL
data-cradle-widgetyesMount marker
data-api-keyyesWidget API key from channel config
data-accentnoHex color for the launcher and send button
data-positionnobottom-right (default) or bottom-left

Server-side theme, position, and locale are returned by GET /api/widget/config/:apiKey. Client attributes override some values.

Architecture

  • packages/widget/ — Vite IIFE bundle, React inlined.
  • src/core/channels/widget-channel.ts — Fastify server in the main process.
  • Shadow DOM mount isolates styles from the host page.
  • No postMessage to the parent window: all communication goes through HTTP and WebSocket to Cradle.

Server endpoints

EndpointPurpose
GET /widget.jsServe the bundle with long cache headers
GET /api/widget/config/:apiKeyTheme, color, position, locale
POST /api/widget/messageAccept a visitor message (X-Visitor-Id header)
WS /api/widget/ws?visitorId=...&apiKey=...Real-time replies and typing events

Client behavior

  • visitorId is generated on first open and stored in localStorage.
  • Chat history is cached locally, so a page reload keeps the conversation.
  • WebSocket auto-reconnects with exponential backoff.
  • Typing indicator shows while a reply is pending.

Security

  • Widget API key is configured per channel in channels_config.widget.config.apiKey.
  • Optional allowedOrigins list restricts which sites can load the widget.
  • Rate limit is applied per IP + key.
  • For production, expose the widget endpoint through a reverse proxy or tunnel and serve it over HTTPS.