# Changelog
Source: https://docs.bubblav.com/changelog
Product updates and new features
Discover what's new in BubblaV. We release new features and improvements monthly.
* **Visitor Greeting Triggers**: Greet visitors the moment they arrive — new `new_visitor` and `returning_visitor` page-behavior triggers fire on page load and open the conversation with an AI-personalized message, so first-timers and regulars get different welcomes. Requires a Pro plan. See [Flows](/user-guide/flows).
* **Mobile Apps**: Take your AI support inbox anywhere. Browse conversations, reply live, hand off to Copilot drafts, and translate replies from your phone. Android is available now on [Google Play](https://play.google.com/store/apps/details?id=com.bubblav.mobile); iOS is coming soon to the App Store.
* **Zoho Commerce Integration**: Connect your Zoho Commerce store — customers can track orders, search your catalog in natural language, and check stock availability, around the clock. OAuth connect with every Zoho data center supported (US, EU, India, Australia, Japan). See [Zoho Commerce](/user-guide/integrations/zoho-commerce).
* **Product Card Button Labels**: Customize the text on every product card button in the chat widget — "View" and "View detail" can say whatever fits your store (up to 40 characters each). Find it under Widget Design → Advanced Settings. See [Widget Design](/user-guide/widget-design).
* **HubSpot Meeting Scheduling**: Visitors can book a meeting right in chat using your HubSpot Meetings links. See [HubSpot](/user-guide/integrations/hubspot).
* **Zapier API-Key Connections**: Connect Zapier with a BubblaV API key instead of OAuth — create a key under website Settings → API keys and paste it into the new **BubblaV (API Key)** Zapier app. Also fixed an "Authorization failed" error during Zapier OAuth caused by a missing JWT secret on the server. See [Zapier](/user-guide/integrations/zapier).
* **Flows**: A visual scenario builder for your chatbot — compose triggers, conditions, and actions on a canvas: match visitor intent, collect input, show forms, run tools, call webhooks, notify your team, and hand off to a human. Smart Triggers, human-handoff scenarios, and forms now live inside flows. Test runs and a per-step run history are built in. Requires a Pro plan. See [Flows](/user-guide/flows).
* **Detected forms become Flows**: Forms BubblaV spots while crawling your site are now imported as ready-made (inactive) flows — a form-submitted trigger wired to a team notification. Activate the ones you want from the Flows list. Requires a Pro plan. See [Forms](/user-guide/forms).
* **MCP form tools**: `bubblav_list_forms`, `bubblav_create_form`, `bubblav_update_form`, and `bubblav_delete_form` are back — AI agents can manage forms again, and `form_submitted` triggers accept an optional `formId` to pin a flow to one form. See [MCP Server](/developer-guide/mcp-server).
* **Smart Triggers**: Your chatbot can now proactively start the conversation at the moment a visitor is most likely to engage — after a set time on a page, or right as they're about to leave (exit intent). Target specific pages with URL rules, let the AI personalize the opener from your message template, set cooldowns to avoid over-messaging, and steer follow-up replies with an optional conversation goal. Triggered messages don't count toward your monthly message quota. Requires a Pro plan. See [Flows](/user-guide/flows).
* **BubblaV Assistant Upgrades**: The in-dashboard Assistant is now available on the **Dashboard Home page** — not only the question-mark icon on website pages. It can now **update settings for you**, not just answer questions: ask it to add a review link, turn on lead collection, or change your chatbot's greeting, and it applies the change directly. It supports any language, and every account gets **100 free Assistant credits per month**, separate from the monthly message quota. See [In-Dashboard Help Assistant](/user-guide/help-assistant).
* **Notification Center**: A new bell icon in the sidebar opens a persistent inbox of everything that needs your attention — visitor messages, support requests, form submissions, and quota alerts.
* **Browser Push Notifications**: Get desktop and mobile push notifications the moment a visitor messages you. Enable push per browser from the sidebar banner or Account Settings.
* **Chatbot Logs**: A new **Log** page under Chatbot shows every tool call your chatbot makes — MCP servers, custom webhook tools, and built-in tools — with status (Succeeded/Failed) and date-range filters. Click any call to inspect its arguments (secrets redacted), result, and error message so you can troubleshoot failures. Find it under Chatbot → Log or via ⌘K search.
* **Copilot-Only Knowledge Sources**: Mark Files, Q\&A, or Tickets as **Copilot only** to hide them from your visitor-facing chatbot while keeping them available to your team's Copilot for drafting replies. Internal-only content stays out of customer chats.
* **Tool Errors in Weekly Report**: Your weekly report email now highlights your chatbot's top tool failures of the week.
* **Live Chat Typing Indicators**: Visitors and human agents now see typing dots during live support, so it's clear when a reply is on the way.
* **Zalo Integration**: Connect your Zalo Official Account or a Zalo bot token from Zalo Bot Creator — customer chats are answered by AI from your knowledge base and land in the unified Live Support inbox. No OAuth required. See [Zalo](/user-guide/integrations/zalo).
* **Telegram Integration**: Connect a Telegram bot with a token from @BotFather — customer DMs are answered by AI from your knowledge base and land in the unified Live Support inbox, with human takeover when you step in. No OAuth required. See [Telegram](/user-guide/integrations/telegram).
* **Shopify Product Recommendations**: A new tool lets your chatbot recommend products as one curated, ranked card group. See [Shopify](/user-guide/integrations/shopify).
* **HubSpot Ticket Sync**: HubSpot conversations and tickets now sync into your unified Live Support inbox every 2 minutes. Reply from BubblaV straight into the HubSpot thread, and draft replies with one-click AI Copilot. See [HubSpot](/user-guide/integrations/hubspot).
* **Self-Learning (Beta)**: Your chatbot now learns from real conversations — when a human agent resolves a chat, a visitor gives a thumbs-down, or the bot stumbles, BubblaV drafts a new Q\&A for your review in Knowledge → Q\&A. Enable Auto-apply in Settings to publish strong answers automatically (Pro). See [Self-Learning](/user-guide/knowledge/self-learning).
* **Email Unified Inbox (IMAP)**: Connect any mailbox — Gmail, Outlook, Zoho, and more — over IMAP. Inbound email lands in your live-support inbox as threaded tickets that agents can reply to right from BubblaV.
* **AI Copilot Upgrades**: A new one-click *Draft reply* button turns any visitor message into a ready-to-edit reply, and Copilot now reads visitor attachments (PDFs, documents, images) for better-informed drafts.
* **Live Support Inbox**: Archive and bulk-select conversations, pin important ones to the top, and filter the unified inbox by the Email channel.
* **YOLO Mode (Unrestricted Knowledge)**: A new per-website Settings toggle (off by default) that lets your chatbot and Copilot answer from their general knowledge and live web search — beyond your site's knowledge base — for broader coverage when you want it. Note: answers may be less on-brand and web-search calls add to your AI usage.
* **TidyCal Scheduling**: New booking integration with OAuth connect and booking lookup.
* **In-Dashboard Help Assistant**: Click the question-mark icon on any website page to ask the BubblaV Assistant, in plain English, how to set up your bot — leads, quotes, reviews, integrations, and more — right inside the dashboard.
* **Cal.com**: New scheduling integration with OAuth connect, EU + Global region support, inline booking suggestions.
* **Acuity Scheduling**: New scheduling integration with OAuth connect and inline booking.
* **Google Tag Manager**: No-code GTM installation option with install guide button for easy setup.
* **22 New MCP Server Tools**: User-facing configuration tools for managing your chatbot settings via MCP.
* **Visitor Memory**: AI chatbot now remembers visitors across sessions for personalized, context-aware conversations.
* **Forms**: Create custom forms that your AI chatbot can show to visitors to collect structured data—feedback, contact details, quote requests, and more—directly inside the chat. AI-powered triggering, email notifications, and a submissions dashboard.
* **Human Handoff Scenarios**: Configure specific questions or intents that should always be handled by human agents
* **Google Drive Integration**: Connect Google Drive as a knowledge source with OAuth, automatic content sync, and vector embedding on creation.
* **Custom Tool Templates**: New template selection system with 6 ready-made templates including Order Email Notification, reducing setup time for common use cases.
* **ChatGPT MCP Integration**: Full ChatGPT App with OAuth DCR support.
* **Claude & OpenClaw MCP Support**: MCP connector now supports Claude, ChatGPT, and OpenClaw clients.
* **AI Chatbot SDKs**: Launched official npm packages for React, Vue, and Angular.
* **Zendesk OAuth App**: Added native Zendesk OAuth app with Help Center and ticket knowledge sync, simplified setup.
* **Bottom-Center Pill Widget**: New widget position.
* **llms.txt Support**: Added llms.txt and llms-full.txt support with Vibe Coding integration.
* **Live Support Unified Inbox Redesign**: Complete redesign of the live support dashboard with dynamic chat platform menu, channel filtering by installed integrations, and improved sidebar navigation.
* **WordPress Plugin & WooCommerce Plugin**: Full support for WordPress and WooCommerce sites with easy installation, automatic content sync, and unified chat management.
* **BigCommerce App**: Native BigCommerce application integration with product catalog access, order tracking, and customer management.
* **Messenger, Slack & Discord**: Complete chat platform integrations with bot functionality, conversation continuity, and human agent handoff support.
* **Notion Integration**: Introduced Notion as a knowledge base source with content crawling and RAG support.
* **Haravan Integration**: Added Vietnamese e-commerce platform support with OAuth installation and script tag injection.
* **Zapier Integration**: Complete automation platform with 14 triggers, 4 actions, and 3 searches for workflow automation.
* **Attio Integration**: CRM integration for contact management, visitor profile sync, and proactive chat initiation.
* **Chat Widget Improvements**: Added drag-to-resize functionality for expanded chat widget.
* **Dashboard Analytics**: Fixed analytics view to use last 30 days as default period.
* **Knowledge Base Unification**: Unified the Tuning Suggestions system into a streamlined "Q\&A" and "Content Gaps" workflow. Renamed the "Text" tab to "Q\&A" with improved terminology (Question/Answer).
* **Content Gaps**: New dashboard card and dedicated tab to identify high-frequency unanswered customer questions for quick Q\&A resolution.
* **Major Integrations**: Added comprehensive support for Stripe and Polar.sh (billing), Klarna (payments) and Zendesk (tickets).
* **Advanced Web Crawler**: Improved crawling logic with incremental updates, better content extraction, and image processing.
* **Custom Tools**: New key management system customizable per website with authentication UI.
* **MCP Servers**: Support for enabling Model Context Protocol servers on a per-website basis.
* **Documentation**: Launched comprehensive documentation for users and developers.
* **Widget & Live Support**: Enhanced real-time chat, dynamic widget sizing.
* **New Integrations**: Full HubSpot (CRM) integrations including contact sync and order search.
* **Shopify Billing & Storefront**: Added subscription management and predictive search via Storefront API.
* **Shopify Automations**: Self-service returns, visitor insights, and granular order permissions.
* **Product Features**: Added product reviews, rating counts, and image carousels.
* **Calendly**: Added inline meeting rescheduling capabilities.
* **Shopify Returns**: Complete management feature for order returns.
* **Analytics**: Enhanced dashboard with geographic distribution and advanced filtering.
* **Authentication**: Launched email/password login and signup.
* **Widget Customization**: Added full control over chat widget colors and layout.
* **Shopify App**: Native integration.
* **Initial Launch**: Released BubblaV with RAG-powered AI Chatbot, standout Widget, and Smart Crawler.
***
**Have questions about a feature?** Check the [User Guide](/user-guide/getting-started) or [contact our support team](https://www.bubblav.com/contact).
# Chatbot Logs
Source: https://docs.bubblav.com/developer-guide/chatbot-logs
Inspect and debug every tool call your chatbot makes — MCP servers, custom webhook tools, and built-in tools.
# Chatbot Logs
When your chatbot answers a visitor, it often calls **tools** behind the scenes — your [MCP servers](/developer-guide/mcp-server), [custom webhook tools](/user-guide/integrations/custom-tools), and built-in tools (forms, scheduling, knowledge lookups). The **Log** page records every one of those calls so you can see exactly what your chatbot did, spot failures, and troubleshoot.
## Open the Log page
1. Go to your **Dashboard** and select a website.
2. In the left sidebar, expand **Chatbot** (under the Chatbot section) and click **Log**.
You can also press **⌘K** (macOS) or **Ctrl K** (Windows) to open the dashboard search and type "Log".
## What each row shows
The list shows one row per tool call:
* **MCP tool name** — the tool that was invoked (for example `search_orders` or `bubblav_search_knowledge`).
* **Status** — **Succeeded** (green) or **Failed** (red).
* **Sent at** — when the call was made, shown in **your browser's timezone** (no manual conversion needed).
Failed rows also show a one-line preview of the error so problems are easy to spot at a glance.
## Filter the list
* **Status** — *All statuses* (default), *Succeeded*, or *Failed*. Filter to **Failed** to jump straight to problems.
* **Date range** — click the calendar button to pick a preset (Today, Yesterday, This Week, This Month, Last Month, Last 3 Months, This Year, Last Year, **All Time**) or select a custom range on the two-month calendar and click **Apply**.
The list paginates 50 calls at a time, newest first.
## Inspect a single call
Click any row to open a detail panel with everything about that call:
* **Tool** — the full tool name.
* **Arguments** — the arguments your chatbot sent to the tool, as JSON. Any field that looks like a secret (tokens, keys, passwords, headers) is **masked as `***`** before it is shown, so logs are safe to share when debugging.
* **Result** — a truncated preview of what the tool returned, plus the response size.
* **Error** — the full error message for failed calls (only shown when the call failed).
* **API Key** — the MCP API key used, if the call came through your MCP server (shown by name and prefix only).
## Debugging workflow
When a tool isn't working for your visitors:
1. Open **Chatbot → Log** and set **Status** to **Failed** (and a date range that covers the issue).
2. Open the most recent failed call.
3. Read the **Error** message — it usually states the root cause (for example, an invalid endpoint URL, an authentication failure, a missing required argument, or the external service returning an error).
4. Check **Arguments** to confirm your chatbot sent what you expected. If an argument is wrong, review the tool's description/schema so the model knows the correct shape.
5. Check **Result** to see what the external system returned, if anything.
Common fixes:
* **401 / 403 / auth errors** → the tool's authentication (bearer token, HMAC secret, API key) is missing or invalid. Re-check the tool configuration.
* **404 / connection errors** → the webhook or MCP endpoint URL is wrong or unreachable.
* **400 / validation errors** → the arguments don't match what the external system expects. Tighten the tool's parameter schema.
* **Timeouts / 5xx** → the external system is slow or down; retry, or check its status.
After changing a tool's configuration, send a test message from the **Test** tab and re-check the Log to confirm the call now succeeds.
## Security & access
* Logs are scoped to **one website only** — you only ever see calls for the website you have open. There is no cross-website access.
* Access follows your website permissions: the **owner** and any **accepted team member** can view logs.
* Secret values inside call arguments are **redacted** before they leave the server.
# In-App Chatbot Integration
Source: https://docs.bubblav.com/developer-guide/in-app-chatbot-integration
Embed the BubblaV chat widget inside your own app and run MCP tools against your MCP server as your logged-in user.
Embed the BubblaV chat widget inside your own application — a SaaS dashboard, customer portal, or internal tool — and let its AI agent execute MCP tools against **your** MCP server **as the currently logged-in user**.
The division of responsibility is deliberate:
* **BubblaV authenticates.** Your backend mints a short-lived signed token per logged-in user. BubblaV verifies it, binds the identity to the conversation server-side, and attaches a freshly-signed per-call token to every outbound MCP tool call.
* **Your server authorizes.** BubblaV never decides what a user may do. Your MCP server receives the verified identity with every tool call and scopes every effect to that user's ID.
This guide is for **your own MCP server** — i.e. an MCP server you operate and connect to BubblaV so the chatbot can call your tools. To instead consume BubblaV's own data and tools from an MCP client, see [MCP Server](/developer-guide/mcp-server).
***
## Use case: a public bot and an internal bot
A common deployment runs **two separate chatbots** from one BubblaV account, each with a different audience:
* **Public website chatbot** — mounted on your marketing site to serve visitors and customers. It answers from your public content, works for anonymous visitors (BubblaV issues a server-side visitor session automatically), and typically needs no tools at all.
* **Internal chatbot** — mounted inside your own app, behind your existing login, to serve employees. It authenticates with [end-user identity](#mint-the-end-user-token), so every conversation is bound to the signed-in employee and answers are personalized to whoever is asking — "my open orders", "my assigned tickets", "my team's data" — instead of generic FAQ answers.
Configure them as **two separate websites** in your dashboard: each website carries its own knowledge base, widget configuration, and bot instructions, so internal knowledge never leaks into the public bot. One widget configuration per page applies — mounting the other bot's website in the same document is rejected with `widget_conflict`; switch between them with a full page navigation (see [Embed the widget](#embed-the-widget)).
The internal bot does more than answer. Give it tools — an identity-enabled [MCP server](#harden-your-mcp-server) (this guide) or an endpoint connected through [Custom Tools](/user-guide/integrations/custom-tools) — and it can **act on behalf of the logged-in employee**: read the records that employee is allowed to see, and create or change data only after the employee approves it in an [approval card](#approval-cards). Your server stays in control: it receives BubblaV's freshly-signed per-call token on every tool call, verifies it, re-resolves the caller's current permissions from `sub` on each call, and scopes every effect to that user — so when an employee loses access in your system, their tool access ends on the next call, not when a token expires.
For example, an order-automation product can ship exactly this pair: a marketing bot on the public site answering pricing and feature questions for anyone, plus an in-dashboard assistant that lists the signed-in operator's own mailboxes and pending orders, previews a change, and then approves an order or invites a teammate after an in-chat confirmation — with every effect scoped to that operator's workspace and an audit trail on writes.
***
## How it works
1. A user signs in to **your** app as usual. Your backend mints a short-lived **end-user identity token** (an HS256 JWT) for that user.
2. The token is handed to the BubblaV widget (script attribute or SDK call).
3. The widget presents the token on protected requests. BubblaV verifies it and authorizes the website-scoped conversation before accessing or persisting its data. Protection covers chat, conversation history/list, detail and mark-read, realtime subscriptions, and direct tool execution.
4. When the agent calls a tool on your MCP server, BubblaV mints a **fresh per-call token** for that invocation and sends it along with pinned identity headers.
5. Your MCP server verifies the per-call token and executes the tool **scoped to that user** — reading and writing only that user's data.
Anonymous visitors can still chat using a server-issued visitor session, bootstrapped through `POST /api/public/widget/session` and carried in `X-BubblaV-Visitor-Token`. A locally stored visitor ID is not proof of ownership. Anonymous conversations stay anonymous: signing in requires a new verified conversation, not promotion of the old one. Verified conversations remain scoped to the same website and subject; dashboard principals have their own server-authenticated scope. Your MCP server decides what, if anything, anonymous callers may do.
This guide describes the implemented repository contract, not a verified deployment. The conversation-authorization migration has been authored but not applied here; a maintainer must review/apply it and verify the deployed web app and widget together before relying on these semantics in production.
***
## Prerequisites
Before you start, you need:
* A BubblaV account with the chat widget installed. Outbound MCP tool calls count against your plan's [MCP call allowance](/developer-guide/mcp-server#rate-limits).
* An MCP server reachable over **HTTPS** (the chatbot calls it over the public internet).
* In your BubblaV dashboard:
1. On your MCP server's configuration, enable **End-user identity**.
2. In your website settings, generate the **website signing secret**. It is shown **once** — copy it immediately and store it in your backend's secret store.
3. Configure identity-enabled MCP with **zero static credentials**: no owner API key, static bearer, or custom credential headers. Enabled mode discards static credentials entirely; only BubblaV's per-call identity credentials are forwarded. Identity-disabled integrations may still use static credentials.
The signing secret is a shared secret between your backend and BubblaV. Store it server-side only — never ship it to the browser, a mobile bundle, or a public repository. If it leaks, rotate it (see [Secret rotation](#secret-rotation)).
***
## Mint the end-user token
For each logged-in user, your backend mints an HS256 JWT signed with your website signing secret. For JavaScript/TypeScript, use the shared npm SDK rather than maintaining token signing and browser lifecycle code yourself:
```bash theme={null}
npm install @bubblav/ai-chatbot-sdk
# Add your framework wrapper, for example:
npm install @bubblav/ai-chatbot-react
```
These examples describe the SDK source contract, not a claim of a published release or a verified deployment.
| Claim | Required | Value |
| ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `iss` | Yes | `bubblav-end-user` (exact) |
| `aud` | Yes | Your BubblaV website ID as an exact string; mint a single audience, not a list |
| `sub` | Yes | A nonempty, stable, opaque user ID (max 128 chars). Prefer a database ID over an email — it must never change for the same user |
| `exp` | Yes | Expiration time (epoch seconds). A 5–15 minute lifetime is recommended (10 minutes in these examples), not an enforced lifetime range |
| `iat` | Yes | Issued-at time (epoch seconds) |
| `nbf` | Recommended | Not-before time (epoch seconds) |
| `jti` | Recommended | A unique token ID |
| `email` | No | Display snapshot only (max 256 chars). Never used for authorization |
| `name` | No | Display snapshot only (max 256 chars). Never used for authorization |
Verification uses a 30-second clock tolerance, so small clock skew between your servers and BubblaV is fine.
Use the **UTF-8 bytes of the displayed hex string** as the HS256 secret; do not hex-decode it. The verifier requires `exp`, `iat`, and `sub`. Its JWT library also accepts an audience array containing the website ID; integrations should mint the exact single-string audience shown here, and the MCP verifier examples below enforce that shape.
```javascript theme={null}
import { createEndUserToken } from '@bubblav/ai-chatbot-sdk/server';
// Server-only: the SDK does not read environment variables automatically.
const identityOptions = {
websiteId: process.env.BUBBLAV_WEBSITE_ID ?? '',
signingSecret: process.env.BUBBLAV_END_USER_SIGNING_SECRET ?? '',
ttlSeconds: 600, // Optional; defaults to 600 seconds.
};
export async function mintEndUserToken(user) {
// user comes from your authenticated backend session, never request input.
return createEndUserToken(
{ userId: user.id, email: user.email, name: user.name },
identityOptions,
);
}
```
```python theme={null}
import os
import time, uuid
import jwt # PyJWT
def mint_end_user_token(user):
now = int(time.time())
payload = {
"iss": "bubblav-end-user",
"aud": os.environ["BUBBLAV_WEBSITE_ID"],
"sub": user["id"], # opaque, stable, ≤128 chars
"iat": now,
"nbf": now,
"exp": now + 10 * 60, # 10 minutes
"jti": str(uuid.uuid4()),
"email": user.get("email"), # optional snapshot
"name": user.get("name"), # optional snapshot
}
return jwt.encode(payload, os.environ["BUBBLAV_END_USER_SIGNING_SECRET"], algorithm="HS256")
```
Mint tokens on your backend only. Your signing secret in the browser would let any visitor mint tokens as any user.
***
## Embed the widget
Pass the token when the widget loads, or supply it (and refresh it) through the SDK.
### Option 1: Token at load time
```html theme={null}
```
### Option 2: Identify after load
```javascript theme={null}
BubblaV.identify(currentEndUserToken);
```
### Managed on-demand refresh (recommended)
```ts theme={null}
import { mountBubblaVWidget } from '@bubblav/ai-chatbot-sdk';
export function mountChat(websiteId: string, initialToken: string) {
const options = {
websiteId,
identity: { token: initialToken, tokenEndpoint: '/api/bubblav/identity-token' },
onError: (error: { code: string }) => console.error('Widget error', error.code),
};
const connection = mountBubblaVWidget(options);
void connection.ready.catch(error => console.error('Widget readiness failed', error.code));
return {
logout() { connection.update({ ...options, identity: { token: null } }); },
dispose() { connection.dispose(); },
};
}
```
Mount only in a browser lifecycle and call `dispose()` on unmount. A same-configuration remount reuses the script; it does not create a second widget. A concurrent owner or different website/source in the same document reports `widget_conflict`. Use full document navigation when changing website configuration; removing the script cannot reset the loader.
Omitting `identity` means unmanaged identity. Explicit `{ token: null }` means logout: abort pending refresh, clear the token, and stop refreshing until a non-null token is supplied. Empty tokens are errors. The SDK deduplicates simultaneous refresh requests and discards late responses after logout, token/refresh-source change, timeout, or disposal. An unchanged initial token prop does not overwrite a token already refreshed by the SDK.
`tokenEndpoint` performs a same-origin, no-store GET with a lifecycle `AbortSignal` and requires an OK JSON response with a nonempty string `token`. For POST, custom headers, or another credential policy, replace `tokenEndpoint` with `getToken: async ({ signal }) => token`; never supply both. The SDK awaits the provider and calls `identify` itself. Keep the provider stable unless its behavior changes. Unlike this provider, global `onIdentityNeeded` and `on('identityNeeded', callback)` listeners **ignore return values**: a low-level listener must deliver the token via `BubblaV.identify(token)`. Do not register a second low-level refresh listener alongside SDK-managed identity.
A minimal authenticated host endpoint (adapt the app-specific authentication helper):
```ts theme={null}
// app/api/bubblav/identity-token/route.ts
import { createEndUserToken } from '@bubblav/ai-chatbot-sdk/server';
import { getAuthenticatedUser } from '@/lib/auth';
const identityOptions = {
websiteId: process.env.BUBBLAV_WEBSITE_ID ?? '',
signingSecret: process.env.BUBBLAV_END_USER_SIGNING_SECRET ?? '',
};
export async function GET() {
const headers = { 'Cache-Control': 'no-store' };
const user = await getAuthenticatedUser();
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401, headers });
const token = await createEndUserToken(
{ userId: user.id, email: user.email },
identityOptions,
);
return Response.json({ token }, { headers });
}
```
### Token expiry behavior
The widget handles short token lifetimes for you:
* **Proactive refresh:** before any protected request — sends, history/detail/list/mark-read fetches, and session bootstrap — if the token expires within 60 seconds, the widget requests a fresh token from the host or configured refresh endpoint. An approved tool continuation also refreshes before continuing the same approval decision.
* **Expired-identity recovery:** every protected route signals an expired token with `X-BubblaV-Identity-State: expired`; JSON routes also return `401 {"error":"identity_expired"}`. On that signal the widget refreshes once and retries the identical request once. `/api/chat` additionally short-circuits an expired token before quota, message logging, or tool dispatch with an empty 200 SSE response carrying the same header — that short-circuit remains chat-only, and there is still no retry for direct tool execution or an already-dispatched write.
* **Refresh failure:** an unsuccessful response, a successful response missing a nonempty `token`, or no host delivery via `identify(token)` within 5 seconds shows a dismissible "session expired" notice and does **not** resend or refetch. Transient failures are not logout and must not silently downgrade an identity-bound conversation to anonymous.
* **Logout:** with the npm SDK, update to `identity: { token: null }` or dispose the managed connection. Low-level integrations must unregister refresh, abort pending work, and call `BubblaV.identify(null)` explicitly. This clears the token and prepared Authorization header. Do not carry the previous user's conversation or pending approval into a new login.
A conversation's identity state is immutable. Verified arrival on an anonymous conversation returns `409 anonymous_locked`; a different principal on a bound conversation returns `403 identity_mismatch`. Unknown or wrong-website conversations return `404`, missing/invalid proof returns `401`, and authorization storage failures return `503`. These checks fail closed, not anonymous-success. Start a new conversation when signing in from anonymous mode or switching users.
***
## Harden your MCP server
BubblaV sends a **freshly-signed per-call JWT** with every MCP tool call. Verify it on every request and scope every effect to its `sub`.
### Per-call token claims
| Claim | Value |
| --------------------- | ----------------------------------------------------------------------------- |
| `iss` | `bubblav` (exact) |
| `aud` | Your BubblaV website ID — exact string |
| `sub` | The chatting user's nonempty ID (max 128 chars; same value your tokens carry) |
| `website_id` | Your BubblaV website ID (custom claim) |
| `exp` | 5 minutes after signing; reusable within this validity window |
| `iat` / `nbf` / `jti` | Issued-at, not-before, unique token ID |
The token is minted fresh for every invocation with the **current** signing secret. Requiring `iss: bubblav` separates per-call tokens from host identity tokens (`iss: bubblav-end-user`), but issuer separation is **not replay prevention**. A per-call token is reusable within its 5-minute validity; `jti` alone is not a consumed-once receipt. Enforce your own authorization and any write idempotency/replay controls on your server.
### Pinned headers
Alongside the JWT, BubblaV sends these headers. They are pinned by BubblaV's server and cannot be overridden by tool arguments or the model:
| Header | Value |
| ---------------------- | ----------------------------------------------- |
| `X-BubblaV-User-Id` | The verified `sub` (absent for anonymous calls) |
| `X-BubblaV-Website-Id` | Your BubblaV website ID |
| `X-BubblaV-Auth-State` | `verified` or `anonymous` |
### Verification rules
1. **Verify the per-call JWT on every request**: HS256 signature, `iss` = `bubblav`, exact-string `aud` = your website ID, required unexpired `exp`, and required nonempty string `sub` of at most 128 characters. Honor `nbf` when present.
2. **Trust `X-BubblaV-*` headers only alongside a valid JWT.** On their own they are unauthenticated data and must be ignored.
3. **Treat anonymous as unauthenticated.** Only a genuinely absent Authorization header may enter your anonymous-discovery policy. A present empty, malformed, or invalid credential must fail rather than become anonymous. `X-BubblaV-Auth-State` alone never proves identity. Explicitly reject missing identity for protected tools, including `tools/call` inside batches.
4. **Scope every effect to `sub`.** Every read and write must be filtered by the verified user ID — database queries, file access, downstream API calls, everything.
5. **Never trust tool arguments for identity.** A user ID arriving in a tool argument is attacker-controlled input. Only the JWT `sub` (and, once verified, the matching `X-BubblaV-User-Id`) identifies the caller.
```javascript theme={null}
import { BubblaVTokenError, verifyMcpRequest, verifyMcpToken } from '@bubblav/ai-chatbot-sdk/server';
const verificationOptions = {
websiteId: process.env.BUBBLAV_WEBSITE_ID ?? '',
signingSecret: process.env.BUBBLAV_END_USER_SIGNING_SECRET ?? '',
previousSigningSecret: process.env.BUBBLAV_PREVIOUS_SIGNING_SECRET || undefined,
};
export async function requireBubblaVIdentity(req) {
// null only for absent Authorization. Malformed or invalid credentials throw.
const identity = await verifyMcpRequest(req.headers, verificationOptions);
if (!identity) throw new BubblaVTokenError('Authentication required');
return identity; // { sub, websiteId, email? }; resolve current permissions from sub.
}
// A transport that already supplies a raw JWT can verify without header checks:
export async function verifyRawPerCallToken(token) {
return verifyMcpToken(token, verificationOptions);
}
```
```python theme={null}
import os
import jwt # PyJWT
SECRETS = [value for value in (
os.environ.get("BUBBLAV_END_USER_SIGNING_SECRET"),
os.environ.get("BUBBLAV_PREVIOUS_SIGNING_SECRET"),
) if value]
def require_bubblav_identity(authorization_header):
if authorization_header is None:
return None # Only a genuinely absent header is anonymous.
parts = authorization_header.split()
if len(parts) != 2 or parts[0].lower() != "bearer":
raise ValueError("Invalid Authorization credential")
for secret in SECRETS:
try:
payload = jwt.decode(
parts[1], secret, algorithms=["HS256"],
issuer="bubblav",
audience=os.environ["BUBBLAV_WEBSITE_ID"],
options={"require": ["exp", "sub"], "strict_aud": True},
)
sub = payload.get("sub")
if not isinstance(sub, str) or not sub.strip() or len(sub) > 128:
raise ValueError("Invalid subject")
return payload # scope every effect to sub
except jwt.PyJWTError:
continue
raise ValueError("Invalid per-call token")
```
The JS helpers require nonempty website/secret configuration and accept only HS256, `iss: bubblav`, an exact-string audience, required unexpired `exp`, and a nonempty `sub` of at most 128 characters. They validate finite time claims and matching `website_id` when present. `nbf` has 30 seconds of tolerance, but expiry is strict: `now >= exp` fails. Only the explicit current and optional previous secret are tried, using UTF-8 bytes. `verifyMcpRequest` additionally checks nonempty user/website identity headers against the verified claims. Configuration and credential failures throw `BubblaVTokenError`; missing identity never overrides an invalid configuration.
For discovery, call `verifyMcpRequest` and explicitly allow `null` only on the methods you choose to expose anonymously. For every protected tool handler, use a required-identity check like the Node example and scope all queries/writes to the returned `sub` after resolving current permissions. Map credential failures to your transport's authentication response. These helpers do not implement discovery policy, authorization, MCP transport, audit storage, replay prevention, or approval. A valid credential does not prove a human approved a write.
### Write-preview pattern for destructive tools
For tools that create or change data, add a top-level `confirmed` boolean to the tool's argument schema. BubblaV's executor strips caller-supplied values and injects `confirmed: true` for the approved branch of its approval flow (see [Approval cards](#approval-cards)). Until then, your tool can return a preview that changes nothing. This is an executor-managed **consent UX convention**, not cryptographic proof that a human approved the exact arguments; your server must still authorize the write.
***
## Approval cards
How BubblaV asks the chatting user before your tool runs is driven by the annotations your tool declares in its MCP schema:
* **`readOnlyHint: true`** — the tool only reads data. It runs without an approval card.
* **`destructiveHint: true`** (or the tool otherwise writes data) — the user sees an approval card showing the tool name and arguments. The tool runs only after the user approves; denying it never reaches your server.
The top-level `confirmed` argument distinguishes the executor's approved path from a preview. Neither that boolean nor the per-call identity JWT is an independently verifiable human-consent receipt. For stronger guarantees, implement a server-issued, single-use preview/confirmation token bound to the exact intended change; that is additional hardening, not part of the current contract. After identity refresh, an approval continuation resumes the same decision rather than creating a second write.
Annotate your tools accurately. Marking a write tool `readOnlyHint: true` makes it run without user approval — BubblaV trusts these hints for the approval flow.
### Timeout and cancellation
MCP execution has a 30-second timeout and receives the incoming request's cancellation signal on every execution path. Timeout or cancellation does **not** prove rollback: the operation may already have completed. Check its status before retrying and **never automatically repeat a dispatched write**. Chat's pre-dispatch expired-token recovery above is a separate, bounded flow.
Identity-enabled MCP clients are isolated by `server.id::url::websiteId::sha256(sub).slice(0,16)`, including website separation for the same subject. Cache eviction is FIFO with a 5-minute creation TTL, not LRU or a token replay ledger.
***
## Secret rotation
Coordinate **both directions**: your backend signs identity tokens that BubblaV verifies, while BubblaV signs per-call tokens that your MCP server verifies. The verifier examples above try the current key first and the optional previous key second.
1. Rotate in the BubblaV dashboard. Copy the new secret shown once; BubblaV retains the previous verification secret for **24 hours** and signs outbound per-call tokens with the current (new) secret.
2. Update `BUBBLAV_END_USER_SIGNING_SECRET` to the new value and move the old value to `BUBBLAV_PREVIOUS_SIGNING_SECRET`. Redeploy your mint endpoint and MCP verifier together. During overlap, BubblaV accepts inbound identity tokens signed with either key; your server accepts new-key per-call tokens first and previous-key tokens as a fallback.
3. After the 24-hour grace window, remove `BUBBLAV_PREVIOUS_SIGNING_SECRET` and redeploy. Verify that only current-key tokens work in both directions.
There is no unconditional zero-downtime guarantee: the period between dashboard rotation and your redeployment can reject new-key outbound tokens. BubblaV invalidates only the rotating process's secret cache; other processes refresh their 60-second cache independently. Coordinate rollout and verify both directions rather than assuming an instantaneous global switch.
After grace, a previous-key token is no longer accepted under that key. An otherwise unexpired token normally fails signature verification; it is not automatically classified as expired and does not downgrade a protected conversation to anonymous. Environment-based previous-key fallback has no automatic grace timer: removing the previous environment value is your responsibility.
***
## Test checklist
* [ ] A logged-in user chats, and tool calls arrive at your MCP server with a valid per-call JWT (`iss: bubblav`, correct `aud`, unexpired) and `X-BubblaV-Auth-State: verified`.
* [ ] Effects are scoped to `sub`: user A can never read or change user B's data, even by asking the bot directly.
* [ ] An anonymous visitor can chat; calls arrive with `X-BubblaV-Auth-State: anonymous`, no `X-BubblaV-User-Id`, and your server rejects or limits them as intended.
* [ ] A request with tampered `X-BubblaV-*` headers but no valid JWT is treated as unauthenticated.
* [ ] A user ID inside a tool argument is ignored — identity comes only from the verified token.
* [ ] A destructive tool triggers an approval card in the widget; denying it results in no call to your server; approving it arrives with `confirmed: true`.
* [ ] Let a token expire mid-session: the widget refreshes it proactively (or retries once reactively) and the user keeps their identity.
* [ ] Rotate and verify both directions during overlap: old/new inbound identity tokens and new/previous outbound per-call tokens. After grace and removal/redeployment, old-key tokens fail.
* [ ] Verify transport isolation across chat, history/list, detail, mark-read, realtime, and direct execute. Missing proof is denied; caller-chosen IDs do not grant access; storage failures are `503` rather than empty-success history.
* [ ] Anonymous-to-login requires a new conversation (`409 anonymous_locked` on the old one); account switching cannot access the previous user's conversation. Logout clears identity, unregisters refresh, and detaches old subscriptions; remount registers once and ignores late old-user responses.
* [ ] No callback, transient endpoint failure, and an OK response missing `token` all show the session-expired notice without resend after the 5-second host wait.
* [ ] Let an approval card outlive the identity token: refresh succeeds and resumes the same decision, without duplicate writes.
* [ ] Configure no static credentials for identity-enabled MCP; anonymous discovery sends no owner bearer. The same `sub` on two websites cannot share an identity-client cache entry.
* [ ] A timed-out or cancelled write is treated as outcome-unknown; inspect status and do not automatically retry it.
## Troubleshooting
| Symptom | Likely cause | Fix |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Chat works but tools run as anonymous | The request has no verified identity, or the MCP integration is not identity-enabled | Supply an initial token and register refresh; check website/secret configuration rather than assuming expired credentials downgrade to anonymous |
| Your server rejects per-call tokens with a signature error | Wrong current key, missing overlap key, or old key retained past the planned grace period | Deploy coordinated current/previous keys in both directions and remove the previous key after grace |
| Every tool call acts as the same user | Your server trusts `X-BubblaV-User-Id` without verifying the JWT, or ignores `sub` | Verify the JWT first, then scope all effects to `sub` |
| `403 identity_mismatch` on chat | The conversation is bound to a different user ID | Start a new conversation; never reuse conversations across users |
| Widget shows "session expired" notice | Refresh failed or did not provide a nonempty token within 5 seconds | Check endpoint auth and response shape. The SDK awaits `getToken`; global event callback return values are ignored. Retry only the unsent message after refresh succeeds |
| Approval card never appears for a write tool | Tool annotated `readOnlyHint: true` | Correct the tool's annotations in your MCP server |
| Identity never verifies at all | End-user identity not enabled on the MCP server, or no signing secret generated | Enable it in the dashboard and generate the website signing secret |
| `409 anonymous_locked` after login | The conversation was created anonymously | Start a new verified conversation; anonymous history is not promoted |
| `401` on history/realtime or `503 authorization_unavailable` | Missing/invalid proof, expired identity, or unavailable authorization storage | Restore valid session/identity proof or service availability; do not fall back to caller-selected visitor IDs |
| Old-user history or duplicate refresh requests after remount | Host lifecycle was not torn down or old requests delivered late | Unsubscribe, abort pending refresh, call `identify(null)`, and start the next login in its own conversation |
| Schema discovery fails with identity enabled | A deployment still uses owner/static credentials or the server rejects anonymous discovery | Remove static credentials and verify the enabled adapter is deployed; allow unauthenticated discovery only if appropriate, never protected tool calls |
| Write reports timeout/cancellation | Dispatch may have completed remotely | Check current state before any user-directed retry; never automatically repeat the write |
***
## Next Steps
Connect MCP clients to BubblaV's own MCP server
Full widget SDK methods and events
# MCP Server
Source: https://docs.bubblav.com/developer-guide/mcp-server
Connect your BubblaV data to MCP-compatible clients like ChatGPT, Claude Desktop, and OpenClaw.
# BubblaV MCP Server
The BubblaV MCP (Model Context Protocol) Server enables you to connect your BubblaV data to MCP-compatible clients like **ChatGPT**, **Claude Desktop**, **Google Antigravity**, and **OpenClaw**. This allows your AI agents to search your knowledge base, access analytics, and manage your chatbot's settings — all in real-time.
> **Looking for recipes?** For ready-to-use prompts to diagnose content gaps, add knowledge, tune your bot's persona, or set up human handoff, see [Use AI Agents to Manage & Improve Your Chatbot](/user-guide/ai-agent-workflows).
## What Can You Do?
* **Search Knowledge Base**: Let your AI agents search your indexed website content
* **Manage Knowledge Base**: Add, delete, and list knowledge entries; upload files; sync support tickets; manage crawl URLs and sitemaps
* **Access Analytics**: Retrieve full analytics reports programmatically
* **Conversation Intelligence**: List, search, and inspect conversations and leads
* **Content Gap Analysis**: Identify unanswered questions and knowledge gaps
* **Visitor Insights**: Get detailed visitor profiles and activity breakdowns
* **Hourly Activity**: Analyze peak support times for staffing optimization
* **Scrape Web Pages**: Convert any public URL into markdown with `bubblav_scrape_url`
* **Configure the Chatbot**: Read and update the chatbot persona (`custom_instructions`) and website settings
* **Design the Widget**: Edit bot name, greetings, suggestions, colors, and position
* **Human Handoff**: Build intent-triggered flows that route visitors to a live agent (Pro+)
* **Manage Custom Tools**: Create, update, delete, and toggle custom webhook tools for your chatbot (Pro+)
* **Manage Forms**: Create and update AI-powered lead-collection forms
* **Manage Flows**: Create, update, and inspect visual multi-step chatbot scenarios (Pro+)
* **Manage API Keys**: Create, list, and revoke scoped MCP API keys
* **Build Automations**: Create custom workflows that leverage your BubblaV data
* **Real-time Integration**: Use Server-Sent Events (SSE) for instant data access
## Available Tools
> This is a **curated reference** of the most-used tools. A connected client receives the complete,
> always-current set via the standard `tools/list` method.
### bubblav\_search\_knowledge
Search your indexed knowledge base for relevant content.
**Parameters:**
* `query` (string, required): Your search query
* `limit` (number, optional): Maximum results to return (default: 5, max: 20)
**Returns:**
```json theme={null}
{
"results": [
{
"content": "The content snippet...",
"source": "https://example.com/page",
"title": "Page Title",
"relevance": 0.95
}
],
"total": 42
}
```
**Example:**
```json theme={null}
{
"query": "shipping policy",
"limit": 10
}
```
### bubblav\_read\_report
Read the full analytics report for your website — the same data shown on the Reports page.
**Parameters:**
* `date_range` (object, optional): Date range for the report (defaults to current calendar month)
* `start` (string): Start date in `yyyy-MM-dd` format
* `end` (string): End date in `yyyy-MM-dd` format
**Returns:**
```json theme={null}
{
"totalConversations": 1234,
"totalMessages": 4567,
"containmentRate": 0.69,
"agentTransferRate": 0.31,
"avgResponseTime": 12.5,
"avgConversationDepth": 4.2,
"messageRating": 4.1,
"avgConfidenceScore": 0.85,
"estimatedCostSavings": 1234.56,
"totalLeads": 42,
"topCountries": ["US", "GB", "DE"],
"mostVisitedLinks": ["https://example.com/pricing"],
"previousPeriodComparison": { ... }
}
```
**Example:**
```json theme={null}
{
"date_range": {
"start": "2026-03-01",
"end": "2026-03-18"
}
}
```
### bubblav\_add\_knowledge
Add a new text knowledge entry to your knowledge base. The content is automatically split into chunks, queued for embedding, and becomes searchable via `bubblav_search_knowledge` once processed.
**Parameters:**
* `title` (string, required): Title for this knowledge entry
* `content` (string, required): Full text content to index (plain text or Markdown)
**Returns:**
```json theme={null}
{
"id": "uuid-of-new-entry",
"title": "Knowledge Entry Title",
"chunks_created": 5,
"embedding_triggered": true
}
```
**Example:**
```json theme={null}
{
"title": "Shipping Policy",
"content": "We ship worldwide. Standard delivery takes 5-7 business days. Express shipping is available for orders over $100."
}
```
**Note:** Subject to plan page limits. If your plan limit is reached, you'll receive a `RATE_LIMITED` error.
### bubblav\_scrape\_url
Scrape a public web page URL and return markdown content optimized for LLM context.
**Parameters:**
* `url` (string, required): The page URL to scrape
**Returns:**
```json theme={null}
{
"url": "https://example.com/final-url",
"markdown": "# Markdown content..."
}
```
**Example:**
```json theme={null}
{
"url": "https://example.com"
}
```
### bubblav\_list\_conversations
List conversations for this website with optional filters. Returns conversation metadata (id, title, state, platform, visitor email/country, rating).
**Parameters:**
* `status` (string, optional): Filter by conversation state — `"bot"`, `"live_support"`, or `"resolved"`
* `platform` (string, optional): Filter by platform (e.g. `"widget"`, `"messenger"`, `"slack"`, `"discord"`, `"whatsapp"`, `"instagram"`)
* `date_range` (object, optional): Date range with `start` and `end` in `yyyy-MM-dd` format
* `limit` (number, optional): Maximum results (default: 20, max: 100)
* `offset` (number, optional): Results to skip for pagination (default: 0)
**Example:**
```json theme={null}
{
"status": "bot",
"date_range": { "start": "2026-03-01", "end": "2026-03-31" },
"limit": 10
}
```
### bubblav\_get\_conversation
Get the full details of a single conversation including all messages. Returns conversation metadata plus a chronological list of messages with sender type, content, confidence score, thumbs rating, and response latency.
**Parameters:**
* `conversation_id` (string, required): UUID of the conversation to retrieve
**Example:**
```json theme={null}
{
"conversation_id": "01234567-89ab-cdef-0123-456789abcdef"
}
```
### bubblav\_search\_conversations
Full-text search across all conversation messages. Returns matching message excerpts with surrounding context, conversation metadata, and visitor email if available.
**Parameters:**
* `query` (string, required): Text to search for in message content (case-insensitive)
* `date_range` (object, optional): Date range with `start` and `end`
* `limit` (number, optional): Maximum results (default: 20, max: 100)
* `offset` (number, optional): Pagination offset (default: 0)
**Example:**
```json theme={null}
{
"query": "billing error",
"limit": 10
}
```
### bubblav\_list\_leads
List conversations where the visitor provided their email address (captured leads). Returns email, country, platform, conversation state, and timestamp.
**Parameters:**
* `platform` (string, optional): Filter by platform
* `date_range` (object, optional): Date range
* `limit` (number, optional): Maximum results (default: 20, max: 100)
* `offset` (number, optional): Pagination offset (default: 0)
**Example:**
```json theme={null}
{
"date_range": { "start": "2026-03-01", "end": "2026-03-31" }
}
```
### bubblav\_list\_unanswered\_questions
Find visitor questions that the AI could not answer well — bot replies with low confidence score, fallback responses, or messages rated thumbs-down by the visitor.
**Parameters:**
* `confidence_threshold` (number, optional): Confidence score cutoff (0.0–1.0, default: 0.5). Replies below this are considered low-quality
* `date_range` (object, optional): Date range
* `limit` (number, optional): Maximum results (default: 20, max: 100)
* `offset` (number, optional): Pagination offset (default: 0)
**Example:**
```json theme={null}
{
"confidence_threshold": 0.3,
"limit": 20
}
```
### bubblav\_get\_most\_asked\_questions
Return the most frequently asked visitor questions over a date range (default: last 30 days). Questions are aggregated and deduplicated.
**Parameters:**
* `date_range` (object, optional): Date range
* `limit` (number, optional): Maximum questions (default: 10, max: 50)
**Example:**
```json theme={null}
{
"limit": 20
}
```
### bubblav\_get\_content\_gaps
Return visitor questions that the AI struggled to answer — bot replies with low confidence score or a thumbs-down rating. Use this to prioritise knowledge base improvements.
**Parameters:**
* `date_range` (object, optional): Date range
* `limit` (number, optional): Maximum questions (default: 10, max: 50)
**Example:**
```json theme={null}
{
"limit": 15
}
```
### bubblav\_get\_answerable\_questions
Return AI-generated questions that the chatbot can confidently answer from its knowledge base. Questions are generated and cached automatically when knowledge is indexed.
**Parameters:**
* `limit` (number, optional): Maximum questions (default: 30, max: 50)
**Example:**
```json theme={null}
{
"limit": 30
}
```
### bubblav\_delete\_knowledge
Delete a text knowledge entry from the knowledge base. Removes the entry and all associated chunks/embeddings. Requires the knowledge entry ID (from `bubblav_list_knowledge_sources`).
**Parameters:**
* `knowledge_id` (string, required): UUID of the text knowledge entry to delete
**Example:**
```json theme={null}
{
"knowledge_id": "01234567-89ab-cdef-0123-456789abcdef"
}
```
### bubblav\_sync\_ticket\_to\_knowledge
Sync a resolved support ticket to the knowledge base. Formats the ticket conversation as a searchable article, splits into chunks, and queues for embedding. Requires Pro plan or higher.
**Parameters:**
* `ticket_id` (string, required): UUID of the live support ticket to sync
**Example:**
```json theme={null}
{
"ticket_id": "01234567-89ab-cdef-0123-456789abcdef"
}
```
### bubblav\_list\_knowledge\_sources
List all knowledge sources for this website. Returns sources from: text entries, Notion pages, Google Docs, Zendesk articles/tickets, and crawled website pages.
**Parameters:** None
**Example:**
```json theme={null}
{}
```
### bubblav\_get\_visitor\_insights
Get insights for a specific visitor including profile data, conversation count, active support tickets, e-commerce orders (Shopify), and subscription status.
**Parameters:**
* `visitor_id` (string, required): Visitor ID (from conversation data or live support session)
**Example:**
```json theme={null}
{
"visitor_id": "visitor_abc123"
}
```
### bubblav\_get\_hourly\_activity
Get hourly activity breakdown showing conversation and support ticket counts per hour (UTC). Returns 24 data points (one per hour), total counts, and peak hour. Defaults to today.
**Parameters:**
* `date_range` (object, optional): Date range
**Example:**
```json theme={null}
{
"date_range": { "start": "2026-04-05" }
}
```
### bubblav\_list\_tool\_logs
Read the audit log of tool calls made for this website — built-in tools and custom webhook tools — to troubleshoot failures. Each entry includes the tool name, succeeded/failed outcome, error message, a truncated result preview, result size, and the request args (with secrets masked). Returns the most recent calls first.
**Parameters:**
* `limit` (number, required): Maximum number of logs to return (max 200)
* `status` (string, optional): Filter by outcome — `succeeded` or `failed`. Omit to return both.
* `date_range` (object, optional): Date range (defaults to the last 7 days)
* `start` (string): Start date in `yyyy-MM-dd` format
* `end` (string): End date in `yyyy-MM-dd` format
* `offset` (number, optional): Number of logs to skip for pagination (default: 0)
**Returns:**
```json theme={null}
{
"logs": [
{
"id": "uuid",
"tool_name": "find_tournaments",
"success": false,
"error_message": "Request timed out after 5000ms",
"created_at": "2026-08-14T12:34:56.000Z",
"result_bytes": 0,
"result_preview": null,
"args": { "city": "Austin" }
}
],
"total": 1,
"limit": 10,
"offset": 0,
"has_more": false
}
```
**Note:** Especially useful for debugging custom webhook tools — ask your AI assistant to pull the failed calls and read the error messages directly. This tool is **not available in the ChatGPT integration**; it works in Claude, Cursor, OpenClaw, and the dashboard.
**Example:**
```json theme={null}
{
"limit": 10,
"status": "failed"
}
```
## Custom Tool Management
These tools let AI agents create and manage custom webhook tools for your chatbot. For example, you can ask Claude to add a tool that searches for products, looks up inventory, or finds nearby events.
Custom tools require a **Pro plan or higher**.
### bubblav\_list\_custom\_tools
List all custom webhook tools for this website with their activation status.
**Parameters:** None
**Returns:**
```json theme={null}
{
"tools": [
{
"id": "uuid",
"tool_name": "find_tournaments",
"display_name": "Find Tournaments",
"description_for_ai": "Search for tournaments near a city...",
"endpoint_url": "https://api.example.com/tournaments/search",
"authentication_type": "bearer",
"http_method": "POST",
"argument_schema": {
"city": { "type": "string", "description": "City name to search near", "required": true, "method": "query" }
},
"is_active": true,
"is_active_for_website": true,
"has_secret": true,
"created_at": "2026-04-01T00:00:00Z",
"updated_at": "2026-04-01T00:00:00Z"
}
],
"total": 1
}
```
**Example:**
```json theme={null}
{}
```
### bubblav\_create\_custom\_tool
Create a new custom webhook tool. The tool is activated for the current website by default.
**Parameters:**
* `tool_name` (string, required): Unique identifier (letters, numbers, underscores, hyphens)
* `display_name` (string, required): Human-readable name shown in dashboard
* `description_for_ai` (string, required): Instructions for the AI on when and how to use this tool
* `description` (string, optional): Short human-readable description shown in dashboard. Auto-generated from `description_for_ai` if omitted.
* `endpoint_url` (string, required): Webhook URL the chatbot will call (HTTPS required)
* `authentication_type` (string, required): `none`, `bearer`, or `hmac`
* `argument_schema` (object, optional): Flat parameter map defining the parameters the tool accepts. Each top-level key must be the real parameter name, and each value may include `type`, `description`, `required`, `default`, and `method` (`query`, `body`, or `path`). Do not wrap it in JSON Schema keys like `type`, `properties`, and `required`.
* `http_method` (string, optional): `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` (default: GET)
* `activate_for_website` (boolean, optional): Auto-activate for current website (default: true)
**Returns:**
```json theme={null}
{
"id": "uuid-of-new-tool",
"tool_name": "find_tournaments",
"display_name": "Find Tournaments",
"secret_key": "abc123...xyz",
"is_active_for_website": true
}
```
**Note:** The `secret_key` is only shown once at creation time. Save it immediately.
**Example:**
```json theme={null}
{
"tool_name": "find_tournaments",
"display_name": "Find Tournaments",
"description_for_ai": "Search for pickleball tournaments near a given city. Use when a visitor asks about upcoming tournaments in their area.",
"description": "Searches pickleball tournaments by city and radius",
"endpoint_url": "https://api.example.com/tournaments/search",
"authentication_type": "bearer",
"http_method": "POST",
"argument_schema": {
"city": { "type": "string", "description": "City name to search near", "required": true, "method": "query" },
"radius_miles": { "type": "number", "description": "Search radius in miles (default: 50)", "default": 50, "method": "query" }
}
}
```
### bubblav\_update\_custom\_tool
Update an existing custom webhook tool. Only the fields you provide will be changed.
**Parameters:**
* `tool_id` (string, required): UUID of the tool to update (from `bubblav_list_custom_tools`)
* `display_name` (string, optional): New human-readable name
* `description_for_ai` (string, optional): New AI instructions
* `description` (string, optional): New human-readable description
* `endpoint_url` (string, optional): New webhook URL
* `authentication_type` (string, optional): `none`, `bearer`, or `hmac`
* `argument_schema` (object, optional): New parameter schema
* `http_method` (string, optional): New HTTP method
* `is_active` (boolean, optional): Enable or disable the tool globally
**Example:**
```json theme={null}
{
"tool_id": "01234567-89ab-cdef-0123-456789abcdef",
"description_for_ai": "Updated: Search for tournaments near a city or zip code.",
"endpoint_url": "https://api.example.com/v2/tournaments/search"
}
```
### bubblav\_delete\_custom\_tool
Permanently delete a custom webhook tool. This removes the tool and deactivates it from all websites. **Cannot be undone.**
**Parameters:**
* `tool_id` (string, required): UUID of the tool to delete
**Example:**
```json theme={null}
{
"tool_id": "01234567-89ab-cdef-0123-456789abcdef"
}
```
### bubblav\_toggle\_custom\_tool
Enable or disable a custom tool for this specific website. Tools must be activated per-website before the chatbot can use them.
**Parameters:**
* `tool_id` (string, required): UUID of the tool to toggle
* `enabled` (boolean, required): `true` to enable, `false` to disable
**Example:**
```json theme={null}
{
"tool_id": "01234567-89ab-cdef-0123-456789abcdef",
"enabled": true
}
```
### Custom Tool Authentication
When creating a tool, choose an `authentication_type` based on your endpoint's security:
| Type | Use Case | Headers Sent |
| -------- | ------------------------------- | ----------------------------------------------------------------- |
| `none` | Public APIs, testing | None |
| `bearer` | APIs with token auth | `Authorization: Bearer ` |
| `hmac` | Production APIs, sensitive data | `X-BubblaV-Signature: sha256=` + `X-BubblaV-Timestamp: ` |
**Key details:**
* A `secret_key` is auto-generated for `bearer` and `hmac` types and returned **only once** at creation time.
* For HMAC, the signature is computed as `HMAC-SHA256(secret, ".")`.
* Your backend must validate the secret/key on every incoming request.
For detailed validation code examples (Node.js, Python), see [Custom Tools → Authentication Methods](/user-guide/integrations/custom-tools#authentication-methods).
## Website & Chatbot Configuration
These tools let an AI agent read and change how your chatbot behaves and looks — the same controls as
the dashboard's **Settings** and **Design** pages, plus knowledge sources, forms, and API keys. They
are what make [agent-driven chatbot management](/user-guide/ai-agent-workflows) possible.
### Chatbot persona & website settings
| Tool | Description | Key parameters |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `bubblav_get_website_settings` | Read name, URL, status, crawl discovery mode, allowed domains, and `custom_instructions` (the chatbot persona / system prompt). | none |
| `bubblav_update_website_settings` | Update website settings. Set `custom_instructions` to change the chatbot persona (max 2,000 chars). | `custom_instructions`, `website_name`, `discovery_mode` (`auto` / `manual-only` / `sitemap-only`), `allowed_domains`, `allow_all_domains` |
### Widget appearance (Design page)
| Tool | Description | Key parameters |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bubblav_get_widget_appearance` | Read bot name, greetings, suggestions, colors, position, product card button labels, branding toggle, and logo/avatar URLs. | none |
| `bubblav_update_widget_appearance` | Update widget appearance; only the fields you provide change. | `bot_name`, `greeting_message`, `welcome_message`, `home_screen_title`, `textbox_placeholder`, `chat_suggestions`, `bubble_color`, `primary_color`, `desktop_position`, `mobile_position`, `product_card_view_label`, `product_card_view_detail_label`, `powered_by_visible`, `home_logo_url`, `bot_avatar_url` |
> Hiding the "Powered by" branding (`powered_by_visible: false`) requires a paid plan.
### Human handoff (Pro+)
Handoffs are flows: a `visitor_intent` trigger describing when to escalate (e.g. "wants to
speak to sales"), followed by a `request_human` node that opens a live-support ticket.
Build them with the flow tools below — see [Human Handoff](/user-guide/human-handoff).
### Knowledge files & crawl sources
| Tool | Description | Key parameters |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `bubblav_upload_knowledge_file` | Upload a file (PDF/DOCX/DOC/TXT/Markdown, ≤10MB) to extract and index. Processing is asynchronous — track with `bubblav_get_crawl_status`. | `filename` (required), `content_type` (required: `pdf`/`docx`/`doc`/`txt`/`md`), `base64_content` (required) |
| `bubblav_list_crawl_urls` | List manual crawl URLs, sub-websites, sitemap URLs, and llms.txt URLs. | none |
| `bubblav_add_crawl_url` | Add a single public URL to crawl and index, then queue an incremental crawl. | `url` (required) |
| `bubblav_delete_crawl_url` | Delete a manual crawl URL by id. | `url_id` (required) |
| `bubblav_update_sitemaps` | Replace the sitemap.xml and/or llms.txt URL lists (full replacement arrays). | `sitemap_urls`, `llms_txt_urls` |
| `bubblav_get_crawl_status` | Check indexing progress: website status, pages indexed, pending/processing chunk counts. | none |
### Forms
| Tool | Description | Key parameters |
| --------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `bubblav_list_forms` | List AI forms with fields, AI instructions, enabled state, and submission counts. | none |
| `bubblav_create_form` | Create an AI-powered form to collect structured data from visitors. | `name` (required), `fields` (required; each needs `id`, `type`, `label`), `ai_instructions`, `enabled` |
| `bubblav_update_form` | Update a form; only provided fields change. | `form_id` (required), `name`, `fields`, `ai_instructions`, `enabled` |
| `bubblav_delete_form` | Permanently delete a form and its submissions. | `form_id` (required) |
### Flows (Pro+)
| Tool | Description | Key parameters |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `bubblav_list_flows` | List flows with name, trigger type, active state, and run counts. | none |
| `bubblav_get_flow` | Get a single flow including its full `definition` (`nodes` + `edges`). | `flow_id` (required) |
| `bubblav_create_flow` | Create a flow. The `definition` is validated (exactly one trigger, acyclic, all nodes reachable). A `form_submitted` trigger accepts optional `data.formId` to pin the flow to one form (ids via `bubblav_list_forms`); omit it to fire on every submission. New flows are inactive — tell the user to test in the editor before activating. | `name` (required), `definition` (required: `{nodes, edges}`), `description`, `is_active` |
| `bubblav_update_flow` | Update a flow; only provided fields change. `definition` is re-validated. | `flow_id` (required), `name`, `description`, `definition`, `is_active` |
| `bubblav_delete_flow` | Permanently delete a flow and its run history. | `flow_id` (required) |
| `bubblav_list_flow_runs` | List execution runs for a flow (status, trigger event, timestamps). | `flow_id` (required), `limit`, `offset` |
### API keys
| Tool | Description | Key parameters |
| ------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `bubblav_list_api_keys` | List MCP API keys (name, prefix, scopes, active state, last used). Never returns the secret. | none |
| `bubblav_create_api_key` | Create a scoped MCP API key. The full key is returned **only once** — store it immediately. | `name` (required), `scopes` (required: `mcp:read` and/or `mcp:tools:execute`) |
| `bubblav_revoke_api_key` | Revoke (deactivate) a key. | `key_id` (required) |
## Setup Guide
BubblaV MCP Server supports these connection methods:
1. **ChatGPT** - OAuth 2.0, no API key needed
2. **Claude / Claude Desktop** - OAuth 2.0, no API key needed
3. **Google Antigravity** - OAuth 2.0, no API key needed
4. **API Key** - For OpenClaw and other MCP clients
## Option 1: ChatGPT (OAuth 2.0)
Use the same MCP server URL:
```
https://www.bubblav.com/mcp
```
If your client expects an API-style path, this also works:
```
https://www.bubblav.com/api/mcp
```
ChatGPT will start OAuth automatically. Sign in to BubblaV and select the website you want to connect.
## Option 2: Claude (OAuth 2.0)
No API key needed. Claude handles authentication automatically via OAuth — just add the server URL.
### Step 1: Add the BubblaV connector
In Claude (web or desktop), open **Settings** → **Integrations** (or **Connected tools**) and add a new MCP server with this URL:
```
https://www.bubblav.com/api/mcp
```
### Step 2: Authorize
Claude will open a BubblaV login page. Sign in and select which website to connect. That's it — no config files to edit, no API keys to copy.
## Option 3: OpenClaw (API Key)
### Step 1: Generate an MCP API Key
1. Log in to your BubblaV dashboard at [https://www.bubblav.com](https://www.bubblav.com)
2. Navigate to your **Website Settings** page
3. Click the **API Keys** tab
4. Click **Generate New Key**
5. Enter a name (e.g., "OpenClaw") and select → MCP scopes
6. Click **Generate** and copy the key immediately — it won't be shown again
Your API key will look like:
```
bubblav_mcp_a1b2c3d4e5f6g7h8i9j0k1l2
```
### Step 2: Configure OpenClaw using mcporter
We recommend using [mcporter](https://github.com/jasonacox/mcporter) to easily configure OpenClaw with BubblaV.
#### Install mcporter
```bash theme={null}
# Using pip
pip install mcporter
# Or using pipx
pipx install mcporter
```
#### Configure BubblaV in OpenClaw
Create a configuration file `bubblav.json`:
```json theme={null}
{
"name": "bubblav",
"url": "https://www.bubblav.com/api/mcp",
"headers": {
"X-API-Key": "bubblav_mcp_YOUR_API_KEY_HERE"
}
}
```
Then run mcporter:
```bash theme={null}
mcporter add bubblav.json
```
#### Manual Configuration
If you prefer manual configuration, add this to your OpenClaw config:
```yaml theme={null}
name: bubblav
connection:
url: https://www.bubblav.com/api/mcp
headers:
X-API-Key: bubblav_mcp_YOUR_API_KEY_HERE
```
### Step 3: Test the Connection
Once connected, your OpenClaw agent will have access to:
* `bubblav_search_knowledge` - Search your knowledge base
* `bubblav_read_report` - Access full analytics reports
* `bubblav_add_knowledge` - Add new knowledge entries
* `bubblav_delete_knowledge` - Remove outdated entries
* `bubblav_list_knowledge_sources` - List all knowledge sources
* `bubblav_list_conversations` - List and filter conversations
* `bubblav_get_conversation` - Get full conversation details
* `bubblav_search_conversations` - Full-text search across conversations
* `bubblav_list_leads` - List captured leads (emails)
* `bubblav_list_unanswered_questions` - Find knowledge gaps
* `bubblav_get_most_asked_questions` - See trending visitor questions
* `bubblav_get_content_gaps` - Identify content improvement areas
* `bubblav_get_answerable_questions` - See what your bot can answer
* `bubblav_get_visitor_insights` - Get visitor profiles
* `bubblav_get_hourly_activity` - Analyze peak support times
* `bubblav_sync_ticket_to_knowledge` - Turn resolved tickets into knowledge
* `bubblav_scrape_url` - Scrape web pages to markdown
* `bubblav_list_custom_tools` - List custom webhook tools
* `bubblav_create_custom_tool` - Create a new custom tool
* `bubblav_update_custom_tool` - Update an existing custom tool
* `bubblav_delete_custom_tool` - Delete a custom tool
* `bubblav_toggle_custom_tool` - Enable/disable a tool per-website
* `bubblav_list_tool_logs` - Read tool-call logs (status, date range, limit) to debug your custom tools
You can test by asking your agent to search for information or add new content to your knowledge base.
## Option 4: OpenClaw (Automatic Setup)
### Setup Everything Automatically
Tell OpenClaw to install and configure everything for BubblaV automatically.
**Command:**
```
Please configure BubblaV MCP server integration with these details:
- Server URL: https://www.bubblav.com/api/mcp
- Tools available: bubblav_search_knowledge, bubblav_read_report, bubblav_add_knowledge, bubblav_list_conversations, bubblav_get_conversation, bubblav_search_conversations, bubblav_list_leads, bubblav_list_unanswered_questions, bubblav_get_most_asked_questions, bubblav_get_content_gaps, bubblav_get_answerable_questions, bubblav_delete_knowledge, bubblav_sync_ticket_to_knowledge, bubblav_list_knowledge_sources, bubblav_get_visitor_insights, bubblav_get_hourly_activity, bubblav_scrape_url, bubblav_list_custom_tools, bubblav_create_custom_tool, bubblav_update_custom_tool, bubblav_delete_custom_tool, bubblav_toggle_custom_tool, bubblav_list_tool_logs
- Authentication: API key required
Please ask me for an MCP API key, or let me guide you through generating one.
```
**What this does:**
1. Opens BubblaV dashboard in your browser
2. Generates an API key with proper scopes
3. Configures OpenClaw with server URL and API key
4. Tests connection
**Example prompt:**
```
Setup BubblaV MCP server so I can access my knowledge base and add content to it from OpenClaw.
```
2. **Search knowledge base**: Ask your AI agent to search your website content
3. **Get analytics**: Request a conversation or performance report
4. **Add knowledge**: Test adding a new knowledge entry with title and content
## Rate Limits
MCP API calls are tracked separately from your AI message limits. Each subscription plan includes a monthly MCP call allowance:
| Plan | Calls per Month |
| ------ | --------------- |
| Free | 100 |
| Pro | 5,000 |
| Custom | Unlimited |
**How it works:**
* Rolling 30-day window (resets every month from your first call)
* When exceeded, you'll receive a `429` status with a `Retry-After` header
* Check your usage in the dashboard under **Integrations** → **MCP Settings**
## Security
### Authentication Methods
**OAuth 2.0 (Claude):**
* Claude handles the full OAuth flow — you only enter the server URL
* Uses PKCE (Proof Key for Code Exchange) for enhanced security
* Tokens expire after 1 hour (access) or 30 days (refresh)
* No credentials to store or rotate
**API Key (OpenClaw and other clients):**
* Simple authentication via `X-API-Key` header
* Keys can be rotated and revoked
* Supports scoped permissions
### API Key & Token Management
* **Keep your API key secret** - Treat it like a password
* **Rotate keys regularly** - Generate new keys and revoke old ones
* **Use scopes** - Only grant the permissions you need
* **Monitor usage** - Review audit logs regularly
### Scopes
Available scopes for MCP API keys and OAuth tokens:
* `mcp:read` - Read-only access to your website data
* `mcp:tools:execute` - Execute MCP tools and scrape URLs via API
### Audit Logging
All MCP tool calls are logged and available in your dashboard:
* Tool name and arguments
* Success/failure status
* API key or OAuth token used
* Timestamp
View logs at **Chatbot** → **Log**
## Troubleshooting
### Connection Issues
**Problem**: "Authentication failed" error
**Solutions**:
* Verify your API key is correct
* Check that the key hasn't been revoked
* Ensure the key has the correct scopes
* Confirm your account is active
**Problem**: "Rate limit exceeded" error
**Solutions**:
* Check your usage in the dashboard
* Wait for the monthly window to reset (check `Retry-After` header)
* Consider upgrading your plan for higher limits
### Tool Errors
**Problem**: "Unknown tool" error
**Solutions**:
* Verify you're using the correct tool names
* Check that your website has indexed content (for knowledge search)
* Ensure your API key has `mcp:tools:execute` scope
**Problem**: "Invalid argument" error
**Solutions**:
* Check that all required parameters are provided
* Verify parameter types match the schema
* Ensure dates are in ISO format (YYYY-MM-DD)
### Knowledge Base Not Available
**Problem**: `bubblav_search_knowledge` tool not available
**Solutions**:
* Ensure your website has been crawled and content indexed
* Check crawl status in the dashboard under **Knowledge Base**
* Trigger a new crawl if needed
## Example Use Cases
### Customer Support Agent
Create an agent that can search your documentation and provide analytics:
```yaml theme={null}
name: support-agent
tools:
- bubblav_search_knowledge
- bubblav_read_report
- bubblav_get_conversation
- bubblav_get_visitor_insights
instructions: |
You are a customer support agent with access to our knowledge base.
Search for relevant information and provide helpful responses.
Look up visitor insights before responding to understand their history.
```
### Reporting Bot
Build a bot that generates monthly performance reports:
```yaml theme={null}
name: reporting-bot
tools:
- bubblav_read_report
- bubblav_get_hourly_activity
- bubblav_get_most_asked_questions
schedule: "0 9 1 * *" # First day of every month at 9 AM
instructions: |
Generate a performance report for the past month.
Include hourly activity breakdowns and top questions.
```
### Knowledge Search API
Create a simple search API for your internal tools:
```javascript theme={null}
const response = await fetch('https://www.bubblav.com/api/mcp/call', {
method: 'POST',
headers: {
'X-API-Key': 'bubblav_mcp_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
toolId: 'bubblav_search_knowledge',
arguments: {
query: 'return policy',
limit: 5
}
})
});
const data = await response.json();
```
### Knowledge Gap Auto-Filler
Build an agent that identifies content gaps and fills them automatically:
```yaml theme={null}
name: knowledge-gap-filler
tools:
- bubblav_get_content_gaps
- bubblav_search_knowledge
- bubblav_add_knowledge
- bubblav_sync_ticket_to_knowledge
instructions: |
Check for content gaps using bubblav_get_content_gaps.
For each gap, search existing knowledge first.
If not covered, add a new knowledge entry.
Also sync resolved tickets that contain useful answers.
```
### Custom Tool Manager
Let an AI agent manage custom webhook tools for your chatbot:
```yaml theme={null}
name: custom-tool-manager
tools:
- bubblav_list_custom_tools
- bubblav_create_custom_tool
- bubblav_update_custom_tool
- bubblav_delete_custom_tool
- bubblav_toggle_custom_tool
instructions: |
Manage custom webhook tools for the BubblaV chatbot.
When asked to create a tool, always list existing tools first to avoid duplicates.
Gather the endpoint URL, authentication type, and argument schema from the user.
After creating, share the secret_key with the user immediately — it won't be shown again.
```
### Lead Pipeline Agent
Monitor leads and feed them into your CRM:
```yaml theme={null}
name: lead-pipeline
tools:
- bubblav_list_leads
- bubblav_get_visitor_insights
- bubblav_search_conversations
schedule: "0 */6 * * *" # Every 6 hours
instructions: |
Fetch new leads from the past 6 hours.
Enrich each lead with visitor insights.
Search their conversations for buying intent signals.
```
## Support
Need help? Contact us at:
* **Email**: [support@bubblav.com](mailto:support@bubblav.com)
## API Reference
### Endpoints
**MCP (JSON-RPC 2.0):**
```
POST https://www.bubblav.com/api/mcp
Headers:
Authorization: Bearer (Claude — OAuth)
X-API-Key: bubblav_mcp_... (OpenClaw — API key)
Content-Type: application/json
Body:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
```
**OAuth Discovery:**
```
GET https://www.bubblav.com/.well-known/oauth-authorization-server
```
**OAuth Authorize:**
```
GET https://www.bubblav.com/api/oauth/authorize
?response_type=code
&client_id=
&redirect_uri=https://claude.ai/api/mcp/auth_callback
&code_challenge=
&code_challenge_method=S256
&state=
&scope=claudeai
```
Redirects unauthenticated users to login, then shows a website-selection consent page.
**OAuth Token Exchange:**
```
POST https://www.bubblav.com/api/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=
&redirect_uri=https://claude.ai/api/mcp/auth_callback
&code_verifier=
```
### Error Codes
| Code | Description |
| ---- | -------------------------------------------------------- |
| 401 | Authentication failed (invalid or missing API key/token) |
| 403 | Insufficient scopes |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
# Scrape API
Source: https://docs.bubblav.com/developer-guide/scrape-api
Scrape a web page URL and receive clean markdown using your BubblaV API key.
# BubblaV Scrape API
Use BubblaV to scrape any public page and return:
```json theme={null}
{
"url": "https://example.com/final-url",
"markdown": "# Page content in markdown"
}
```
You can reuse the same API key used for MCP server access.
## Endpoint
* **URL:** `POST https://www.bubblav.com/api/scrape`
* **Header:** `X-API-Key: bubblav_mcp_...`
* **Required scope:** `mcp:tools:execute`
## cURL
```bash theme={null}
curl -X POST https://www.bubblav.com/api/scrape \
-H "Content-Type: application/json" \
-H "X-API-Key: bubblav_mcp_YOUR_API_KEY" \
-d '{"url":"https://example.com"}'
```
## Node.js SDK
```bash theme={null}
npm install @bubblav/tools
```
```js theme={null}
import BubblavTools from '@bubblav/tools';
const app = new BubblavTools({ apiKey: 'bubblav_mcp_YOUR_API_KEY' });
const data = await app.scrape('https://example.com');
console.log(data.url);
console.log(data.markdown);
```
## Python
```python theme={null}
import requests
resp = requests.post(
"https://www.bubblav.com/api/scrape",
headers={
"X-API-Key": "bubblav_mcp_YOUR_API_KEY",
"Content-Type": "application/json",
},
json={"url": "https://example.com"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())
```
## CLI (npx)
```bash theme={null}
export BUBBLAV_API_KEY=bubblav_mcp_YOUR_API_KEY
npx @bubblav/tools scrape https://example.com
```
## AI Skill Install
Create a local skill folder and add this `SKILL.md`:
```md theme={null}
# Web Scrape Markdown Skill
Use BubblaV scrape API for web fetches.
POST https://www.bubblav.com/api/scrape
Header: X-API-Key
Body: { "url": "https://..." }
```
Skill lives in this repo: `skills/web-scrape-md/SKILL.md`.
## MCP Tool
If you're already connected to BubblaV MCP server, use tool:
* `bubblav_scrape_url` with `{ "url": "https://example.com" }`
This returns the same JSON structure (url + markdown).
## Install AI Skill with npx
```bash theme={null}
npx skills add github:bubblav-org/tools/skills/web-scrape-md
```
## Claude Code Plugin
### Configure API key for the plugin
The plugin skills (e.g. `web-scrape-md`) need a BubblaV API key.
**Generate a key:**
1. Log in to your [BubblaV dashboard](https://www.bubblav.com)
2. Navigate to your **Website Settings** page
3. Click the **API Keys** tab
4. Click **Generate New Key**
5. Enter a name (e.g. "Claude Code") and select **MCP scopes**
6. Click **Generate** and copy the key immediately — it won't be shown again
Then set it in your project's `.claude/.env` file:
```bash theme={null}
# .claude/.env
BUBBLAV_API_KEY=bubblav_mcp_YOUR_API_KEY
```
If the key is missing, the skill will prompt you to provide one on first use and save it automatically. Once configured, it persists across sessions.
**Env file priority** (highest to lowest):
| Priority | File | Scope |
| -------- | ----------------------------- | -------------------- |
| 1 | `process.env` | Runtime override |
| 2 | `.claude/skills//.env` | Skill-specific |
| 3 | `.claude/skills/.env` | All skills |
| 4 | `.claude/.env` | Project-wide default |
### Install via marketplace
Add the BubblaV marketplace and install the plugin:
```text theme={null}
/plugin marketplace add bubblav-org/tools
```
Then browse and install from the **Discover** tab, or install directly:
```text theme={null}
/plugin install bubblav-tools@bubblav-org-tools
```
After installing, reload to activate:
```text theme={null}
/reload-plugins
```
# SDK Reference
Source: https://docs.bubblav.com/developer-guide/sdk-reference
Control the BubblaV widget programmatically using the JavaScript SDK.
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
### NPM Packages (Recommended)
Install your framework package and the shared SDK (for browser types and server-only token helpers):
**1. Install the package:**
```bash theme={null}
npm install @bubblav/ai-chatbot-react @bubblav/ai-chatbot-sdk
```
**2. Add the widget to your app:**
```tsx theme={null}
import { BubblaVWidget } from '@bubblav/ai-chatbot-react';
function App() {
return (
);
}
```
**3. Control the widget programmatically:**
```tsx theme={null}
import { useBubblaVWidget } from '@bubblav/ai-chatbot-react';
function MyComponent() {
const widget = useBubblaVWidget();
const handleSupportClick = () => {
widget?.open();
widget?.sendMessage('Hello! I need help.');
};
return ;
}
```
**1. Install the package:**
```bash theme={null}
npm install @bubblav/ai-chatbot-vue @bubblav/ai-chatbot-sdk
```
**2. Add the widget to your app:**
```vue theme={null}
```
**3. Control the widget programmatically:**
```vue theme={null}
```
**1. Install the package:**
```bash theme={null}
npm install @bubblav/ai-chatbot-angular @bubblav/ai-chatbot-sdk
```
**2. Add the widget to your app:**
```ts theme={null}
import { Component } from '@angular/core';
import { BubblaVWidgetComponent } from '@bubblav/ai-chatbot-angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [BubblaVWidgetComponent],
template: ``
})
export class AppComponent {}
```
**3. Control the widget programmatically:**
```ts theme={null}
import { Component, inject } from '@angular/core';
import { BubblaVWidgetService } from '@bubblav/ai-chatbot-angular';
@Component({
selector: 'app-support',
template: ``
})
export class SupportComponent {
private bubblav = inject(BubblaVWidgetService);
handleSupportClick() {
this.bubblav.open();
this.bubblav.sendMessage('Hello! I need help.');
}
}
```
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:
```ts theme={null}
import { waitForBubblaVAPI } from '@bubblav/ai-chatbot-sdk';
const controller = new AbortController();
const api = await waitForBubblaVAPI({ signal: controller.signal });
api?.open();
// On teardown: controller.abort();
```
`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
```tsx theme={null}
'use client';
import { BubblaVWidget } from '@bubblav/ai-chatbot-react';
export function DashboardChat({ websiteId, initialToken, refreshSettings }: {
websiteId: string;
initialToken: string | null;
refreshSettings: () => void;
}) {
return (
{
console.info('Tools finished', toolNames);
}}
toolRefresh={{
refresh: refreshSettings,
shouldRefresh: ({ toolNames }) => toolNames.includes('update_settings'),
debounceMs: 500,
}}
onError={(error) => console.error('Widget error', error.code)}
/>
);
}
```
`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:
```vue theme={null}
```
Angular exposes `identity` / `toolRefresh` inputs and `toolExecuted` / `error` outputs:
```ts theme={null}
import { Component, Input } from '@angular/core';
import { BubblaVWidgetComponent } from '@bubblav/ai-chatbot-angular';
import type { BubblaVWidgetError, ToolExecutedEvent, ToolRefreshOptions } from '@bubblav/ai-chatbot-sdk';
@Component({
selector: 'app-dashboard-chat',
standalone: true,
imports: [BubblaVWidgetComponent],
template: `
`,
})
export class DashboardChatComponent {
@Input({ required: true }) websiteId!: string;
@Input({ required: true }) initialToken!: string | null;
@Input({ required: true }) toolRefresh!: ToolRefreshOptions;
onTools({ toolNames }: ToolExecutedEvent) { console.info('Tools finished', toolNames); }
onError(error: BubblaVWidgetError) { console.error('Widget error', error.code); }
}
```
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
```bash theme={null}
npm install @bubblav/ai-chatbot-sdk
```
```ts theme={null}
import { mountBubblaVWidget } from '@bubblav/ai-chatbot-sdk';
export function mountDashboardChat(websiteId: string, initialToken: string) {
const options = {
websiteId,
identity: { token: initialToken, tokenEndpoint: '/api/chat-identity' },
};
const connection = mountBubblaVWidget(options); // Browser lifecycle only
void connection.ready.then(api => api.open()).catch(error => {
console.error('Widget failed to become ready', error.code);
});
return {
logout() {
connection.update({ ...options, identity: { token: null } });
},
dispose() { connection.dispose(); },
};
}
```
`mountBubblaVWidget(options)` returns a `WidgetConnection`: `ready: Promise`, `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:
```ts theme={null}
import type { IdentityTokenProvider, WidgetIdentity } from '@bubblav/ai-chatbot-sdk';
const getToken: IdentityTokenProvider = async ({ signal }) => {
const response = await fetch('/api/chat-identity', {
method: 'POST',
credentials: 'same-origin',
cache: 'no-store',
signal,
});
if (!response.ok) throw new Error('Identity refresh failed');
const data = await response.json();
if (typeof data?.token !== 'string' || !data.token.trim()) {
throw new Error('Identity refresh returned no token');
}
return data.token;
};
export const identityFor = (initialToken: string): WidgetIdentity => ({ token: initialToken, getToken });
```
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](/developer-guide/in-app-chatbot-integration#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.
```ts theme={null}
// Server-only configuration
export const identityOptions = {
websiteId: process.env.BUBBLAV_WEBSITE_ID ?? '',
signingSecret: process.env.BUBBLAV_END_USER_SIGNING_SECRET ?? '',
};
```
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:
```ts theme={null}
// app/api/chat-identity/route.ts — adapt the auth helper to your app
import { createEndUserToken } from '@bubblav/ai-chatbot-sdk/server';
import { getAuthenticatedUser } from '@/lib/auth';
import { identityOptions } from '@/lib/chat-identity-options';
export async function GET() {
const headers = { 'Cache-Control': 'no-store' };
const user = await getAuthenticatedUser();
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401, headers });
const token = await createEndUserToken(
{ userId: user.id, email: user.email, name: user.name },
{ ...identityOptions, ttlSeconds: 600 },
);
return Response.json({ token }, { headers });
}
```
| Helper | Contract |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createEndUserToken(user, options): Promise` | `user` is `{ userId: string, email?: string \| null, name?: string \| null }`. `EndUserTokenOptions` requires nonempty `websiteId` and `signingSecret`; optional `ttlSeconds` is a finite positive integer, default 600. |
| `verifyMcpToken(token, options): Promise` | Verifies a per-call JWT, not a host identity token. `McpVerificationOptions` requires `websiteId` and `signingSecret`; optional nonempty `previousSigningSecret` is tried only when explicitly configured. |
| `verifyMcpRequest(headers, options): Promise` | Accepts a Web `Headers` object. Returns `null` only when Authorization is absent and configuration is valid. A present empty/malformed/non-Bearer/invalid credential throws `BubblaVTokenError`, even on discovery requests. |
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.
```ts theme={null}
import { BubblaVTokenError, verifyMcpRequest } from '@bubblav/ai-chatbot-sdk/server';
import { identityOptions } from '@/lib/chat-identity-options';
import { settingsForUser } from '@/lib/settings';
const verificationOptions = {
...identityOptions,
previousSigningSecret: process.env.BUBBLAV_PREVIOUS_SIGNING_SECRET || undefined,
};
// Called by your protected tool handler, not by anonymous schema discovery.
export async function readSettings(headers: Headers) {
const identity = await verifyMcpRequest(headers, verificationOptions);
if (!identity) throw new BubblaVTokenError('Authentication required');
return settingsForUser(identity.sub); // Resolve current permissions and scope every query here.
}
```
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](/developer-guide/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.
```javascript theme={null}
BubblaV.open();
```
**Use cases:**
* Trigger chat from a custom button
* Open chat after a user action
* Start conversation proactively
***
#### `close()`
Closes the chat widget.
```javascript theme={null}
BubblaV.close();
```
**Use cases:**
* Close chat after a conversation
* Respond to user dismiss action
***
#### `toggle()`
Toggles the widget open/closed state.
```javascript theme={null}
BubblaV.toggle();
```
**Use cases:**
* Single button to toggle widget
* Keyboard shortcuts for chat access
***
#### `openSearch()`
Opens the search interface (modal).
```javascript theme={null}
BubblaV.openSearch();
```
**Use cases:**
* Trigger search from a custom button
* Open search after a user action
***
#### `isOpen()`
Checks if the widget is currently open.
```javascript theme={null}
if (BubblaV.isOpen()) {
console.log('Widget is open');
}
```
**Returns:** `boolean`
***
### Messaging
#### `sendMessage(text, conversationId?)`
Sends a message programmatically.
```javascript theme={null}
// Send a simple message
BubblaV.sendMessage('Hello, I need help!');
// Send to a specific conversation
BubblaV.sendMessage('Where is my order?', 'conv_123');
```
| Parameter | Type | Required | Description |
| ---------------- | -------- | -------- | ---------------------- |
| `text` | `string` | Yes | Message text to send |
| `conversationId` | `string` | No | Target conversation ID |
**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.
```javascript theme={null}
// Show default greeting
BubblaV.showGreeting();
// Show custom message
BubblaV.showGreeting('Hi! How can I help you today?');
// Show greeting with sender info
BubblaV.showGreeting({
message: 'Hi! How can I help you today?',
senderName: 'Support Team',
senderAvatarUrl: 'https://example.com/avatar.png',
timestamp: new Date().toISOString()
});
```
| Parameter | Type | Required | Description |
| --------- | -------------------- | -------- | ------------------------------------------------------------------------------------- |
| `data` | `string` \| `object` | No | Message string or object with `message`, `senderName`, `senderAvatarUrl`, `timestamp` |
**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.
```javascript theme={null}
BubblaV.hideGreeting();
```
***
### Configuration
#### `getConfig()`
Gets the current widget configuration.
```javascript theme={null}
const config = BubblaV.getConfig();
console.log('Widget config:', config);
```
**Returns:** `object` with current configuration
***
#### `setDebug(enabled)`
Enables or disables debug mode.
```javascript theme={null}
// Enable debug mode
BubblaV.setDebug(true);
// Disable debug mode
BubblaV.setDebug(false);
```
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.
```javascript theme={null}
BubblaV.on('chat:opened', () => {
console.log('Chat widget opened');
});
BubblaV.on('message:received', (message) => {
console.log('New message:', message);
});
```
### `off(event, callback)`
Unregister an event listener.
```javascript theme={null}
const handler = () => console.log('Chat opened');
BubblaV.on('chat:opened', handler);
// Later...
BubblaV.off('chat:opened', handler);
```
***
## Available Events
| Event | Description | Payload |
| -------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `chat:opened` | Triggered when the chat widget is opened. | `undefined` |
| `chat:closed` | Triggered when the chat widget is closed. | `undefined` |
| `search:opened` | Triggered when the search interface is opened. | `{ mode: string }` |
| `search:closed` | Triggered when the search interface is closed. | `{ mode: string }` |
| `message:sent` | Triggered when a message is sent by the user. | `{ conversation_id: string, text: string }` |
| `message:received` | Triggered when a message is received from the bot/agent. | `{ conversation_id: string, message_id: string, text: string, fromVisitor: boolean }` |
| `message:rated` | Triggered when a specific message is rated. | `{ conversation_id: string, message_id: string, rating: 'up' \| 'down' }` |
| `conversation:rated` | Triggered when the conversation is rated. | `{ conversation_id: string, rating: number }` |
| `widget:expanded` | Triggered when the widget is expanded (desktop). | `undefined` |
| `widget:collapsed` | Triggered when the widget is collapsed (desktop). | `undefined` |
| `search:query` | Triggered when a search query is submitted. | `{ query: string, source: "input" \| "suggestion" }` |
| `toolExecuted` | One or more tools reached terminal output, including errors. | `{ toolNames: string[] }` |
| `identityNeeded` | The widget requests a replacement end-user token. Global listener return values are ignored. | `undefined` |
| `ready` | Triggered when the widget is fully loaded. | `undefined` |
***
## Framework Examples
### React
#### Using Hooks
```tsx theme={null}
'use client';
import { useRef } from 'react';
import { BubblaVWidget, useBubblaVWidget } from '@bubblav/ai-chatbot-react';
import type { BubblaVAPI } from '@bubblav/ai-chatbot-sdk';
function SupportButton() {
const widgetRef = useRef(null);
const widget = useBubblaVWidget();
const openSupport = () => {
widget?.open();
};
return (
<>
>
);
}
```
#### Using the Widget Component
```tsx theme={null}
import { BubblaVWidget } from '@bubblav/ai-chatbot-react';
function App() {
return (
console.info('Tools finished', toolNames)}
/>
);
}
```
***
### Vue
#### Using Composition API
```vue theme={null}
```
***
### Angular
```ts theme={null}
import { Component, inject } from '@angular/core';
import { BubblaVWidgetComponent, BubblaVWidgetService } from '@bubblav/ai-chatbot-angular';
@Component({
selector: 'app-support',
standalone: true,
imports: [BubblaVWidgetComponent],
template: `
`
})
export class SupportComponent {
private bubblav = inject(BubblaVWidgetService);
openSupport() {
this.bubblav.open();
}
}
```
***
## 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:
```ts theme={null}
import type { BubblaVAPI, ToolExecutedEvent, WidgetIdentity, ToolRefreshOptions } from '@bubblav/ai-chatbot-sdk';
import type { BubblaVWidgetProps } from '@bubblav/ai-chatbot-react';
const config: BubblaVWidgetProps = {
websiteId: 'your-website-id',
onToolExecuted: (event: ToolExecutedEvent) => console.info(event.toolNames),
};
```
Vue's `useBubblaVWidget()` returns `Ref`; 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:
```javascript theme={null}
BubblaV.ready(() => {
BubblaV.open();
});
```
3. **Clean Up Listeners**
Remove event listeners when they're no longer needed:
```javascript theme={null}
const handler = () => console.log('Opened');
BubblaV.on('chat:opened', handler);
// Later...
BubblaV.off('chat:opened', handler);
```
4. **Handle Edge Cases**
Check if methods exist before calling:
```javascript theme={null}
if (BubblaV && typeof BubblaV.open === 'function') {
BubblaV.open();
}
```
5. **Use Environment Variables**
Store your website ID in environment variables:
```env theme={null}
# Next.js
NEXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
# Nuxt
NUXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
```
```tsx theme={null}
```
***
## Full SDK Reference
```typescript theme={null}
import type { ToolExecutedEvent } from '@bubblav/ai-chatbot-sdk';
interface BubblaVAPI {
open(): void;
close(): void;
toggle(): void;
isOpen(): boolean;
show(): void;
hide(): void;
openSearch(): void;
closeSearch(): void;
toggleSearch(): void;
sendMessage(message: string, conversationId?: string): void;
showGreeting(data?: string | {
message?: string;
senderName?: string;
senderAvatarUrl?: string;
timestamp?: string | number;
}): void;
hideGreeting(): void;
identify(token: string | null): boolean | void;
onIdentityNeeded(callback: () => void): (() => void) | void;
offIdentityNeeded(callback: () => void): void;
on(event: 'toolExecuted', callback: (event: ToolExecutedEvent) => void): void;
on(event: string, callback: (data: T, ...args: unknown[]) => void): void;
off(event: 'toolExecuted', callback: (event: ToolExecutedEvent) => void): void;
off(event: string, callback: (data: T, ...args: unknown[]) => void): void;
getConfig(): Record;
setDebug(enabled: boolean): void;
ready(callback: () => void): void;
track(eventName: string, properties?: Record): void;
}
```
***
## Next Steps
Customize widget appearance and behavior
Quick-start templates for Next.js and Nuxt
# Starter Templates
Source: https://docs.bubblav.com/developer-guide/starter-templates
Quick-start templates for integrating BubblaV into your Next.js, Nuxt, or Angular applications
Starter templates provide a quick way to integrate BubblaV into your project. Use our official templates for Next.js, Nuxt, and Angular to get started in minutes.
***
## Next.js Template
Get started with BubblaV in your Next.js application.
### Repository
[github.com/bubblav-org/nextjs-template](https://github.com/bubblav-org/nextjs-template)
### Features
* Pre-configured BubblaV widget integration
* Environment variable setup
* TypeScript support
* Example usage components
### Quick Start
```bash theme={null}
# Clone the template
git clone https://github.com/bubblav-org/nextjs-template.git my-bubblav-app
# Navigate to the project
cd my-bubblav-app
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env.local
# Edit .env.local and add your website ID
# NEXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
# Start the development server
npm run dev
```
### Project Structure
```
nextjs-template/
├── app/
│ ├── layout.tsx # Root layout with BubblaV provider
│ └── page.tsx # Home page with example usage
├── components/
│ └── bubblav-widget.tsx # Widget component
├── .env.example # Environment variables template
└── README.md # Setup instructions
```
### Configuration
Add your website ID in `.env.local`:
```env theme={null}
NEXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
```
***
## Nuxt Template
Get started with BubblaV in your Nuxt application.
### Repository
[github.com/bubblav-org/nuxt-template](https://github.com/bubblav-org/nuxt-template)
### Features
* Nuxt 3 compatible
* Auto-imports for BubblaV composables
* Environment variable configuration
* TypeScript support
### Quick Start
```bash theme={null}
# Clone the template
git clone https://github.com/bubblav-org/nuxt-template.git my-bubblav-app
# Navigate to the project
cd my-bubblav-app
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env
# Edit .env and add your website ID
# NUXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
# Start the development server
npm run dev
```
### Project Structure
```
nuxt-template/
├── app.vue # Root component with BubblaV integration
├── components/
│ └── BubblaVWidget.vue # Widget component
├── composables/
│ └── useBubblaV.ts # BubblaV composable
├── .env.example # Environment variables template
└── README.md # Setup instructions
```
### Configuration
Add your website ID in `.env`:
```env theme={null}
NUXT_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
```
***
## Angular Template
Get started with BubblaV in your Angular application.
### Repository
[github.com/bubblav-org/angular-template](https://github.com/bubblav-org/angular-template)
### Features
* Angular 21 with standalone components
* Tailwind CSS with CSS variable theming
* Dark/light theme toggle with localStorage persistence
* Pre-configured BubblaV widget integration
* TypeScript support
* Environment variable setup via `set-env.cjs` script
### Quick Start
```bash theme={null}
# Clone the template
git clone https://github.com/bubblav-org/angular-template.git my-bubblav-app
# Navigate to the project
cd my-bubblav-app
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env.local
# Edit .env.local and add your website ID
# ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
# Start the development server
npm run start
```
Open [http://localhost:4200](http://localhost:4200) to view your app.
### Project Structure
```
angular-template/
├── src/
│ ├── app/
│ │ ├── components/
│ │ │ ├── header.component.ts # Navigation with theme toggle and "Ask AI" button
│ │ │ └── theme-toggle.component.ts # Dark/light mode switcher
│ │ └── app.component.ts # Root component with BubblaV widget
│ ├── environments/
│ │ ├── environment.template.ts # Environment template (git tracked)
│ │ └── environment.prod.template.ts # Production template (git tracked)
│ └── styles.css # CSS variables and theme definitions
├── set-env.cjs # Environment file generator script
├── .env.example # Environment variables template
└── README.md # Setup instructions
```
### Configuration
Add your website ID in `.env.local`:
```env theme={null}
ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID=your-website-id
```
**How it works:**
* The `set-env.cjs` script reads your `.env.local` file and generates `src/environments/environment.ts` at build time
* Run `npm run start` - the script runs automatically before the dev server
* For Vercel deployment, set `ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID` in your project's Environment Variables
***
## Deploy to Vercel
Deploy your BubblaV-powered application to Vercel in a few clicks.
### Prerequisites
* A [Vercel account](https://vercel.com/signup)
* Your BubblaV website ID
* Git repository (GitHub, GitLab, or Bitbucket)
### Deploy Next.js Template
#### Option 1: One-Click Deploy (Recommended)
The fastest way to deploy your Next.js application to Vercel:
#### Option 2: Deploy with Vercel CLI
```bash theme={null}
# Install Vercel CLI
npm install -g vercel
# Navigate to your project
cd my-bubblav-app
# Deploy
vercel
```
#### Option 3: Deploy via Vercel Dashboard
1. **Push your code to GitHub**
```bash theme={null}
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/your-username/my-bubblav-app.git
git push -u origin main
```
2. **Import to Vercel**
* Go to [vercel.com/new](https://vercel.com/new)
* Click "Import Git Repository"
* Select your repository
* Configure the project:
* **Framework Preset**: Next.js (auto-detected)
* **Root Directory**: `./` (default)
* **Build Command**: `npm run build` (default)
* **Output Directory**: `.next` (default)
3. **Add Environment Variables**
* In the Vercel dashboard, go to **Settings** → **Environment Variables**
* Add `NEXT_PUBLIC_BUBBLAV_WEBSITE_ID` with your website ID
* Click "Save"
4. **Deploy**
* Click "Deploy"
* Vercel will build and deploy your application
***
### Deploy Nuxt Template
#### Option 1: One-Click Deploy (Recommended)
The fastest way to deploy your Nuxt application to Vercel:
#### Option 2: Deploy with Vercel CLI
```bash theme={null}
# Install Vercel CLI
npm install -g vercel
# Navigate to your project
cd my-bubblav-app
# Deploy
vercel
```
#### Option 3: Deploy via Vercel Dashboard
1. **Push your code to GitHub**
```bash theme={null}
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/your-username/my-bubblav-app.git
git push -u origin main
```
2. **Import to Vercel**
* Go to [vercel.com/new](https://vercel.com/new)
* Click "Import Git Repository"
* Select your repository
* Configure the project:
* **Framework Preset**: Nuxt.js (auto-detected)
* **Root Directory**: `./` (default)
* **Build Command**: `npm run build` (default)
* **Output Directory**: `.output` (default)
3. **Add Environment Variables**
* In the Vercel dashboard, go to **Settings** → **Environment Variables**
* Add `NUXT_PUBLIC_BUBBLAV_WEBSITE_ID` with your website ID
* Click "Save"
4. **Deploy**
* Click "Deploy"
* Vercel will build and deploy your application
***
### Deploy Angular Template
#### Option 1: One-Click Deploy (Recommended)
The fastest way to deploy your Angular application to Vercel:
#### Option 2: Deploy with Vercel CLI
```bash theme={null}
# Install Vercel CLI
npm install -g vercel
# Navigate to your project
cd my-bubblav-app
# Deploy
vercel
```
#### Option 3: Deploy via Vercel Dashboard
1. **Push your code to GitHub**
```bash theme={null}
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/your-username/my-bubblav-app.git
git push -u origin main
```
2. **Import to Vercel**
* Go to [vercel.com/new](https://vercel.com/new)
* Click "Import Git Repository"
* Select your repository
* Configure the project:
* **Framework Preset**: Angular (auto-detected)
* **Root Directory**: `./` (default)
* **Build Command**: `npm run build` (default)
* **Output Directory**: `dist/angular-template/browser` (default)
3. **Add Environment Variables**
* In the Vercel dashboard, go to **Settings** → **Environment Variables**
* Add `ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID` with your website ID
* Click "Save"
4. **Deploy**
* Click "Deploy"
* Vercel will build and deploy your application
***
## Environment Variables
| Variable | Description | Required |
| ----------------------------------- | ---------------------------------------------------- | ------------- |
| `NEXT_PUBLIC_BUBBLAV_WEBSITE_ID` | Your website ID from the BubblaV dashboard (Next.js) | Yes (Next.js) |
| `NUXT_PUBLIC_BUBBLAV_WEBSITE_ID` | Your website ID from the BubblaV dashboard (Nuxt) | Yes (Nuxt) |
| `ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID` | Your website ID from the BubblaV dashboard (Angular) | Yes (Angular) |
### Finding Your Website ID
1. Log in to your [BubblaV dashboard](https://www.bubblav.com/dashboard)
2. Go to **Chat Widget** → **Installation**
3. Copy your Website ID
***
## Customization
After deploying, you can customize the widget:
Customize colors, position, and behavior
Programmatic control with the SDK
***
## Troubleshooting
### Widget Not Showing
1. **Check your Website ID**: Ensure the environment variable is set correctly (`NEXT_PUBLIC_BUBBLAV_WEBSITE_ID` for Next.js, `NUXT_PUBLIC_BUBBLAV_WEBSITE_ID` for Nuxt, `ANGULAR_PUBLIC_BUBBLAV_WEBSITE_ID` for Angular)
2. **Verify deployment**: Check Vercel deployment logs for errors
3. **Clear cache**: Clear your browser cache and reload
4. **For Angular**: Verify the `set-env.cjs` script ran correctly by checking `src/environments/environment.ts` contains your Website ID
### Environment Variables Not Working
1. **Redeploy after adding variables**: Environment variables require a redeploy
2. **Check variable scope**: Ensure variables are set for all environments (Preview, Production)
3. **Verify variable name**: Make sure you're using the correct prefix (`NEXT_PUBLIC_` for Next.js, `NUXT_PUBLIC_` for Nuxt, `ANGULAR_PUBLIC_` for Angular)
4. **For Angular**: Ensure you're using `set-env.cjs` to generate environment files before running `npm run start` or `npm run build`
***
## Next Steps
Learn different installation methods
Programmatic control with the SDK
Customize widget appearance
# Help & Support
Source: https://docs.bubblav.com/help-support
Find answers to common questions and get help with BubblaV
Find answers to frequently asked questions about BubblaV. For quick how-to questions while you work, try the [in-dashboard help assistant](/user-guide/help-assistant). If you need additional help, [contact our support team](https://www.bubblav.com/contact).
## Getting Started
Visit [bubblav.com](https://www.bubblav.com) and click **Sign Up**. You'll need to verify your email before you can start using the platform.
After logging in, go to **Dashboard** → **Websites** and click **Add Website**. Enter your website URL and BubblaV will automatically start crawling your content.
You can have a basic chatbot running in 5-10 minutes. Website crawling typically takes 2-5 minutes depending on your site size, and you can continue configuring while it runs.
1. BubblaV automatically crawls your website to learn your content
2. Your knowledge base is populated with indexed pages
3. A unique embed code is generated for your website
4. You can customize the widget and test it before going live
No installation on your server is required. You just need to add a small JavaScript snippet to your website's HTML. See the Installation guide for platform-specific instructions.
## Installation & Widget Deployment
1. Go to **Dashboard** → **Installation**
2. Copy the embed code provided
3. Paste it into your website's HTML (typically in the footer or header)
4. The widget will appear on your live site within minutes
For platform-specific instructions, see the Installation guide.
Yes! You can use the "Insert Headers and Footers" plugin to paste the embed code in the footer section, or manually add it to your theme's footer.php file.
Yes! Install the BubblaV Shopify app from the App Store. It will automatically integrate with your store and you can configure it from your dashboard.
Yes! Google Tag Manager (GTM) works on virtually any website and is a great option when your platform has no dedicated app. Create a new **Custom HTML** tag, paste your BubblaV embed code, set the trigger to **All Pages**, then **Submit** and **Publish**. See the [Google Tag Manager guide](/user-guide/integrations/google-tag-manager) for full step-by-step instructions.
* Verify the embed code is correctly placed in your HTML
* Check your browser console for errors
* Ensure you're using the correct website ID
* Wait a few minutes for the widget to load
* Check that your website ID is active in your dashboard
Yes. Go to **Design** → **Positioning** and choose **Bottom Right** or **Bottom Left** for both desktop and mobile.
## Knowledge Base & Training
Website crawling automatically scans your website, extracts content from your pages, and makes it searchable so your chatbot can answer questions accurately based on your actual content.
When you add a website, BubblaV:
1. Visits your URL and extracts all text content
2. Follows links to discover other pages on your domain
3. Detects sitemaps and crawls listed URLs
4. Processes content into searchable chunks
5. Updates status for each page (Crawled, Pending, Failed)
Yes! You can add sub-websites and external domains to your knowledge base. This allows you to train your chatbot on content from multiple related sources.
Check your robots.txt file. BubblaV respects the robots.txt standard, so pages blocked there won't be crawled. If needed, you can manually add content using text snippets or file uploads.
Yes! You can upload PDFs, documents, and text files directly to your knowledge base. Go to **Knowledge** → **Files** to upload content.
Use **Knowledge** → **Q\&A** to add specific entries. Write out question and answer pairs you want the chatbot to know.
## Widget Customization & Design
Go to **Design** in your dashboard to customize:
* Brand colors and color themes
* Widget size and position
* Welcome message and chat suggestions
* Bot name and avatar
* Background styles
Yes! When you add a new website, BubblaV automatically analyzes your site's colors and applies a matching theme. You can also manually extract colors anytime: go to **Design** → **Color Palette Presets**, enter any URL, and click **Extract Colors**.
Yes. Go to **Design** → **Home Screen** to customize the bot's name, avatar image, and welcome message.
Yes, this option is available on Pro+ plans. Go to **Design** → **General** and toggle **Show 'Powered by' branding**.
* **Width**: Default is 400px (adjustable)
* **Height**: Default is 650px (adjustable)
You can customize dimensions to match your website's design.
Changes usually appear within a minute of saving. If they don't, allow up to 5 minutes for caching to clear, then reload your site — or open it in an incognito window to see the latest version. See [Widget Design](/user-guide/widget-design) for details.
## Integrations
Connecting Shopify enables your chatbot to:
* Track orders by order number
* Search your product catalog
* Show product details
* Access customer order history
* Process returns and refunds
* Check gift card balances
* Validate discount codes
1. Go to **Dashboard** → **Integrations** → **Shopify**
2. Click **Connect Shopify**
3. The BubblaV app will open in the Shopify App Store
4. Click **Install** and authorize the app
5. You'll be redirected back to your dashboard
* Verify you're using your `.myshopify.com` domain
* Check that your store is active
* Clear browser cache and try incognito mode
* Ensure you have app installation permissions
* Try the authorization process again
BubblaV supports integrations with: Shopify, HubSpot, Zendesk, Calendly, Stripe, Klarna, Polar, and custom tools via our MCP servers.
Use **Custom Tools** to create HTTP requests to any API. You can define tools that call external services and integrate them into your chatbot.
## Live Support
Live support lets you take over conversations in real-time when a customer needs to talk to a human. This feature is available on Pro+ plans.
Live support is automatically enabled for Pro+ plan users. Your team members can access the **Live Support** dashboard to see and respond to conversations in real-time.
Your account owner can add team members with different roles. Go to **Team & Members** to manage who can access live support conversations.
## Account & Billing
BubblaV offers plans with different features and pricing. Visit the [Pricing page](https://www.bubblav.com/pricing) to see all available plans and their features.
**Pricing Summary:**
* **Free**: \$0/month (100 messages/month, 1 website, 50 pages)
* **Pro**: \$49/month (\$39/month annually, save \$120/year, 5,000 messages/month) - 14-day free trial
All paid plans include annual billing options with 20% savings compared to monthly billing.
Yes! The Pro plan includes a **14-day free trial** for new customers. You get full access to all Pro features during the trial period. Your payment card is required at signup but won't be charged until the trial ends. Cancel anytime during the trial at no cost.
You can change your plan anytime from your **Account Settings** → **Billing**. Upgrades are effective immediately, and downgrades take effect at the end of your billing cycle.
EU consumers have a 14-day right of withdrawal under EU consumer law
(ångerätt). Because we charge nothing during the 14-day free trial and paid
plans cannot start until the trial ends, your withdrawal right is fully
covered by the trial: you may cancel or downgrade to the Free plan at any
time before the trial ends at no cost. If you are ever charged within 14
days of starting a paid subscription, contact us for a full refund.
Otherwise, contact our [support team](https://www.bubblav.com/contact) to
discuss your options. See our [Terms of Service](https://www.bubblav.com/terms) for full details.
Go to **Team & Members** in your dashboard and click **Add Member**. Enter their email address and select their role. They'll receive an invitation to join your account.
## Troubleshooting
* Verify your website was fully crawled (check Knowledge → Pages)
* Add specific Q\&A pairs for common questions you want answered
* Upload relevant documents to your knowledge base
* Use "Content Gaps" to identify what information is missing
* Test with specific questions from your website content
Your knowledge base may not have enough specific information. Consider:
* Adding more detailed content to your website
* Uploading PDFs with detailed product/service information
* Adding Q\&A entries with specific question/answer pairs
* Refining behavior in Settings
* Check your spam/junk folder
* Verify you entered the correct email address
* Request a new verification email
* Try signing up with Google instead
* Large websites (100+ pages) naturally take longer
* Check if your site blocks bots in robots.txt
* Try adding pages manually if crawl continues to fail
* Contact support if crawl is stuck
* Verify you're using the correct login credentials
* Try resetting your password
* Check that your browser supports the dashboard
* Clear your browser cache and try again
* Contact support if you're still unable to access
* Check your internet connection
* Verify the widget code is correctly installed
* Check browser console for JavaScript errors
* Ensure your website's server is responding quickly
* Try clearing your browser cache
## Still Need Help?
If you can't find the answer you're looking for, we're here to help! [Contact our support team](https://www.bubblav.com/contact) and we'll respond as quickly as possible.
You can also check the [User Guide](/user-guide/getting-started) for more detailed documentation.
# Documentation
Source: https://docs.bubblav.com/index
Guides and references for setting up, customizing, and growing with your BubblaV AI chatbot
BubblaV is an AI chatbot that trains on your website content, answers visitor questions 24/7, and hands complex conversations to your live support team. Start here or jump straight to the area you need.
## Start here
Create an account, add your website, and go live in under 10 minutes
Add the chatbot widget to your website or platform
Match the widget to your brand colors, position, and tone
Verify answers and behavior before going live
## Train and improve your chatbot
How website crawling, Q\&A, and files become answers
Tone of voice, guardrails, and answer quality
Automations: proactive openers, handoffs, and multi-step scenarios
Conversations, trends, and most-asked questions
## Engage and convert visitors
Unified inbox, copilot, and human handoff across channels
Collect leads, quotes, reviews, and support tickets in chat
## Integrations
E-commerce, CRM, messaging, scheduling, and more
Order tracking, product search, and visitor insights
Escalate conversations to your help desk
## For developers
Programmatic control of the widget
Ready-to-use Next.js and Nuxt examples
Connect AI agents and tools to your chatbot
Programmatic access to website crawling
## Get help
FAQs and how to reach our support team
Free and Pro plans, quotas, and upgrades
Product overview and sign-up
# Account Settings
Source: https://docs.bubblav.com/user-guide/account-settings
Manage your profile, notification preferences, and security from one tabbed page
# Account Settings
Account Settings is your personal hub for profile information, notification preferences, and security. It's organized into three tabs: **Profile**, **Notifications**, and **Security**.
Open it from the sidebar avatar menu or go to **Dashboard → Account Settings**. You can also deep-link a tab with `?tab=profile`, `?tab=notifications`, or `?tab=security`.
## Profile tab
Update your basic account information:
* **Profile image** — Upload and crop an avatar. It appears in support chats and internal dashboards.
* **Full name** — Used in emails and across the dashboard.
* **Email** — Read-only. This is the address you signed up with.
Click **Save Changes** when you're done.
## Notifications tab
Control how BubblaV reaches you across three channels and four notification types. See [Push & Message Notifications](/user-guide/live-support/push-notifications) for the full walkthrough; the key idea is a **channel × type** matrix.
* **Web** — the in-app notification bell (the notification center).
* **Push** — browser push notifications on desktop and mobile.
* **Email** — sent to your account email address.
### Master channel toggles
At the top, three switches act as master kill-switches. Turning a channel off disables it for **every** notification type below — for example, turn off **Push** to stop all browser push notifications at once.
### Per notification type
Each type has independent **Web**, **Push**, and **Email** checkboxes (a checkbox is disabled while its master toggle is off):
| Type | What it covers |
| ------------------- | --------------------------------------------------------------------------------------------------------- |
| **Messages** | A visitor sends a message in live support. |
| **Quota** | Your message quota is low or exhausted. Includes an **alert threshold (%)** and an optional **CC email**. |
| **Support request** | A visitor requests human support. |
| **Form submission** | A visitor submits a form. |
Your account email always receives email notifications for enabled types. You can add **one** additional CC email for quota notifications.
### Browser push status
A separate panel shows whether push is enabled **on this browser**. Because browser permission is per-device, enabling push here only affects the browser you're currently using — use it on each device where you want notifications. If push is blocked, unblock the site in your browser settings, then return here.
Click **Save preferences** to persist your matrix.
## Security tab
* **Change Password** — Available for email/password accounts. OAuth users manage passwords through their provider.
* **Data Export** — Download all your account data (profile, subscriptions, websites).
* **Danger Zone** — Permanently delete your account. This is irreversible and cancels active subscriptions.
## FAQ
**Q: Why don't I see push notifications on my phone?**
A: Browser push works on the specific browser where you enabled it. Open BubblaV in your mobile browser and enable push in **Account Settings → Notifications → Browser push status** on that device.
**Q: I turned off a type but still see old notifications.**
A: Toggles affect *future* notifications. Existing items stay in your bell inbox until you archive or read them.
**Q: Where do form and support-request emails come from?**
A: They're sent from BubblaV to your account email (plus your quota CC email for quota alerts). See [Email Notifications](/user-guide/live-support/email-notifications) for message-reply emails.
# Use AI Agents to Manage & Improve Your Chatbot
Source: https://docs.bubblav.com/user-guide/ai-agent-workflows
Connect Claude, ChatGPT, or OpenClaw to BubblaV via MCP and let your AI diagnose content gaps, write knowledge, tune behavior, set up human handoff, and build custom tools — with copy-paste prompts.
You don't have to manage your chatbot by hand. BubblaV exposes its data and settings over an
**MCP server**, so an AI assistant like **Claude**, **ChatGPT**, **Google Antigravity**, or
**OpenClaw** can run the same tasks you'd do in the dashboard — diagnose weak answers, write and
add knowledge, tune the bot's persona, set up human handoff, and build custom tools.
This page is a recipe book. Each recipe has a **goal**, a **copy-paste prompt**, and the **MCP
tools** it triggers. For the full tool-by-tool reference and connection details, see the
[MCP Server](/developer-guide/mcp-server) developer guide.
## What you can do
Find the questions your bot struggles with and the topics visitors ask about most.
Draft and add Q\&A, upload files, and let the AI search resolved tickets automatically.
Rewrite the chatbot persona and edit the widget's words, colors, and starters.
Configure human-handoff triggers and build custom webhook tools.
## Connect your AI (one time)
Add BubblaV as an MCP server in your assistant. The setup differs slightly by client — full
screenshots are in the [MCP Server guide](/developer-guide/mcp-server).
These clients use **OAuth** — no API key to manage.
1. In your assistant's settings, add a new MCP server with the URL below.
2. Authorize: sign in to BubblaV and pick the website to connect.
3. Done. Your assistant now sees BubblaV's tools.
```text theme={null}
https://www.bubblav.com/mcp
```
API-key clients send a header instead of OAuth.
1. In BubblaV, open **Website Settings → API Keys** and generate a key with the
`mcp:read` and `mcp:tools:execute` scopes. Copy it — it's shown once.
2. Point your client at the endpoint below, sending `X-API-Key: bubblav_mcp_…`.
3. We recommend the [mcporter](https://github.com/jasonacox/mcporter) helper to configure OpenClaw.
```text theme={null}
URL: https://www.bubblav.com/api/mcp
Header: X-API-Key: bubblav_mcp_YOUR_KEY
```
Your assistant can only act on the website you authorized, and every call is logged in
**Integrations → MCP Settings → Audit Logs**.
***
## Recipes
Paste each prompt into your connected assistant and edit the bracketed parts. Your assistant will
call the BubblaV tools for you.
### 1. Find content gaps & trending questions
**Goal:** see where the bot fails and what visitors ask most, grouped into themes.
```text theme={null}
Look at my chatbot's content gaps and most-asked questions from the last 30 days.
Group them by theme, tell me which topics the bot struggles with most, and rank
the top five things I should fix.
```
**Tools it triggers:** `bubblav_get_content_gaps`, `bubblav_get_most_asked_questions`, `bubblav_read_report`.
### 2. Fill content gaps with new knowledge
**Goal:** draft answers for the worst gaps and add them — without writing each one by hand.
```text theme={null}
Take the top three gaps in the [shipping] theme. Here's our policy: [paste text].
Draft a clear Q&A-style answer for each gap, show them to me for approval, then
add each approved answer to the knowledge base. Skip any gap already covered.
```
**Tools it triggers:** `bubblav_search_knowledge` (de-dup check), `bubblav_add_knowledge`.
```text theme={null}
Upload and index this file as knowledge: [attach PDF/DOCX/TXT/MD, ≤10MB]
```
Calls `bubblav_upload_knowledge_file`, then `bubblav_get_crawl_status` to confirm indexing.
```text theme={null}
Crawl and index this URL into my knowledge base: https://example.com/new-page
```
Calls `bubblav_add_crawl_url`.
With the Zendesk, Zoho Desk or HubSpot integration connected, the AI searches resolved
tickets at answer time — configure visibility under the integration's Tools.
### 3. Turn conversations into insight
**Goal:** audit specific issues or pull leads out of conversations.
```text theme={null}
Find every conversation from the last two weeks that mentioned a "billing error".
Summarize the common causes. Then list the leads (visitors who gave an email) from
the same period so I can follow up.
```
**Tools it triggers:** `bubblav_search_conversations`, `bubblav_get_conversation`, `bubblav_list_leads`.
### 4. Tune the chatbot persona & widget
**Goal:** change how the bot talks and looks, editing in place rather than overwriting.
```text theme={null}
Read my bot's current instructions. Then update the persona so it's warmer and more
concise, always greets by name, and offers to escalate to a human for anything
billing-related. Also set the widget greeting to "Hi there! How can we help?" and
add three starter suggestions.
```
**Tools it triggers:** `bubblav_get_website_settings`, `bubblav_update_website_settings`
(the `custom_instructions` field is the persona, max 2,000 chars), `bubblav_update_widget_appearance`.
### 5. Set up human handoff triggers (Pro+)
**Goal:** route sensitive intents to a live agent automatically.
```text theme={null}
Create a handoff flow: a visitor_intent trigger matching "refund, cancellation, or
complaint", then a request_human node with the message "Let me connect you with a
teammate who can sort this out." List my existing flows first so we don't duplicate.
```
**Tools it triggers:** `bubblav_list_flows`, `bubblav_create_flow`.
### 6. Build a custom webhook tool (Pro+)
**Goal:** let the chatbot take a real action (check an order, query a CRM, get a quote).
```text theme={null}
Create a custom tool called "check_order_status" that takes an order number and
calls my webhook at https://example.com/api/order-status using bearer auth.
Describe it for the AI so it knows when to use it, then activate it for this website.
```
**Tools it triggers:** `bubblav_list_custom_tools`, `bubblav_create_custom_tool`.
The `secret_key` for a bearer/hmac tool is returned **only once**. Tell your assistant to surface
it to you immediately so you can configure your webhook. See
[Custom Tools](/user-guide/integrations/custom-tools) for webhook validation details.
### 7. Create a scoped API key for another agent
**Goal:** give a second assistant (or Zapier, a script, etc.) limited access.
```text theme={null}
Create a new MCP API key named "Zapier" with read-only (mcp:read) scope.
```
**Tools it triggers:** `bubblav_create_api_key`. (Use `bubblav_list_api_keys` and
`bubblav_revoke_api_key` to audit and revoke.)
***
## The improvement loop
These recipes chain into a weekly habit:
```text theme={null}
1. Diagnose — "what should I fix this week?"
2. Improve — "draft & add answers for the top gaps"
3. Measure — "how did resolution rate change?"
4. Tune — "adjust tone / handoff based on what you saw"
```
Your AI drives each cycle — BubblaV does **not** run an autonomous self-improvement job in the
background. You approve knowledge before it's added and control how the persona evolves. The win
is collapsing a week of dashboard chores into a single conversation.
## Plans & limits
MCP calls are counted separately from your AI message limits, on a rolling 30-day window.
| Plan | MCP calls / month |
| ------ | ----------------- |
| Free | 100 |
| Pro | 5,000 |
| Custom | Unlimited |
The following require a **Pro plan or higher** (gated when the tool runs):
* `bubblav_create_custom_tool` and custom-tool management
* `bubblav_create_flow` and flow management (handoffs, smart triggers, form notifications)
* `bubblav_sync_ticket_to_knowledge`
See [Billing & Plans](/user-guide/billing) for full plan details. When you exceed the limit you'll
get an HTTP `429` with a `Retry-After` header.
## Related
Every tool, parameter, auth flow, and rate limit — the developer reference.
How crawled pages, Q\&A, and files become answers.
The dashboard view of content gaps and answerable questions.
Webhook tools, authentication, and validation.
# AI Page
Source: https://docs.bubblav.com/user-guide/ai-page
Add a full-page AI chat interface to your website
The AI Page is a full-page, conversational AI interface that provides an immersive chat experience. Unlike the floating widget, the AI Page takes over the entire viewport, making it perfect for dedicated help pages, support portals, or AI-powered landing pages.
## What is the AI Page?
The AI Page provides:
* **Full-page experience**: Immersive chat interface that fills the entire browser window
* **Conversational AI**: Interactive chat with streaming responses
* **Source citations**: AI responses include links to relevant content from your knowledge base
* **Customizable appearance**: Light and dark themes to match your brand
* **Lazy loading**: Optimized performance with code splitting
## Use Cases
The AI Page is ideal for:
* **Dedicated help centers**: `/help` or `/support` pages
* **AI-powered landing pages**: Interactive product demos or onboarding
* **Knowledge base search**: Full-page search interface for documentation
* **Internal tools**: Employee support portals or FAQ pages
* **Customer portals**: Integrated chat in customer dashboard areas
***
## Installation
### Basic Setup
Add the AI Page to your website in two simple steps:
Add a container div where you want the AI Page to appear:
```html theme={null}
```
Add the AI Page script with your configuration:
```html theme={null}
```
The AI Page will automatically create the container if you don't provide one, but we recommend adding it explicitly for better control.
***
## Configuration Options
### Required Attributes
| Attribute | Description | Example |
| -------------- | ------------------------------ | -------------------------------------- |
| `src` | Script URL | `https://www.bubblav.com/ai-page.js` |
| `data-site-id` | Your unique website identifier | `812b25b4-02df-40fa-9f68-3a99b372b1a1` |
### Optional Attributes
| Attribute | Description | Default |
| ------------------ | -------------------------------- | ------------------------- |
| `data-theme` | Visual theme (`light` or `dark`) | `light` |
| `data-title` | Header text for the chat | `"What can I help with?"` |
| `data-placeholder` | Input placeholder text | `"Ask me anything..."` |
***
## Platform-Specific Instructions
### Static HTML
Add to your HTML page:
```html theme={null}
AI Help Center
```
### React / Next.js
**Using next/script (Recommended for Next.js):**
```jsx theme={null}
// app/ai-help/page.tsx
import Script from 'next/script';
export default function AIHelpPage() {
return (
);
}
```
**Using useEffect (Alternative):**
```jsx theme={null}
// components/AIPage.jsx
import { useEffect } from 'react';
export default function AIPage() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://www.bubblav.com/ai-page.js';
script.dataset.siteId = 'YOUR_SITE_ID';
script.dataset.theme = 'dark';
script.defer = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
};
}, []);
return ;
}
```
### WordPress
**Option 1: Using a Plugin**
1. Install a "Custom HTML" or "Insert HTML" plugin
2. Create a new page (e.g., "AI Help Center")
3. Add a Custom HTML block with:
```html theme={null}
```
**Option 2: Page Template**
Create a custom page template in your theme:
```php theme={null}
```
### Webflow
1. Create a new page (e.g., "AI Help")
2. Add an Embed element anywhere on the page
3. Paste the following code:
```html theme={null}
```
4. Set the page body to have no padding/margin for full-screen experience
### Framer
1. Create a new page
2. Add a Code component from the components panel
3. Set it to "Custom Code" and paste:
```html theme={null}
```
4. Set the page layout to fill the screen for best results
***
## Styling & Layout
### Container Styling
The AI Page fills its parent container. For best results:
```css theme={null}
#bubblav-ai-page {
width: 100%;
height: 100vh; /* Full viewport height */
margin: 0;
padding: 0;
overflow: hidden; /* Prevent scrollbars */
}
```
### Theme Options
Choose between two built-in themes:
**Light Theme:**
```html theme={null}
data-theme="light"
```
**Dark Theme:**
```html theme={null}
data-theme="dark"
```
The theme controls the color scheme of the entire interface including the chat sidebar, message bubbles, and input area.
***
## Advanced Configuration
### Custom Titles
Change the header text:
```html theme={null}
data-title="How can I help you today?"
```
### Custom Placeholder
Change the input placeholder:
```html theme={null}
data-placeholder="Type your question here..."
```
***
## How It Works
1. **Script loads**: The ai-page.js loader fetches the latest version
2. **Widget initializes**: React component mounts in the container
3. **User sends message**: Chat streams responses in real-time
4. **Sources displayed**: AI responses include citations from your knowledge base
5. **Conversation history**: Chat persists during the session
***
## Best Practices
The AI Page is designed for full-page experiences. Use it on dedicated routes like `/help`, `/support`, or `/ai-chat`.
Choose light or dark theme based on your website's design for seamless integration.
Customize the title and placeholder to match the purpose of your page (e.g., "Product Support" vs "Sales Assistant").
Ensure your API endpoint is accessible and properly configured before going live.
The AI Page uses your plan's message limits. Monitor usage in your dashboard.
***
## Troubleshooting
* Verify the container div with `id="bubblav-ai-page"` exists
* Check browser console for JavaScript errors
* Ensure your API key is correct
* Confirm the script URL is loading (check Network tab)
* Verify `data-api-url` points to a valid endpoint
* Check CORS settings on your API
* Ensure your API key is valid and not expired
* Review browser console for specific error messages
* Ensure parent container has defined height
* Check for CSS conflicts from your site's stylesheets
* Verify `overflow: hidden` on the container
* Test in different browsers
* The widget uses lazy loading for optimal performance
* Initial load may take 1-2 seconds
* Subsequent loads are faster due to browser caching
* Check your network connection
***
## Comparison: AI Page vs Widget
| Feature | AI Page | Widget |
| --------------- | -------------------- | ----------------- |
| Layout | Full-page immersion | Floating bubble |
| Best for | Dedicated help pages | Site-wide support |
| Screen usage | 100% viewport | Minimal footprint |
| User experience | Focused conversation | Quick assistance |
| Installation | Per page | Site-wide |
Use both! Install the widget sitewide for quick help, and add the AI Page to your dedicated support page for in-depth conversations.
***
## Next Steps
Add content for the AI to reference
Customize your chatbot appearance
# Best Practices
Source: https://docs.bubblav.com/user-guide/best-practices
Guide to getting the most out of BubblaV for your customers
To ensure your BubblaV chatbot provides the best possible support to your customers, follow these best practices for content management, testing, and continuous improvement.
## 1. Effective Content Crawling
The foundation of a smart chatbot is a comprehensive knowledge base.
* **Start with a thorough crawl**: When setting up, ensure you crawl your main documentation, help center, and landing pages.
* **Verify status**: Check the **Knowledge** tab to ensure all pages are "Indexed".
## 2. Testing in the Design Page
Before deploying or after making changes, always use the testing function on the **Design** page.
1. Navigate to your website dashboard and click **Design**.
2. The chat preview on the right side simulates the real user experience.
3. **Ask specific questions**: Ask about pricing, specific features, return policies, or edge cases.
4. **Verify citations**: Check that the bot is citing the correct pages from your site.
## 3. Resolving Content Gaps
When you spot an incorrect or suboptimal answer during testing:
* Go to the **Knowledge** section -> **Content Gaps**.
* BubblaV automatically flags questions that the AI struggled with.
* **Add a Q\&A Entry**: You can convert an unanswered question into a precise, hand-crafted Q\&A pair.
* This is perfect for "sensitive" questions or brand-specific phrasing that might not be clear in the raw web text.
## 4. Adding Manual Q\&A
Sometimes your website doesn't explicitly state the answer to a common question (e.g., "Do you offer a non-profit discount?") or the info is scattered.
* Go to **Knowledge** > **Q\&A**.
* Add a **Q\&A Entry** (e.g., Question: "Do you offer discounts?", Answer: "Yes, we offer...").
* This fills gaps without needing to create new public web pages.
## 5. Monitoring Content Gaps
Your chatbot improves over time if you listen to what users are asking.
* **Check Top Unanswered Questions**: Periodically review usage reports to see what questions the bot couldn't answer.
* **Identify Gaps**: If users ask about a feature you haven't documented, that's a content gap.
* **Action**:
* Add a new section to your website and re-crawl.
* Or add a manual Q\&A entry in the **Q\&A** tab to address it immediately.
By following this loop—**Crawl**, **Test**, **Q\&A**, and **Monitor**—you will build a powerful automated support agent that your customers love.
# Billing & Plans
Source: https://docs.bubblav.com/user-guide/billing
Manage your subscription, billing details, and usage
BubblaV offers flexible pricing plans to scale with your business needs. You can manage your subscription, view invoices, and track usage directly from the dashboard.
## Subscription Plans
We offer plans to suit different needs:
Perfect for testing and personal projects.
* **Price**: \$0/month
* 1 Website
* 50 pages (web + files + text)
* 100 messages/month
* 100 MCP API calls/month
* 7 days retention
* Built-in integrations
* Human handoff on visitor request (chatbot → human)
* Email to visitors
For growing businesses needing advanced features. **Start with a 14-day free trial.**
* **Price**: \$49/month (\$39/month annually, save \$120/year)
* Everything in Free
* 5 Websites
* 5,000 pages (web + files + text) per website
* 5,000 messages/month
* 5,000 MCP API calls/month
* 1 year retention
* Advanced data sources and reports
* Live Chat Dashboard (real-time takeover)
* Flows (visual scenario builder): smart triggers, AI handoff routing, form notifications
* Integrations (Zendesk, HubSpot, Attio) and Custom tools
* Custom branding (remove "Powered by")
* 3 team member seats
* Weekly data sync
## Managing Your Subscription
To access billing settings:
1. Click your **user avatar** in the top-right corner of the dashboard
2. Select **Subscription** from the menu
You can also go directly to [bubblav.com/dashboard/subscription](https://www.bubblav.com/dashboard/subscription).
### Upgrading Your Plan
1. Navigate to the **Subscription** page (via user avatar menu or direct link).
2. Scroll down to the **Available Plans** section.
3. Click **Upgrade** on your desired plan.
4. Follow the checkout prompts to complete the purchase.
### Free Trial
The Pro plan includes a 14-day free trial for new customers. You get full access to all Pro features during the trial period.
* **Eligibility**: Available to new customers who haven't had a paid subscription before
* **Card Required**: Your payment card is required at signup but won't be charged until the trial ends
* **Trial Duration**: 14 days from signup
* **Automatic Conversion**: After the trial, your subscription automatically converts to a paid Pro plan
* **Reminder**: We'll send you a reminder email 2 days before your trial ends
* **Cancel Anytime**: If you cancel during the trial, you won't be charged at all
To start a free trial, click **Start 14-Day Free Trial** on the Pro plan card in the Subscription page.
### Message Usage & Limits
Your plan includes a monthly allowance of AI responses (messages). Only AI responses are counted.
* **Reset Schedule**:
* **Paid Plans**: Usage resets on your monthly billing date (e.g., if you subscribed on the 14th, it resets on the 14th of each month).
* **Free Plan**: Usage resets on the 1st of every calendar month.
* **Tracking Usage**: The Subscription page shows a real-time progress bar of your message consumption.
* **Overages**: If you run out of messages, your chatbot will stop replying until the next cycle or until you purchase an add-on.
* **Add-on Packs**: You can buy "Extra Message Packs" (1,000 messages for \$5) that never expire and are used after your monthly allowance is exhausted.
### MCP API Call Quotas
MCP API calls are tracked separately from your AI message usage.
* **Free**: 100 MCP API calls/month
* **Pro**: 5,000 MCP API calls/month
* **Reset Schedule**: MCP API usage resets on a rolling 30-day window from your first MCP call in the current cycle.
* **Tracking Usage**: You can check current MCP API usage from your website settings in the dashboard.
* **When Limit Is Reached**: MCP requests return a rate limit error until the quota resets.
### Data Sync Frequency
BubblaV automatically syncs your data to keep your chatbot up-to-date. The frequency depends on your plan:
* **Free**: Every 30 days
* **Pro**: Every 7 days
This ensures your chatbot always has the latest information from your website and connected sources.
## Plan Features
### Free Plan Features
The Free plan includes essential features for testing:
* Basic AI chatbot functionality
* Built-in integrations (no external tools)
* Core analytics dashboard
* Message & conversation trends
* Export report data
### Pro Plan Features
The Pro plan unlocks advanced capabilities:
The AI automatically detects when it can't help and escalates to a human agent. It collects visitor information, creates a live support session, and generates external support tickets (Zendesk, HubSpot, etc.) for seamless follow-up.
Take over conversations in real-time with the Live Chat Dashboard. Monitor active conversations, see what visitors are typing, and jump in instantly when needed. Provides full control to handle complex queries personally.
Access detailed analytics including:
* Most active times
* Conversation flow visualization
* Visitor and conversation geography
* Top unanswered questions
* Bad feedback conversations
* Most visited links
* Leads captured
Connect with external tools:
* Zendesk (tickets and knowledge base)
* HubSpot (CRM and tickets)
* Attio (CRM)
* Custom tools
* MCP Servers (Model Context Protocol) - Connect to any external API or service
Remove the "Powered by BubblaV" branding and fully customize the widget appearance to match your brand.
## Billing Providers
We support billing through different providers depending on how you signed up:
### Polar
For users who sign up directly on BubblaV (non-Shopify merchants).
* **14-day free trial** available on Pro plan for new customers
* Invoices emailed automatically
* Choose monthly or yearly billing (save 20% with annual)
### Shopify
For users who installed BubblaV via the Shopify App Store.
* Charges appear on Shopify bill
* Upgrades/downgrades via Shopify billing
* **Note**: Shopify billing only supports monthly billing cycles
* Usage tracking in BubblaV dashboard
## Cancellation
You can cancel your subscription at any time by downgrading to the Free plan:
1. Click your **user avatar** in the top-right corner and select **Subscription**, or go to [bubblav.com/dashboard/subscription](https://www.bubblav.com/dashboard/subscription)
2. Click **Downgrade to Free** on your current plan
3. Confirm the downgrade when prompted
4. Your plan will remain active until the end of the current billing period
**During Free Trial**: If you cancel during your 14-day free trial, you won't be charged at all and your account will revert to the Free plan immediately.
# Make Your Bot Collect Leads, Quotes & Reviews
Source: https://docs.bubblav.com/user-guide/configure-bot-leads-quotes-reviews
Configure your chatbot to handle "Get Free Quote", share review links, and collect leads
Most "can the bot do X?" questions are answered by three features working together: **Forms**, **Q\&A**, and **Integrations**. This page maps the most common requests to the exact setup steps.
Not sure where to start? You can also open the [help assistant](/user-guide/help-assistant) from the **question-mark icon** in the top menu of your dashboard and ask in plain English — e.g. *"How do I make the bot give customers a review link?"*
***
## "I want the bot to handle 'Get Free Quote' requests"
Use a **Form** so the bot collects the visitor's details inside the chat instead of sending them elsewhere.
**Dashboard** → select your website → **Flows** → open a flow (or create one) → add a **Show form** node → **Create form**.
Add the fields you need (e.g. Name, Email, Company, Service, Message).
Use something like: *"Show this form when a visitor asks about pricing, a quote, an estimate, a free quote, or wants to discuss business terms."* Saving it creates an active companion flow that shows the form when the intent matches.
If you placed the form in a flow you built yourself, switch it to **Active** — the editor autosaves. (The auto-created companion flow is already active.)
See [Forms](/user-guide/forms) for the full field list and the ready-made **Quote Requests** example.
Connect a [CRM & Marketing integration](/user-guide/integrations/attio) (Attio, HubSpot, Klaviyo) so every submitted quote becomes a lead in your pipeline automatically.
***
## "I want the bot to give customers a review link"
Two simple options:
Best for a single review link. Add a Q\&A whose question covers review phrasings ("how do I leave a review", "review link", "rate my order") and whose answer contains the exact URL.
Best when you want to collect the review content in-chat. Use the **Product Review** form example so the bot gathers feedback before linking out.
For the Q\&A approach, **Dashboard** → your website → **Knowledge** → **Q\&A** → **Add Q\&A**. Set:
* **Question:** *"How do I leave a review / where is the review link?"*
* **Answer:** *"We'd love your feedback! Leave a review here: [https://your-review-url.com](https://your-review-url.com)"*
***
## "I want the bot to collect email leads"
Combine a **Form** (to capture email + consent) with a **CRM & Marketing integration** (to sync the lead):
* Create a "Newsletter Signup" or "Contact Me" form with an Email field.
* Connect [HubSpot](/user-guide/integrations/hubspot), [Klaviyo](/user-guide/integrations/klaviyo), or [Attio](/user-guide/integrations/attio) so submissions flow into your marketing tool.
***
## Related configuration
The bot answers from your website + knowledge base. Add pages, files, and Q\&A.
Edit the greeting, tone, and persona in Widget Design. Add Q\&A for exact phrasings.
Add the chatbot to your site with one script snippet — no coding required.
Route complex questions to your team with human handoff.
***
## Tips for reliable answers
* **Write Q\&A questions the way visitors actually ask** (e.g. "free quote", not "pricing enquiry form").
* **Keep answers short and actionable** — lead with the link or the next step.
* After adding Q\&A, give the bot a moment to index the new entry before testing.
# Flows: Build Multi-Step Chatbot Scenarios Visually
Source: https://docs.bubblav.com/user-guide/flows
Compose chatbot scenarios on a visual canvas — match visitor intent, collect answers, run tools, call webhooks, notify your team, and hand off to a human — without writing code.
Sometimes a conversation needs more than a single AI answer: collect a few details, look
something up in your systems, then act on it. **Flows** is a visual builder where you compose
those scenarios as a graph of steps — a trigger that starts the flow, then condition and action
nodes that run in order.
Two examples of what a flow can do:
* **Multi-source answer** — a visitor asks a question → the flow searches your Discourse forum
and your CRM via Custom Tools → the AI aggregates the results into one answer.
* **Ticket intake** — the flow asks for email, company, and the problem → submits everything to
your webhook → notifies your team.
Flows consolidate four older features into one canvas:
* **Smart Triggers** → a `page_behavior` trigger + `send_message` node
* **Human handoff scenarios** → a `visitor_intent` trigger + `request_human` node
* **Forms** → embedded in a flow with a `show_form` node
* **Cart Recovery** → a `cart_abandoned` trigger + `delay` + `cart_recovery_touch` nodes
The old Smart Triggers, Forms, and Cart Recovery pages redirect here — everything is built
and edited in the flow editor.
Flows require a **Pro plan**. Messages a flow sends don't consume your monthly message
quota.
## How Flows work
1. A **trigger** starts a run — either a visitor message that matches your intent description,
or an event like a form submission.
2. The flow walks the graph node by node: asking questions, branching on conditions, calling
tools and webhooks, sending messages.
3. While a flow is running or waiting for the visitor's answer, it **owns the conversation** —
the visitor's replies resume the flow instead of going to the AI.
4. The run ends when the graph ends, when an **AI respond** node hands the collected results to
the chatbot for a final answer, or when the visitor cancels ("cancel", "stop", "never mind").
## Triggers
Every flow has exactly one trigger — the first node on the canvas.
| Trigger | Starts a run when… |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `visitor_intent` | A visitor's chat message matches your natural-language intent description (e.g. "wants a callback", "asks about order status"). The AI scores each active flow's intent and the best match above the threshold runs. |
| `page_behavior` | The widget detects page behavior — time on page, exit intent, or (Shopify) cart threshold / product page — and the flow opens the conversation proactively. |
| `form_submitted` | A visitor submits one of your BubblaV forms. |
| `conversation_started` | A new conversation is created. |
| `conversation_rated` | A visitor rates a conversation (thumbs up/down). |
| `handoff_requested` | A live-support ticket is created. |
| `lead_captured` | A visitor's email is captured. |
| `cart_abandoned` | (Shopify) A synced abandoned checkout starts a run — the sync runs every 15 minutes. Payload exposes `{{trigger.email}}`, `{{trigger.recoveryUrl}}`, `{{trigger.totalPrice}}`, `{{trigger.currency}}`, `{{trigger.items}}`. |
| `inbound_webhook` | An external system POSTs to the flow's secret webhook URL — for events from your own backend. |
`visitor_intent` and `page_behavior` are the **chat triggers**: the flow runs inside the
conversation and can talk to the visitor. The others are **event triggers** that run in the
background. Event triggers that carry a conversation (`form_submitted`,
`conversation_started`, `handoff_requested`) can still message the visitor;
`conversation_rated`, `lead_captured`, `cart_abandoned`, and `inbound_webhook` have no
conversation, so chat nodes aren't allowed under them — the editor enforces this.
### Page behavior triggers
A `page_behavior` trigger turns the flow into a proactive opener: the widget watches the
visitor's page behavior and, when it matches, the flow starts a conversation with an
AI-personalized message.
| Subtype | Fires when… |
| ------------------- | -------------------------------------------------------------------------------------- |
| `time_on_page` | The visitor has spent a set dwell time on a matching page. |
| `exit_intent` | The visitor is about to leave (mouse toward the top on desktop, tab switch on mobile). |
| `cart_threshold` | (Shopify) The cart total crosses your configured amount. |
| `product_page` | (Shopify) The visitor dwells on a product page. |
| `new_visitor` | The page loads during the visitor's first session on your site. |
| `returning_visitor` | The page loads for a visitor returning after their first session (\~30 min window). |
Config: `subtype`, `urlMatchType` (`exact`/`contains`/`prefix`/`regex`), `urlPatterns`,
`dwellSeconds`, `cooldownMinutes`, `sortOrder`, plus `config.cart_threshold` for e-commerce
subtypes (`threshold_cents`, `min_cart_cents`, `currency`). `new_visitor` and `returning_visitor`
fire on page load and ignore `dwellSeconds`. When the static greeting message is
enabled it owns the first pageview — a `new_visitor` flow then fires on the next
page view or SPA navigation once the greeting is dismissed or no longer showing.
Pair it with a `send_message` node for the opener — or `generate_text` → `send_message`
when you want the AI to write the opener from instructions.
## Node catalog
Nodes are the steps of your flow. Drag them from the palette onto the canvas and connect them.
| Node | What it does | Settings (`data`) |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trigger` | Entry point — exactly one per flow. | `triggerType`, plus `intent` (required for `visitor_intent`) |
| `condition` | Branches the flow. Its outgoing edges are labeled `true`/`false`. | `mode: 'context'` → `field`, `op` (`equals`, `not_equals`, `contains`, `exists`, `not_exists`), `value`; or `mode: 'ai'` → `question` answered against collected variables |
| `delay` | Parks the run until a timer fires, then resumes on the next node. Visitor messages during the wait go to the AI, not the flow. | `minutes` |
| `collect_input` | Sends a question as a bot message and waits; the visitor's reply is stored in a variable. | `question`, `variable`, `expected` (optional, e.g. `email`, `phone` — the AI checks the reply contains a usable value and re-asks once if not) |
| `show_form` | Sends a bot message with one of your forms embedded and waits for the submission. | `formId`, `introMessage`, `variable` |
| `run_tool` | Runs one of your Custom Tools or MCP tools and stores the result. | `toolId`, `args` (values can be literals or `{{var}}`), `variable` |
| `send_message` | Sends a bot message. | `message` |
| `call_webhook` | Calls an external URL with the same SSRF and timeout guards as Custom Tools; optionally signs the request (HMAC) and stores the response. | `url`, `method` (`POST`/`GET`/`PUT`/`PATCH`), `headers`, `body`, `secret`, `variable` |
| `send_email` | Sends a transactional email. | `to`, `subject`, `body` |
| `notify_team` | Sends a notification to your website's team members (bell, push, and email per their preferences). | `title`, `message` |
| `request_human` | Creates a live-support ticket so a teammate can take over. | `message` |
| `ai_respond` | **AI answer — terminal, chat flows only.** The chatbot answers the visitor using the knowledge base and all collected variables. Must be the last node. | `instructions` (optional) |
| `generate_text` | Generates text mid-flow into a variable — e.g. summarize the conversation for a `send_email` body. Includes the transcript automatically. | `instructions` (required), `variable` (required) |
| `cart_recovery_touch` | Sends an AI-written recovery message for the run's abandoned cart — chat widget if the visitor is reachable (first touch only), else an unsubscribe-compliant email with a one-click recovery link. Skips when the cart is recovered, expired, or suppressed. | `aiInstructions` (optional), `discountCode` (optional) |
## Variables and `{{var}}` interpolation
Every value a flow collects — visitor replies, form submissions, tool results, webhook
responses — is stored in a named **variable**. Use `{{variable}}` (or a nested path like
`{{order.status}}`) inside any message, question, webhook body, or email to insert the value.
The trigger's payload is available as `{{trigger}}`. Missing variables resolve to an empty
string.
## Build a flow
In the dashboard, open your website and go to **Flows**, then click
**New Flow**.
Give the flow a name and choose what starts it — a visitor intent or an event.
Drag nodes from the palette and connect them. Click a node to configure it in the side
panel — pick forms and tools from your website's existing ones, or create a new one from
the panel without leaving the editor.
The editor autosaves as you work (watch for "Saving…"/"Saved" in the header). Open the
**Test** panel to run the flow — chat with it like a visitor, or fire a test event for
event triggers.
When the test run looks right, switch the flow to **active**. New flows are saved inactive
— they never run until you turn them on.
Stuck? Click **Ask BubblaV** in the editor toolbar and describe the scenario — the assistant
can draft the flow on your canvas for you.
## Test before activating
The editor's **Test** panel runs the flow without touching real conversations. Clicking
**Test** saves any pending canvas edits first, so the run always exercises what you see.
* For `visitor_intent` flows, a chat-style transcript lets you play the visitor — send messages,
answer the flow's questions, and watch each step's status. The panel reports the intent-match
score your message would get in production, and typing "cancel" or "stop" exercises the same
escape hatch visitors have. `show_form` nodes render the real form inline — submitting it
resumes the run, and an `ai_respond` node previews the actual AI reply.
* For event triggers, fire a test event with a JSON payload preview. If the run then waits on a
chat node (`collect_input`, `show_form`), the input row switches to a chat box so you can
continue the run like a visitor.
* While a test runs, the canvas highlights the executed path — green for completed nodes, red
for failures, and a pulsing amber ring on the node the run is waiting on.
* Each step in the trace expands to show its exact input and output JSON, so you can see what
data flowed between nodes. Steps that touch the outside world (`run_tool`, `call_webhook`,
`send_email`, `notify_team`, `request_human`, `cart_recovery_touch`) carry a `live` badge.
Test runs execute **real side effects** — tools run, webhooks are called, emails are sent.
Only message delivery is simulated (nothing is sent to a visitor). Point test webhooks at a
service like webhook.site if you don't want to hit production endpoints.
## Runs and history
Every execution is recorded as a **run**. Open a flow's **Runs** page to see each run's status
(`running`, `waiting`, `completed`, `failed`, `cancelled`), when it started, and a per-step
trace showing every node's input, output, or error — the fastest way to debug a flow that
didn't behave as expected.
A run that waits more than 24 hours for a visitor reply is cancelled automatically — timer
waits on a `delay` node are exempt and resume when the timer fires. A visitor can always
escape a waiting flow by saying "cancel" or "stop" — the conversation then goes back to the
normal AI.
## Debug and troubleshoot
When a flow misbehaves, work through it in this order:
1. **Reproduce in the Test panel.** The transcript, intent-match score, and canvas highlight
show exactly which path executed. Expand each step's input/output to see the data it
received and produced.
2. **Check the Runs page.** Every real and test execution is recorded. A `failed` step shows
its error inline; a `waiting` run means the flow is parked on a `collect_input` or
`show_form` node expecting a visitor reply.
3. **Common causes:**
* *Flow never triggers* — the visitor's phrasing doesn't match the intent closely enough.
Test the exact message in the panel; if the score is below the 0.6 threshold, broaden the
intent description.
* *Flow stops mid-run* — a `waiting` status means it's waiting for input, not broken. Check
whether the visitor escaped with "cancel"/"stop" (status `cancelled`) or the run timed
out after 24h.
* *Webhook/tool step failed* — expand the step output for the HTTP status or error. Test
webhooks against a service like webhook.site first.
* *AI reply looks wrong* — `ai_respond` composes from the collected variables; check the
step inputs to confirm the right values were captured, and tighten the node's
`instructions`.
## Example flows
Six recipes to copy — each is a chain of nodes you can build in a few minutes.
### Lead qualification
`visitor_intent` ("interested in pricing / wants a quote") → `collect_input` email
(`expected: email`) → `collect_input` company → `call_webhook` to your CRM → `notify_team` →
`send_message` confirmation.
The visitor asks about pricing, the flow collects their email and company, posts the lead to
your CRM, pings your team, and confirms to the visitor — all inside one conversation.
### Proactive opener (Smart Trigger)
`page_behavior` (`time_on_page`, 30s on `/pricing*`) → `generate_text` → `send_message` → `ai_respond`.
The widget watches visitors dwell on your pricing page, opens the chat with an
AI-written opener, then lets the chatbot answer follow-ups. This is the old Smart
Triggers pattern as a flow.
### Human handoff
`visitor_intent` ("wants to speak to a human / asks for sales") → `collect_input` email →
`request_human`.
The old handoff-scenario pattern: the flow matches the visitor's intent, optionally collects
contact details first, then creates a live-support ticket so a teammate can take over with
the full transcript attached. See [Human handoff](/user-guide/human-handoff).
### Form in a flow
`visitor_intent` ("wants a demo / wants to sign up") → `show_form` (your signup form) →
`send_message` confirmation.
Instead of the AI deciding when to surface a form, the flow controls it: the form renders
in chat at exactly the step you place it, and the submission lands in a variable you can
pass to a webhook or email downstream.
### Ticket intake (event)
`inbound_webhook` → `condition` on `{{trigger.priority}}` → `send_email` to support /
`notify_team`.
Your backend POSTs a ticket payload to the flow's webhook URL; the flow routes high-priority
tickets to the support inbox and notifies the team about the rest. Event triggers have no
visitor conversation, so only non-chat nodes are used.
### Cart recovery (Shopify)
`cart_abandoned` → `delay` 60m → `cart_recovery_touch` → `delay` 24h → `cart_recovery_touch`.
Every synced abandoned checkout starts a run: the flow waits an hour, sends an AI-written
recovery message (chat widget if the visitor is still around, email otherwise), waits a day,
then sends one follow-up. A completed purchase cancels the run mid-wait. See
[Shopify](/user-guide/integrations/shopify#ai-abandoned-cart-recovery).
## Best practices
* **Write intents like a visitor would phrase them** — "wants to speak to sales", not "sales
intent trigger".
* **Collect one thing per `collect_input`** — short questions get better answers, and each
answer lands in its own variable.
* **Set `expected` when the answer has a shape** — `email`, `phone`, `order number` — so the
flow re-asks once instead of storing "I don't know".
* **End chat flows with `ai_respond` or `send_message`** — don't leave the visitor hanging on a
silent last step.
* **Test with real-looking data** — `run_tool` and `call_webhook` hit your real endpoints even
in test runs.
## Plans & limits
Flows require a **Pro plan** or higher. There's no limit on the number of flows per website.
Messages a flow sends don't consume your plan's message quota. See
[Billing & Plans](/user-guide/billing) for details.
## Related
The webhook tools a flow can call with `run_tool`.
Build the forms a `show_form` node embeds in chat.
What happens after a `request_human` node creates a ticket.
How the chat widget looks when a flow opens with your message.
# Forms
Source: https://docs.bubblav.com/user-guide/forms
Collect structured data from visitors through AI-powered forms
Forms let your chatbot collect structured data from visitors—like feedback, contact details, or survey responses—directly inside the chat. Instead of redirecting visitors to external pages, a flow presents the form at exactly the step you place it.
Forms are now part of **Flows**. The standalone Forms page redirects to the flows list —
create and edit forms inside a flow's `show_form` node, which shows the form in chat and
stores the submission in a variable. See [Flows](/user-guide/flows).
## How It Works
1. You **create or pick a form** inside a flow's `show_form` node
2. The form's **AI Instructions** become the intent of a companion `visitor_intent → show_form` flow that's created automatically — or you can place the form in any flow you build yourself
3. When a visitor message matches the intent, the form **appears in the chat** and the flow waits
4. The visitor **fills it out and submits** — the submission is stored in a variable you can pass to later nodes (webhooks, emails, tools)
The AI matches each visitor message against your AI Instructions (the companion flow's intent). Write clear, specific instructions so the form triggers at the right moment.
## Detected Forms
When BubblaV crawls your website, it detects lead and contact forms on your pages and imports each one with two flows: an **active companion flow** (`visitor_intent` built from the detected AI instructions → `show_form`) that shows the form in chat, and an **inactive notification flow** (`form_submitted` → team notification) you can activate in **Flows** (requires Pro). To keep things focused, at most **5 forms per website** are ever auto-imported; you can always create additional forms manually inside a flow's `show_form` node.
***
## Creating a Form
Go to **Dashboard** → select your website → **Flows**, open a flow (or create
one), and add a **Show form** node — its side panel lets you pick an existing form or
create a new one without leaving the editor.
Click the **Create form** button to open the form builder.
* **Name** (required): A clear name like "Product Review Form" or "Contact Request"
* **Description**: Brief text shown to visitors above the form
* **AI Instructions**: Tell the chatbot *when* to show this form (e.g., "Show when a visitor wants to leave a product review or feedback") — they become the intent of the form's companion flow
Click **Add Field** and configure each field's type, label, placeholder, and whether it's required. See [Field Types](#field-types) below for all options.
The live preview on the right shows how your form will look to visitors. Click **Create form** when you're done.
Write specific AI instructions. "Show when visitor asks about pricing or quotes" works better than "Show when needed."
***
## Field Types
Forms support 8 field types to cover most data collection needs:
| Type | Description | Use For |
| ---------------------- | --------------------------------- | ------------------------- |
| **Text** | Single-line text input | Names, short answers |
| **Email** | Email input with validation | Email addresses |
| **Number** | Numeric input | Quantities, ages |
| **Long Text** | Multi-line text area | Feedback, descriptions |
| **Dropdown** | Select one from a list | Categories, departments |
| **Radio Buttons** | Choose one option | Yes/No, ratings, choices |
| **Checkbox** | Single toggle (checked/unchecked) | Agreements, confirmations |
| **Rating (1-5 Stars)** | Star rating selector | Satisfaction scores |
### Field Configuration
Each field has:
* **Label** (required): The question or prompt shown to visitors
* **Type**: The input type from the list above
* **Placeholder**: Hint text inside the field (not available for Checkbox and Rating)
* **Required**: Whether the visitor must fill in this field before submitting
For **Dropdown** and **Radio Buttons**, you also configure a list of options that the visitor can choose from.
### Reordering Fields
Use the up/down arrows on each field to change the order. Fields appear to visitors in the order you set.
***
## AI Instructions
AI Instructions tell your chatbot when to display a form. Saving them creates (or updates) a
companion flow — a `visitor_intent` trigger using your instructions, wired to a `show_form`
node — so the wording is exactly what the intent matcher scores visitor messages against.
This is the most important part of form configuration—if the instructions are unclear, the
form won't surface at the right moment.
### Writing Good Instructions
* "Show when a visitor wants to leave a product review or feedback about their purchase"
* "Show when a visitor asks for a quote, pricing information, or wants to discuss custom plans"
* "Show when a visitor expresses interest in becoming a partner or reseller"
* "Show when a visitor wants to schedule a demo or consultation call"
* "Show when needed" (too vague)
* "Show form" (no context)
* "When customer" (incomplete)
You can create multiple forms per website, each with different AI instructions. The best-matching intent wins. Editing the instructions later updates the companion flow's intent automatically.
***
## Enabling and Disabling Forms
Forms are **enabled by default** when created, and there is no toggle in the dashboard — the
`bubblav_update_form` MCP tool can disable one. Disabling a form deactivates its companion
flow and makes any `show_form` node that references it fail at run time ("not found or
disabled"), so leave forms enabled.
***
## Viewing Submissions
Every form submission is stored. To see them, open the flow that uses the form, click the
`show_form` node, and click **View submissions** — a dialog lists the latest 50 submissions.
Each submission shows:
* All field values with their labels
* Formatted values (e.g., "4/5 stars" for ratings)
* Submission date and time
* Visitor ID and conversation ID
### Email Notifications
By default, you receive an email notification when a visitor submits a form. The email includes:
* Form name
* Website name
* All submitted field values
* A link to view the submission in your dashboard
***
## Sample Use Cases
### Product Reviews
Collect customer feedback with ratings and detailed reviews.
**Name**: Product Review
**AI Instructions**: "Show when a visitor wants to leave a review, feedback, or rate a product"
1. Text — "Product Name" (required)
2. Rating — "Overall Rating" (required)
3. Long Text — "Your Review" (required)
4. Text — "Reviewer Name"
***
### Quote Requests
Capture lead information when visitors ask about pricing.
**Name**: Request a Quote
**AI Instructions**: "Show when a visitor asks about pricing, quotes, custom plans, or wants to discuss business terms"
1. Text — "Full Name" (required)
2. Email — "Email Address" (required)
3. Text — "Company Name"
4. Dropdown — "Interest" (required): Sales, Support, Partnership, Other
5. Long Text — "Tell us about your needs" (required)
***
### Customer Support Tickets
Collect issue details before escalating to your support team.
**Name**: Support Ticket
**AI Instructions**: "Show when a visitor has a technical problem, wants to report a bug, or needs help that requires follow-up"
1. Text — "Full Name" (required)
2. Email — "Email Address" (required)
3. Dropdown — "Issue Type" (required): Billing, Technical, Account, Other
4. Text — "Order/Reference Number"
5. Long Text — "Describe the issue" (required)
***
### Event Registration
Sign visitors up for webinars or events.
**Name**: Event Registration
**AI Instructions**: "Show when a visitor wants to register for an event, webinar, workshop, or demo"
1. Text — "Full Name" (required)
2. Email — "Email Address" (required)
3. Text — "Company"
4. Number — "Number of Attendees"
5. Dropdown — "Session" (required): Morning, Afternoon, Evening
***
### Newsletter Signup
Collect email subscriptions directly in chat.
**Name**: Newsletter Signup
**AI Instructions**: "Show when a visitor wants to subscribe to the newsletter, get updates, or stay informed"
1. Text — "First Name" (required)
2. Email — "Email Address" (required)
3. Checkbox — "I agree to receive marketing emails" (required)
***
## Editing and Deleting Forms
### Edit a Form
Open the flow that uses the form, click the `show_form` node, and click **Edit form** — the
form builder opens in place and changes save automatically.
### Delete a Form
There's no delete button in the dashboard — use the `bubblav_delete_form` MCP tool instead.
Deleting a form also deletes all submissions for that form. Consider exporting important data before deleting.
***
## How Visitors Experience Forms
When a flow reaches a `show_form` step:
1. The flow sends a brief message (e.g., "I'd love to get your feedback! Please fill out this quick form:")
2. The form appears inline in the chat with all configured fields
3. The visitor fills in the fields and clicks **Submit**
4. Required fields are validated before submission
5. A success message confirms the submission
6. The conversation continues normally
Visitors never leave the chat—the entire experience happens inside the widget.
***
## Best Practices
3-5 fields is ideal. Long forms reduce completion rates.
Describe exactly when to show the form — they become the companion flow's intent. Vague instructions lead to missed triggers.
Only mark fields as required if you truly need the data. Optional fields increase completion rates.
Use the preview in the form builder and test via the chatbot to verify the experience.
***
## Troubleshooting
* Check the form is **enabled** — a disabled form deactivates its companion flow
* Review your **AI Instructions** — they are the companion flow's `visitor_intent`; make them more specific
* Test the phrasing in the flow editor's **Test** panel and check the intent-match score
* Ensure the form has at least one field
* Check if multiple forms have overlapping AI instructions — the best-matching intent wins
* Make each form's instructions distinct and specific to its purpose
* Open the flow, click the `show_form` node, and check **View submissions**
* Verify the form is enabled
* Check your email notifications settings
***
## Next Steps
Embed forms in scenarios with show\_form nodes
Connect your chatbot to external APIs
Escalate to live agents
Optimize your chatbot setup
# Getting Started
Source: https://docs.bubblav.com/user-guide/getting-started
Start your journey with BubblaV in minutes
Welcome to BubblaV! This guide will help you create your account, set up your first chatbot, and get it live on your website in under 10 minutes.
## What You'll Need
Before starting, have these ready:
* An email address (or Google account)
* Your website URL
* A few minutes of your time
***
## Step 1: Create an Account
Go to [bubblav.com/login](https://www.bubblav.com/login)
Pick your preferred option:
* **Email**: Enter email and create a password
* **Google**: One-click sign up with your Google account
If using email, check your inbox and click the verification link
You'll be redirected to your dashboard automatically
Using Google is fastest—no email verification needed.
***
## Step 2: Choose Your Plan
BubblaV offers plans for every business size:
| Feature | Free | Pro (\$49/mo) |
| --------------------------------------------- | ------------------ | ----------------------------- |
| **Messages/month** | 100 | 5,000 |
| **Pages crawled** | 50 | 5,000 |
| **Websites** | 1 | 5 |
| **Team members** | 1 | 3 |
| **Human handoff** | On visitor request | Yes (incl. AI intent routing) |
| **Email to visitors** | Yes | Yes |
| **Live Support** | - | Yes |
| **Flows** (smart triggers, forms, AI handoff) | - | Yes |
| **Custom Tools** | Yes | Yes |
| **Remove branding** | - | Yes |
| **Conversation retention** | 7 days | 1 year |
| **Annual billing** | - | \$39/month (save \$120/year) |
Start with the **Free** plan to test everything. The **Pro** plan includes a **14-day free trial**—full access during the trial, cancel anytime at no cost. Annual billing saves 20% on all paid plans.
### Upgrading Later
1. Click your **user avatar** in the top-right corner
2. Select **Subscription** from the menu
3. Click **Upgrade Plan**
4. Select your desired plan
5. Enter payment details
6. Your new limits apply immediately
***
## Step 3: Create Your First Website
From the dashboard, click **+ New Website**
The full URL of your site (e.g., `https://example.com`)
Your website is created and ready to configure. We'll automatically fetch your favicon and site name if available.
### What Happens Next
After creating your website:
1. **Automatic crawl begins**: BubblaV scans your website to learn about your business
2. **Knowledge base populates**: Content from your pages is indexed
3. **Widget is generated**: A unique embed code is created for you
Crawling typically takes 2-5 minutes depending on your website size. You can continue setup while it runs.
***
## Step 4: Setup Wizard
The setup wizard guides you through essential configuration:
### Crawl Status
Monitor your website crawl:
* **In Progress**: Pages are being scanned
* **Completed**: All pages indexed successfully
* **Errors**: Some pages couldn't be accessed
### Design Preview
Quick customization in the **Design** tab:
* Choose your **brand colors**
* Select a **position** (bottom-right or bottom-left)
* Customize **bot identity** (Name, Avatar, Welcome Message)
* Preview how it looks in real-time
### Installation Code
Get your embed code:
```html theme={null}
```
***
## Step 5: Test Your Chatbot
Before going live, test your chatbot:
Click **Design** in the sidebar to open the widget configuration and live preview.
Try questions your customers might ask:
* "What are your shipping options?"
* "How do I contact support?"
* "What products do you sell?"
Verify the answers are accurate and helpful
If answers are wrong, add content to your knowledge base
***
## Quick Start Checklist
Track your progress through setup:
Sign up and verify your email
Create your first website in the dashboard
Wait for your website content to be indexed
Customize colors and appearance to match your brand
Verify responses are accurate in preview mode
Add the widget code to your website
Confirm the widget appears on your live site
***
## Common First Steps
After basic setup, consider these enhancements:
### Improve AI Knowledge
Add PDFs, documents with detailed info
Add specific answers for common questions
### Customize Experience
Custom Instructions on the Behavior page
Match your brand colors and style
Website details, notifications, team access
### Connect Integrations
Connect for order lookups
Enable appointment booking
See all integrations
***
## Troubleshooting Setup
* Check your spam/junk folder
* Ensure you entered the correct email
* Request a new verification email
* Try signing up with Google instead
* Large websites take longer (100+ pages)
* Check if your site blocks bots (robots.txt)
* Try adding pages manually if crawl fails
* Refresh the page
* Clear browser cache
* Check browser console for errors
* Ensure JavaScript is enabled
* Review what content was crawled
* Add missing information via Q\&A entries
* Check "Content Gaps" for common unanswered questions
***
## Getting Help
Need assistance? Here's how to get help:
* **Documentation**: You're already here! Browse the guides.
* **Email Support**: Contact [support@bubblav.com](mailto:support@bubblav.com)
* **Live Chat**: Chat with our bot on [bubblav.com](https://www.bubblav.com)
Pro and Turbo plans include priority support with faster response times.
***
## Next Steps
Ready to continue? Here's what to do next:
Add the chatbot to your website
Add more knowledge for better answers
# In-Dashboard Help Assistant
Source: https://docs.bubblav.com/user-guide/help-assistant
Ask the BubblaV Assistant to configure your chatbot or update settings for you — without leaving your dashboard
Not sure how to set something up? The **BubblaV Assistant** is an inline help chat built into your dashboard. Ask how to configure your bot in any language you like, and get answers right where you're working — no need to open a separate tab or dig through docs. The assistant can also **update settings for you** — it doesn't just answer questions, it can make changes directly, so you don't have to hunt for the right toggle.
## Where to Find It
You can open the BubblaV Assistant from two places:
* The **Assistant** on the **Dashboard Home page** — available as soon as you log in.
* The **question-mark icon** in the workspace header on any website page.
On the Dashboard Home page. Or, inside a website page, click the question-mark icon in the top header.
Type in any language — ask how to configure something, or ask the assistant to update a setting for you.
For changes the assistant makes on your behalf, review the summary and confirm before it's applied.
The first time you open a website page, a small nudge points out the help icon. Dismiss it, or simply open the assistant — it won't show again.
## What to Ask (and Do)
The assistant is tuned for setup and configuration. It can both answer questions and apply changes, such as:
* "How do I make the bot collect leads?"
* "Add a review link to my chatbot."
* "Turn on lead collection for the 'Get Free Quote' button."
* "Connect my Google Business integration."
* "Update my chatbot's greeting message."
For the full mapping of common requests to setup steps, see [Make Your Bot Collect Leads, Quotes & Reviews](/user-guide/configure-bot-leads-quotes-reviews).
## How It Works
* The assistant opens as a **side panel** that stays in view as you scroll — your page remains visible alongside it.
* It's powered by the same BubblaV chatbot, answering from BubblaV's documentation and your setup.
* When you ask it to change a setting, it performs the update through the dashboard — no manual clicking required.
* Close it with the **X** or press `Esc`.
Think of it as a guided helper for the dashboard: ask where something is, how to enable a feature, or just tell it to make the change — then follow along in the same window.
## Credits
Each BubblaV account gets **100 free assistant credits per month**.
These assistant credits are **separate from your monthly message quota** — using the assistant does not count against the messages your chatbot uses with visitors.
When you run out of free credits for the month, the assistant will let you know and point you to alternative ways to get help until your credits reset on the first of the next month.
## Next Steps
Set up your first website
Common bot setup walkthroughs
# Human Handoff
Source: https://docs.bubblav.com/user-guide/human-handoff
Route conversations to your team with a visitor-intent flow
# Human Handoff
Route conversations to a human teammate when the visitor's intent calls for it — sales
inquiries, enterprise pricing, or anything you describe in natural language. Handoffs are
built as a **Flow**: a `visitor_intent` trigger that matches what the visitor asks, followed
by a `request_human` node that creates a live-support ticket for your team.
## Plan Availability
This feature is available on **Pro** plans.
## Setting Up a Handoff Flow
1. Navigate to **Flows** in your dashboard and click **New Flow**
2. Pick the **Visitor intent** trigger and describe when to hand off in natural language —
e.g. "wants to speak to sales" or "asks about enterprise pricing"
3. Add a **Request human** node and set its **message** — shown to the visitor while they
wait (required)
4. Optionally add `collect_input` nodes before the handoff to gather the visitor's email,
name, or order number first
5. Test the flow in the editor's **Test** panel, then switch it to **Active**
## Example Intents
### Sales Inquiries
* "When someone asks about enterprise pricing"
* "Custom integration or development requests"
* "Partner or reseller inquiries"
### Support Issues
* "Technical support requests"
* "Billing or account issues"
* "Feature requests or custom development"
## How It Works
When a visitor sends a message:
1. **Intent Matching**: the AI scores the message against each active `visitor_intent` flow
2. **Match Detection**: the best match above the threshold runs the flow
3. **Info Collection**: optional `collect_input` nodes ask for email, name, or details
4. **Ticket Created**: the `request_human` node opens a live-support ticket
5. **Team Notified**: teammates are notified per their notification preferences
## Best Practices
### Be Specific
* Good: "When someone asks about enterprise pricing plans"
* Poor: "pricing questions"
### Use Natural Language
* Good: "Partner or reseller partnership inquiries"
* Poor: "partner"
### Review Content Gaps
Check the **Knowledge** > **Insights** > **Content Gaps** tab to see what questions visitors
ask that the AI struggles with. These may be good candidates for handoff flows.
## Related
The visual builder where handoff automations live.
The inbox where handoff tickets land.
# Installation
Source: https://docs.bubblav.com/user-guide/installation
Add the chatbot widget to your website
Install BubblaV on any website in minutes. Choose your platform for step-by-step instructions.
## Using AI Builders (Lovable, v0, Bolt, Cursor)
Building with an AI-powered tool? Copy the prompt below and paste it directly into your AI builder to integrate BubblaV automatically.
This works with Lovable, v0, Bolt, Cursor, Windsurf, and any other AI coding assistant.
```text expandable theme={null}
Add the BubblaV AI chatbot widget to this project.
**Option 1: NPM Package (Recommended for React, Vue, Angular)**
Install:
React: npm install @bubblav/ai-chatbot-react
Vue: npm install @bubblav/ai-chatbot-vue
Angular: npm install @bubblav/ai-chatbot-angular
Import and add to your root component or layout:
React — import { BubblaVWidget } from '@bubblav/ai-chatbot-react';
Vue — import { BubblaVWidget } from '@bubblav/ai-chatbot-vue';
Angular (standalone) — import { BubblaVWidgetComponent } from '@bubblav/ai-chatbot-angular';
Add BubblaVWidgetComponent to the component's imports array, then:
IMPORTANT — For Vite-based projects (Lovable, Bolt, v0, plain Vite), add this to
vite.config.ts to prevent duplicate-React conflicts:
resolve: { dedupe: ['react', 'react-dom'] }
**Option 2: Script Tag (fallback — works with any framework)**
Add this before