React component reference
Package: @bootstrapware/chat
Styles: @bootstrapware/chat/styles.css
Import styles once near the feature. Use a Client Component in Next.js App Router. Bootstrapware does not authenticate chat end users. Pass user from your session.
Props
| Prop | Type | Required | Notes |
|---|---|---|---|
| user | ChatAuthor | null | yes | Opaque stable id. Optional name, email, avatarUrl for display. |
| adapter | ChatAdapter | BYO / local | If set, wins over Hosted. Use createLocalAdapter or your own API. |
| appId | string | Hosted / BYO config | With publishableKey for Hosted. Prefix cha_. |
| publishableKey | string | Hosted | Browser-safe. Never put secret keys in the client. |
| apiBaseUrl | string | no | Defaults to https://chat.bootstrapware.co |
| config | Partial<ChatAppConfig> | no | Overrides toggles / empty state until Hosted config loads. |
| authorToken | string | no | Short-lived host-signed assertion from POST /api/v1/author-tokens (secret key). Required when the app sets requireAuthorToken. |
| people | ChatAuthor[] | no | Directory for the people picker, titles, and avatars. Display only. Identity stays user.id. If omitted, New still has a collapsed Other id field. |
| launcher | boolean | no | Corner bubble with unread total. Default off so full-width embeds stay unchanged. Closed: button. Open: list + thread. Escape or backdrop closes. Position with --bsw-ch-launcher-right and --bsw-ch-launcher-bottom. |
| defaultOpen | boolean | no | Initial open state when launcher is true. |
| dir | "ltr" | "rtl" | no | Text direction. |
| className | string | no | Wrapper class for layout. |
Resolve order
- If
adapteris passed, use it (BYO orcreateLocalAdapter). - Else if both
appIdandpublishableKeyare set, use Hosted. - Else fall back to
createLocalAdapter(demo / free).
Local / demo
import { Chat, createLocalAdapter } from "@bootstrapware/chat";
import "@bootstrapware/chat/styles.css";
<Chat
user={{ id: "user_1", name: "Ada" }}
people={[{ id: "user_kai", name: "Kai" }]}
adapter={createLocalAdapter({ storageKey: "demo-chat" })}
/>Launcher
Optional corner bubble. Marketing demos stay as the full inbox. Use this when you want a collapsed embed:
<Chat
launcher
user={currentUser}
people={workspaceMembers}
adapter={createLocalAdapter({ storageKey: "demo-chat" })}
/>Closed: a button with the unread total (sum of unreadCount). Open: the same list and thread. Escape or the backdrop closes. Nudge with CSS variables --bsw-ch-launcher-right and --bsw-ch-launcher-bottom.
Browser notifications
Optional and default off. Notify in the widget header is the only control that requests Notification permission; mounting the widget never prompts. After opt-in, a message.created from someone else can show a system notification while the tab is hidden. Visible-tab messages, the viewer's own messages, opted-out, and OS deny do not notify. Denied stays off with no re-prompt loop. Clicking a notification focuses the window and opens the thread. No email, SMS, or server push.
Markup
Messages are stored as the same 4,000-character string. The widget renders a tiny subset: **bold**, _italic_, inline `code`, and simple - / * lists, plus existing http(s) linkify. No raw HTML, images in markup, or headings. Hosted inbox and JSON export stay raw text.
Hosted
<Chat
appId="cha_..."
publishableKey="bsw_live_pub_..."
user={currentUser}
/>Live config fetch needs BYO ($9.99) or Hosted ($19.99). Live Hosted writes need Hosted ($19.99). Test publishable keys work unpaid.
Limits in the UI
Body max 4000 characters. Groups max 20. Poll fallback 4 seconds, or about 20 seconds when subscribe is healthy. See limits.
Related: Modes · Adapter · Identity · Quickstart · Live updates