Skip to main content
The BubblaV SDK provides programmatic control over your chat widget. The shared npm package owns script readiness, authenticated-user token refresh, and tool-completion subscriptions; the React, Vue, and Angular packages adapt that lifecycle to their frameworks.
The SDK is automatically loaded when you add the widget to your site. For React, Vue, and Angular projects, we recommend using our NPM packages for better type safety and framework integration.

Installation

Install your framework package and the shared SDK (for browser types and server-only token helpers):
1. Install the package:
2. Add the widget to your app:
3. Control the widget programmatically:
NPM packages provide full TypeScript support, framework-specific patterns, and better lifecycle management.

Global SDK

When using a script embed, the loader exposes window.BubblaV. Its presence alone does not mean the real API has finished loading. The shared helper waits for the loader’s readiness callback:
waitForBubblaVAPI({ signal?, timeoutMs? }) does not mount a widget. It returns the ready BubblaVAPI, or null on server rendering, cancellation, or timeout (15 seconds by default). For a framework-neutral lifecycle that also loads the script, use mountBubblaVWidget below.

Authenticated dashboard integration

Your backend authenticates the user and mints the initial token. Pass that token to one widget in your client layout, then let the SDK refresh it when the widget requests identity. Never put a signing secret in client code.

React

BubblaVWidgetProps uses the shared WidgetOptions contract. The component renders no host markup. useBubblaVWidget() and a component ref return the actual API only after readiness, and are initially null.

Vue and Angular

Vue uses typed props and tool-executed / error emits:
Angular exposes identity / toolRefresh inputs and toolExecuted / error outputs:
Supply the Angular toolRefresh input with the same { refresh, shouldRefresh, debounceMs } shape as React. Framework wrappers mount on the client, update the existing connection when props/inputs change, and dispose it on unmount/destruction.

Framework-neutral JavaScript / TypeScript

mountBubblaVWidget(options) returns a WidgetConnection: ready: Promise<BubblaVAPI>, update(options): void, and dispose(): void. update takes the complete options, not a partial patch. Browser imports have no DOM side effects; mounting outside a browser reports configuration.

Identity and custom refresh

identity accepts { token: string | null, tokenEndpoint?: string, getToken?: IdentityTokenProvider }:
  • Omit identity for an unmanaged embed. It does not clear an externally supplied token on initial mount. Removing previously managed identity clears it; use explicit { token: null } for logout.
  • A nonempty token provides initial identity. Empty/whitespace tokens are configuration errors. A refresh source is optional, but without one the SDK cannot renew the token.
  • { token: null } clears identity, aborts pending refresh, and ignores subsequent identity requests until a non-null token is supplied. Disposal also clears identity managed by that connection. Start a new conversation when changing users; tokens do not change conversation ownership.
  • tokenEndpoint performs GET with credentials: 'same-origin', cache: 'no-store', and an AbortSignal. It requires an OK JSON response containing a nonempty string token. The endpoint must authenticate the current session; there is no assumed endpoint path.
  • Set at most one of tokenEndpoint and getToken. For POST, custom headers, or another credential policy, supply getToken instead:
The SDK awaits getToken and delivers its result via identify. In contrast, the global onIdentityNeeded / on('identityNeeded', callback) event ignores callback return values: a low-level listener must call identify(token) itself. Use one lifecycle owner rather than registering both approaches. Concurrent identity requests share one in-flight refresh. Requests time out after 5 seconds, and obsolete responses cannot restore an identity after logout, token change, or disposal. Rerendering with the unchanged initial token does not revert a refreshed token. Keep a custom provider stable when its behavior has not changed; replacing a refresh source cancels its in-flight work. Refresh failures report identity_refresh_failed without clearing the current identity, silently downgrading to anonymous, or automatically retrying. A later widget identity request can try again. The widget can show its session-expired notice; the SDK never resends a write. See token expiry behavior for the widget’s narrowly scoped pre-dispatch chat recovery.

Tool completion and refreshing host views

The event is named toolExecuted (singular), with payload ToolExecutedEvent = { toolNames: string[] }. The SDK ignores invalid/empty payloads and trims nonempty tool names. onToolExecuted runs immediately for each valid event. toolRefresh is a separate, optional convenience:
  • refresh: () => void is required; it refreshes the host’s selected views, not the chat message.
  • shouldRefresh(event) runs per event and defaults to true. The host decides which tool names affect which views; the SDK does not infer reads or writes.
  • debounceMs defaults to 500 ms, trailing-edge; 0 runs immediately. Negative or nonfinite values are configuration errors.
  • Updated callbacks are used without duplicate subscriptions. Pending refresh is cancelled on identity change or disposal; callback exceptions do not block identity cleanup or other subscribers.
Completion includes both output-available and output-error. It is not evidence of successful mutation, authorization, or human approval. Do not use it to approve or retry writes.

Ownership and errors

