Facade loader
RecommendedRenders the chat bubble in ~2 KB. The full bubuu-chat.js bundle preloads in the background and is promoted on click or hover.
A 2 KB facade that paints on first frame. The full widget streams in behind it. Embedded into any page, framework, or CMS in two lines of HTML.
Bubuu's lead widget is a Custom Element — <bubuu-chat> — that drops a guided real-estate conversation into any page. It mounts inside a Shadow DOM, inheriting none of the host site's CSS and leaking none of its own. No frameworks to align, no global styles to fight.
The widget ships in two halves. A 2 KB loader renders the chat bubble on first paint; the full bundle preloads in the background and takes over on click. Visitors on cold connections still see the bubble before the page finishes settling.
Two scripts, one element. Drop the loader on every page where the widget should be reachable; the chat bubble renders immediately and the full widget streams in behind it.
Renders the chat bubble in ~2 KB. The full bubuu-chat.js bundle preloads in the background and is promoted on click or hover.
Use this when the page is a conversion target and you want the widget interactive on first paint. Ships the full ~210 KB bundle up-front — skip if you care about Core Web Vitals on cold visits.
Two scripts, in sequence. The loader is tiny enough to be inlined on every page; the widget is large enough that you would not want it on every page. The facade pattern lets both be true.
bubuu-loader.js
~2 KB over the wire
bubuu-chat.js
~210 KB over the wire
Loader registers the element
bubuu-loader.js defines <bubuu-chat> as a 2 KB facade and renders a chat bubble inside a Shadow DOM. The full bundle starts preloading immediately.
Bubble paints on first frame
No framework boot, no hydration cost. The bubble is a single button with inline styles, so it shows up even on cold cache and slow connections.
Visitor opens the chat
On hover, the preloaded widget bundle is already cached. On click, the cached bundle is promoted from background to foreground.
Widget takes over in place
The full widget upgrades the same DOM node, inheriting every attribute you set on it. The conversation opens immediately — visitors never see a second click.
Every option is a plain HTML attribute on <bubuu-chat>. Set them once in the markup or change them at runtime with element.setAttribute(…). Attributes flagged reactive re-render the widget without losing chat state.
Identifies your account on the Bubuu backend. Every chat and lead created by this instance is attributed to this partner.
Resumes an existing conversation by its server-issued ID. When omitted, a new chat is created on the first user message. Useful for deep-linking back into a previous session from email or a CRM.
UI language. Changing this at runtime swaps the locale without clearing messages — the conversation continues in the new language.
Color scheme. auto follows the host page's prefers-color-scheme and reacts to system theme changes. The widget runs inside a Shadow DOM, so this never affects host styles.
ISO country or region code used to pick locale-specific copy, phone formats, and address parsers. Defaults to the partner's configured region when absent.
Override the agent avatar shown next to assistant messages. Falls back to the partner's brand avatar when omitted.
Page, visitor, and metadata context for the AI as a JSON object — { page, visitor, metadata }. Sent with every message so answers stay grounded in what the visitor is viewing. Malformed JSON is ignored with a console warning; the widget still loads. For objects from JS or a framework, prefer the context property or setContext() — see Context.
Tell the AI what the visitor is looking at. Attach page, visitor, free-form metadata, and the page content itself, and the widget sends it on every message, so the assistant grounds its answers in the exact listing on screen and can pre-fill lead capture. Context rides the existing chat channel — no extra requests, and it survives the facade→full-widget upgrade.
What the visitor is viewing. Auto-derived from the host page (location.href, document.title, document.referrer) when you omit it; anything you pass wins per field.
Known visitor identity. Used to pre-fill the lead form. user is accepted as a friendly alias for visitor.
Free-form key/value bag. Put listing identifiers here — listingId, an OpenImmo or RESO ref, price, location — and the backend resolves them into the matched property. Values are coerced to strings; the backend sanitizes and size-limits them.
The page content the AI should read, handed straight to the backend so it can skip scraping the page. Pass a string (treated as the body) or { body, type }, where type is a format hint (e.g. markdown vs HTML). Omit it to let the backend fetch the page itself.
Use the context attribute for static, server-rendered markup; the context property to bind an object (it replaces the current context); and setContext(patch) to merge a partial update at runtime. getContext() returns the current value. All three reach the same place. Malformed JSON in the attribute is ignored with a console warning — the widget still loads.
Frameworks bind objects to the element's context property. React 19, Vue, Angular, Svelte, and Preact all do this for you. React 18 and below stringify object props, so reach for a ref and call setContext() instead.
Timing is automatic: context set before the chat opens lands on the first message, and an update pushed mid-session applies to the next one. setContext merges, so when the page changes (e.g. SPA navigation) send the new pageContent in full — a partial patch keeps the previous page's body. Updating context never clears the thread or drops the connection — it behaves like the reactive lang and theme attributes. The widget only reads window and document; it adds nothing to the host's global scope.
The widget paints inside a Shadow DOM — host styles can't bleed in, widget styles can't bleed out. Click a mode to retheme the live widget; the switch lands in place, no reload.
Pick a locale to flip the live widget. UI strings re-render in place — the chat thread, the open WebSocket, and scroll position survive the switch.
A few patterns that cover most production embeds. Each one stands on its own — copy, swap in your IDs, ship.
<bubuu-chat> is a standard Custom Element. Load the loader once, then render the tag anywhere — React, Vue, Svelte, Angular, or plain HTML all treat it as a native element.
Drop the visitor straight back into their last conversation. Pass chat-id when linking from email follow-ups or saved-search alerts and the widget restores the thread.
On a listing page, push the property the visitor is viewing. The assistant answers about that listing and the lead is saved with it. Re-run setContext whenever the listing changes — the thread and connection stay put.