@bubblio/widget
v0.11.1
Published
Embeddable real-time AI customer-service character widget — drop into any React app in 5 lines of code.
Maintainers
Readme
@bubblio/widget
Embeddable support-teammate widget for Bubblio — customer service for humans and the agents they send. A floating bubble that opens into a chat teammate; with the optional Face add-on it becomes a live video character (Runway, Tavus, or Anam, via the runway-webrtc, daily-webrtc, and anam-webrtc transports — at zero video minutes the widget continues as text chat). Talks to your backend via @bubblio/server.
Guides: script-tag embed · Next.js install
npm install @bubblio/widget @runwayml/avatars-react react react-domPeer dependencies:
react >= 18,react-dom >= 18,@runwayml/avatars-react >= 0.14.
Install 0.10.3 or newer. The character's
show_link_card/set_animation_statearguments are model-generated, so they are reachable from anything that gets text into your knowledge base. 0.10.3 filters both: link-card URLs must behttp://orhttps://(anything else renders nothing rather than an href in your page's origin), and an unknown animation state renders nothing rather than throwing during render. On the default Runway transport these events go straight from the provider to the browser, so the widget is the only layer that can filter them — a lockfile pinned to<= 0.10.2stays exposed no matter which platform version you run. Script-tag embedders on a major-version CDN URL (@0.11, or@0.10at0.10.3+) float to the fix automatically.
Quickstart
import { BubblioWidget } from '@bubblio/widget'
export default function App() {
return (
<BubblioWidget
config={{
name: 'Aria',
character: '/aria.png',
serverUrl: '/api/bubblio/session',
}}
/>
)
}serverUrl is your own backend route that returns the session JSON from createBubblioSession — { sessionId, provider, transport, events, … } (plus sessionKey on Runway). Pair it with @bubblio/server:
// app/api/bubblio/session/route.ts
import { createBubblioSession } from '@bubblio/server'
export async function POST() {
const session = await createBubblioSession({
bubblioApiKey: process.env.BUBBLIO_API_KEY!,
personality: 'Help the customer.',
// optional: characterId from your Characters page
})
return Response.json(session)
}That's it. The widget renders a floating bubble; clicking it opens the live character panel and starts a WebRTC connection. Closing the panel ends the session.
No React? One script tag.
Plain HTML, Webflow, Wix — drop this anywhere (Webflow/Wix users: paste it into a custom-code block):
<script defer
src="https://cdn.jsdelivr.net/npm/@bubblio/[email protected]/dist/embed.global.js"
data-server-url="https://yoursite.com/api/bubblio/session"></script>The bubble auto-mounts on DOM ready. Configure it with data-* attributes:
| Attribute | Maps to |
| --- | --- |
| data-server-url | serverUrl (required for auto-mount) |
| data-name | name |
| data-character | character |
| data-primary-color | theme.primaryColor |
| data-accent-color | theme.accentColor |
| data-dot-color | theme.dotColor |
Prefer to configure from JavaScript? Set window.bubblioConfig before the embed script tag (inline scripts run before defer scripts, so this ordering is always safe — including in Webflow/Wix custom-code blocks) and omit data-server-url:
<script>
window.bubblioConfig = { serverUrl: 'https://yoursite.com/api/bubblio/session' }
</script>
<script defer src="https://cdn.jsdelivr.net/npm/@bubblio/[email protected]/dist/embed.global.js"></script>For full runtime control there's also a global API — note it only exists once the embed script has loaded (call it from the script tag's load event or a later user interaction, never from an inline script above it):
window.Bubblio.init({ serverUrl: 'https://yoursite.com/api/bubblio/session' })
// later:
Bubblio.destroy()The embed is a single self-contained file (~300 KB gzipped) that loads deferred. React is not required on the page — and if the page already has React, nothing clashes: everything is bundled and scoped inside the script.
Persistence across navigation
Mount <BubblioWidget /> once in your root layout so the session survives page transitions. Mounting inside a page component will tear down and restart the session every time the user navigates.
// app/layout.tsx (Next.js App Router)
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<BubblioWidget config={{ name: 'Aria', character: '/aria.png', serverUrl: '/api/bubblio/session' }} />
</body>
</html>
)
}Theming
<BubblioWidget
config={{
name: 'Aria',
character: '/aria.png',
serverUrl: '/api/bubblio/session',
theme: {
primaryColor: '#0066ff',
dotColor: '#0066ff',
},
}}
/>| Field | What it styles |
| --- | --- |
| primaryColor | Retry button, default bubble color |
| dotColor | Floating trigger bubble color (defaults to primaryColor) |
| accentColor | Reserved for future use |
Client events
The character can fire two built-in client events to drive your UI:
set_animation_state — Switch a visual state in the widget. The character should call this just before any tool call, then idle once the result is back. States: idle, searching, creating, found, analyzing, linking, closing.
show_link_card — Render a clickable link card inside the panel. Useful for directing the user to a specific page.
{ name: 'show_link_card', args: { title: 'Your dashboard', url: '/dashboard' } }Both events are registered automatically by the platform — you just need to mention them in the character's personality prompt so it knows when to use them.
API
<BubblioWidget config={config} />
interface BubblioConfig {
name?: string // shown in panel header (default: 'Assistant')
character?: string // portrait image URL or path (default: built-in Bubblio mark)
serverUrl: string // your backend endpoint that returns the Bubblio session JSON
theme?: {
primaryColor?: string
accentColor?: string
dotColor?: string
}
}
type AnimationState =
| 'idle' | 'searching' | 'creating' | 'found'
| 'analyzing' | 'linking' | 'closing'
interface LinkCard {
title: string
url: string
description?: string // optional — renders without a description when omitted
}License
MIT. See LICENSE.
