docs · script-tag embed

The bubble on any website.
No React. No build step.

One script tag puts a live AI video character on plain HTML, Webflow, Wix — anywhere you can paste custom code. It talks to a tiny endpoint on your server, so your Bubblio API key never touches the browser.

How it works

  1. 1
    The script tag renders the bubble.
    One deferred ~290 KB gzipped file from a CDN, with the whole widget (and its own React) bundled inside. It floats over the page and stays idle — an idle bubble costs nothing.
  2. 2
    A click calls your session endpoint.
    The widget POSTs to the data-server-url you configured. That endpoint runs on your server, holds your secret API key, and asks Bubblio for a session — with whatever personality, character, and tools you define.
  3. 3
    The browser connects to the character.
    Your endpoint returns short-lived, single-session credentials. The widget opens a WebRTC connection to the avatar provider Bubblio chose — Runway, Tavus, or Anam, with automatic failover — and your visitor is talking to a person.

Step 1 — Create your session endpoint

A few lines on your backend (any host: Vercel, a VPS, a Lambda). Grab an API key from the dashboard first. If your website and this endpoint live on different domains — always the case for Webflow/Wix — include the CORS header shown below.

route.ts
import { createBubblioSession } from '@bubblio/server'// POST /api/bubblio/session — runs on YOUR server.// Your Bubblio API key never reaches the browser.export async function POST() {const session = await createBubblioSession({bubblioApiKey: process.env.BUBBLIO_API_KEY,personality: 'You are Aria, support agent for Acme.',})return Response.json(session, {// Webflow/Wix sites live on another domain — allow them in:headers: { 'Access-Control-Allow-Origin': 'https://yoursite.com' },})}

Step 2 — Paste the script tag

Point data-server-url at the endpoint from step 1. Prefer configuring from JavaScript? Use the second tab — set window.bubblioConfig in an inline script above the embed tag (inline scripts run before defer’d ones, so that order is always safe).

index.html
<!-- Before </body>. That's the whole integration. --><script defersrc="https://cdn.jsdelivr.net/npm/@bubblio/widget@0.4/dist/embed.global.js"data-server-url="https://yoursite.com/api/bubblio/session"data-name="Aria"></script>
data-* reference
data-server-urlserverUrlYour session endpoint (step 1). Required for auto-mount.
data-namenameName in the widget header. Default: “Assistant”.
data-charactercharacterPortrait image URL. Default: the Bubblio mark.
data-primary-colortheme.primaryColorButtons and accents. Default: #1b77fd.
data-accent-colortheme.accentColorSecondary accent.
data-dot-colortheme.dotColorThe floating bubble. Defaults to the primary color.

After the script loads there’s also a runtime API for single-page flows: window.Bubblio.init(config) / Bubblio.destroy(). Call it from the script tag’s load event or a user interaction — never from an inline script above the tag (it hasn’t loaded yet there).

Platform guides

Plain HTMLany hosting
  1. Paste the tag right before </body> on every page that should show the bubble.
  2. Done — defer means it never blocks your page render.
Webflowpaid site plan (custom code)
  1. Site settings → Custom code → Footer code, paste the tag.
  2. Use Page settings → Custom code instead if you only want it on some pages.
  3. Publish. Custom code does not run in the Designer preview — check the published site.
WixPremium + connected domain (custom code)
  1. Settings → Advanced → Custom Code → “+ Add Custom Code”.
  2. Paste the tag, apply to All pages, place in Body — end.
  3. Publish and view the live site.
Heads-up: Do not use the drag-in “Embed HTML” element — it sandboxes code into an iframe, so the bubble gets clipped to that little box instead of floating over the page.
Squarespace, Framer, Shopify…varies
  1. Any builder that injects raw HTML into the page works: Squarespace Code Injection (footer), Framer custom code (end of <body>), Shopify theme.liquid before </body>.
  2. Rule of thumb: page-level code injection works; iframe-sandboxed “embed” widgets don’t.

Troubleshooting

The bubble doesn’t appear.
Open the browser console and look for [Bubblio] messages — the embed warns instead of crashing. Check that data-server-url is present (without it the script waits for window.bubblioConfig or Bubblio.init). If your site sends a Content-Security-Policy, allow scripts from cdn.jsdelivr.net and inline styles (the widget injects one <style> tag for its animations).
The panel opens but shows an error and a Retry button.
That is your session endpoint failing — the widget surfaces the JSON error field from any non-200 response. Test it directly: curl -X POST your endpoint URL. The most common cause on Webflow/Wix is a missing Access-Control-Allow-Origin header for your site’s domain (your endpoint lives elsewhere, so the browser enforces CORS).
Will it clash with my page’s JavaScript or CSS?
No. Everything — React included — is bundled and scoped inside the script; the widget styles itself inline and floats above the page (it does not need or touch your page’s React, if any). It’s one ~290 KB gzipped file, loaded with defer so it never blocks rendering.
Calling window.Bubblio.init() throws “Cannot read properties of undefined”.
Inline scripts run before defer’d scripts, so window.Bubblio doesn’t exist yet at that point. Use window.bubblioConfig (see above) — it’s built for exactly this — or call Bubblio.init() from the script tag’s load event or a later user interaction.
Which avatar provider does a session use?
Bubblio picks a healthy provider (Runway, Tavus, or Anam) when the visitor connects and fails over automatically if one is down. The embed handles all three transports — nothing to configure on the page.
Give your character hands, not just a face.
The same session endpoint can register tools — signed callbacks into your backend so the character can look up orders, book appointments, or hand off to a human.
Request accessServer SDK docs ↗