Mount only one owning widget per document. Same-configuration remounts reuse the script, including framework development remounts. Disposal unsubscribes, aborts refresh, cancels debounce, clears managed identity, and hides the widget; it retains the loader script. Mounting a different website in the same document is a widget_conflict; switching sites requires a full document navigation, not script removal or private-global resets. Do not combine a separate script embed with an npm-owned widget. onError receives BubblaVWidgetError with a code: configuration, widget_conflict, load_failed, ready_timeout, identity_unsupported, or identity_refresh_failed. Initial load/readiness failures also reject connection.ready; consume that rejection in vanilla integrations. Framework wrappers already consume it. There is no automatic script retry or production fallback.

Server-only token helpers

Import these helpers only from @bubblav/ai-chatbot-sdk/server in your backend (Node.js 18+). The browser entry does not include token signing. No helper reads your environment automatically: pass explicit options from server-only configuration.
Mint the initial server-rendered token with await createEndUserToken({ userId: user.id, email: user.email }, identityOptions) after authenticating user, and pass the resulting string to the client example above. A refresh route uses the same authenticated-user lookup; it must never accept a user ID supplied by the browser:
Minting uses HS256, UTF-8 secret bytes (not hex decoding), iss: bubblav-end-user, an exact-string website audience, sub, website_id, numeric iat/nbf/exp, and random UUID jti. Subjects must be nonempty and at most 128 characters; optional email/name snapshots are at most 256 characters, with null snapshots omitted. Pinned claims cannot be overridden. Verification pins HS256 and iss: bubblav, rejects audience arrays, requires unexpired exp and a nonempty subject of at most 128 characters, validates finite time claims and matching website_id when present, and honors nbf with 30 seconds of tolerance. Expiration is strict (now >= exp fails); the tolerance does not extend expiry. McpIdentity contains only { sub, websiteId, email? }, with email returned only if a string of at most 256 characters. There is no automatic previous-key expiry timer. verifyMcpRequest also checks nonempty X-BubblaV-User-Id and X-BubblaV-Website-Id against the verified identity. Headers without a JWT never establish identity. For a raw JWT supplied by your transport, use await verifyMcpToken(token, verificationOptions); that helper does not inspect request headers.
Your MCP route decides whether missing identity is allowed for discovery (initialize, notifications, tools/list); it must explicitly reject it for protected tools/call, including calls inside a batch. Invalid credentials are errors, never anonymous discovery. Map token errors to your transport’s authentication response, and resolve current authorization from the verified sub for every operation. The SDK does not own membership, authorization, transport, audit, replay prevention, or approval policy. Credentials prove identity, not human consent to tool arguments. See In-App Chatbot Integration for MCP configuration, the claim contract, key rotation, immutable conversation identity, and approval limitations.

SDK Methods

Widget Control

open()

Opens the chat widget.
Use cases:
  • Trigger chat from a custom button
  • Open chat after a user action
  • Start conversation proactively

close()

Closes the chat widget.
Use cases:
  • Close chat after a conversation
  • Respond to user dismiss action

toggle()

Toggles the widget open/closed state.
Use cases:
  • Single button to toggle widget
  • Keyboard shortcuts for chat access

openSearch()

Opens the search interface (modal).
Use cases:
  • Trigger search from a custom button
  • Open search after a user action

isOpen()

Checks if the widget is currently open.
Returns: boolean

Messaging

sendMessage(text, conversationId?)

Sends a message programmatically.
Use cases:
  • Start conversation with a suggested message
  • Send contextual help based on page content
  • Pre-fill messages based on user actions

showGreeting(data)

Shows a greeting message to the user with optional sender information.
Use cases:
  • Display contextual greetings based on page
  • Show agent-specific messages with avatar
  • Time-based greetings (good morning, etc.)
  • Campaign-specific messages

hideGreeting()

Hides the greeting message.

Configuration

getConfig()

Gets the current widget configuration.
Returns: object with current configuration

setDebug(enabled)

Enables or disables debug mode.
Only enable debug mode in development. It logs detailed information to the console.

Event System

The SDK emits events for various widget actions. Listen to events to respond to user interactions.

on(event, callback)

Register an event listener.

off(event, callback)

Unregister an event listener.

Available Events


Framework Examples

React

Using Hooks

Using the Widget Component


Vue

Using Composition API


Angular


TypeScript Support

The shared package owns the browser API and lifecycle types. Frameworks use the same BubblaVAPI; there is no separate framework-specific global declaration to copy:
Vue’s useBubblaVWidget() returns Ref<BubblaVAPI | null>; use .value in script. Angular’s BubblaVWidgetService exposes open(), close(), toggle(), sendMessage(message), identify(token: string | null), and onToolExecuted(callback), which returns an unsubscribe function that also cancels a pre-ready subscription. For managed identity, prefer the component’s identity input rather than mixing direct service calls with SDK refresh.

Best Practices

  1. Prefer NPM Packages For React, Vue, and Angular projects, use the NPM packages instead of the global SDK for better type safety and lifecycle management.
  2. Wait for Ready State Always check if the SDK is ready before using it:
  3. Clean Up Listeners Remove event listeners when they’re no longer needed:
  4. Handle Edge Cases Check if methods exist before calling:
  5. Use Environment Variables Store your website ID in environment variables:

Full SDK Reference


Next Steps

Widget Design

Customize widget appearance and behavior

Starter Templates

Quick-start templates for Next.js and Nuxt