Embed codes
Every embed option lives in Dashboard → Widget Designer → Widget embed codes: pick a placement (floating bubble or inline chat block) and the panel generates the snippet with your store ID already filled in. This page explains what each variant is and where to paste it.
- Open
Widget Designerand scroll to the embed codes panel. - Pick the placement - the floating bubble for storefront-wide chat, or an inline chat block for a dedicated page. The JS loader always renders the floating bubble; inline blocks use the iframe or the WordPress shortcode.
- For the bubble, copy the JS loader - it auto-updates when you change branding in the designer, because the loader is generated per-store on request.
- Paste it into your site’s footer (before
</body>) and publish.
Is the widget key safe to expose?
Plain HTML / vanilla site
One script tag. The per-store loader has your key and branding pre-baked, so there’s nothing else to configure:
<script
src="https://app.zubbyai.com/widget/loader/YOUR_STORE_ID.js"
defer
></script>The loader renders a lightweight launcher button and only creates the chat iframe when a shopper clicks. This reduces initial work, but performance still depends on your theme, scripts, device and network. Measure your storefront before and after installation.
Shopify
Use the theme App Embed - covered in Embed the widget on Shopify. Enable it in the theme editor; its settings let you set the widget key, color, position, greeting, launcher label, and a floating vs. inline display mode. No code edits needed. The App Embed also wires up Shopify-only extras: verified customer login (the AI greets logged-in shoppers by name) and native add-to-cart from chat.
WooCommerce
The plugin injects the floating bubble automatically via wp_footer - no snippet needed. Plugin settings include per-page visibility toggles (hide on checkout is on by default). For an inline chat block inside a page or post, add the shortcode; the plugin renders it with its own connected store and widget key, so it takes no attributes:
[zubby_ai]Webflow / Squarespace / Wix
Paste the JS loader snippet into the site-wide footer code area: Webflow - Site Settings → Custom code → Footer Code; Squarespace - Settings → Advanced → Code Injection → Footer; Wix - Settings → Custom Code → Body end. Note that some free plans don’t allow custom code.
Next.js / React / any SPA
The loader works as a plain script tag in any framework. In Next.js, drop it in your root layout with strategy="afterInteractive":
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://app.zubbyai.com/widget/loader/YOUR_STORE_ID.js"
strategy="afterInteractive"
/>
</body>
</html>
);
}For SPAs that want a real DOM element instead of an injected script, use the <zubby-widget> web component - it renders an accessible, keyboard-focusable launcher in shadow DOM and lazy-loads the chat iframe on open:
<script src="https://app.zubbyai.com/widget-element.js" defer></script>
<zubby-widget
store-id="YOUR_STORE_ID"
widget-key="YOUR_WIDGET_KEY"
app-base="https://app.zubbyai.com"
primary-color="#3B82F6"
position="bottom-right"
></zubby-widget>Inline chat blocks
Outside WordPress, an inline chat block is the iframe variant from the embed panel - an iframe pointing at your hosted widget. Shoppers tap the chat button inside the block to start a conversation. The widget reads your current key server-side, so the snippet carries no key:
<!-- Zubby AI · inline chat block -->
<iframe src="https://app.zubbyai.com/widget/YOUR_STORE_ID?mode=inline"
style="width:100%; min-height:600px; border:0; border-radius:16px;"
loading="lazy"
title="AI assistant"></iframe>There is no auto-popup or full-page embed mode. Timed or exit-intent offer popups are configured in the Widget Designer and shown by the JS loader itself.
Listening for widget events
The web component dispatches host-page CustomEvents your own code can react to:
const widget = document.querySelector("zubby-widget");
widget.addEventListener("zubby:open", () => console.log("chat opened"));
widget.addEventListener("zubby:close", () => console.log("chat closed"));
// Fired when the AI adds a product to the cart on a non-Shopify site -
// detail carries the variant/product so your storefront code can act on it.
widget.addEventListener("zubby:cart_add", (e) => console.log(e.detail));Verify the embed
After publishing, open your storefront and check:
- The launcher renders on an eligible page after the loader runs.
- Clicking it opens the chat panel (in DevTools → Network you’ll see the
/widget/YOUR_STORE_IDiframe load on first click). - Sending a test message gets an AI reply -
/api/v1/widget/chatreturns 200.
Anything off? See Widget not loading.
Custom cart event contract
The web component emits zubby:cart_add with { variantId, productTitle, quantity }. Your adapter must validate that variant against your catalog and call your own cart API. Receiving the event is not proof that an item was added. Handle failures visibly, update the cart only after your API succeeds, and remove listeners when a framework component unmounts. Custom stores otherwise use product links; Zubby does not provide a universal custom checkout writer.
Inline iframes and the web component have different mounting behavior from the lazy launcher. Measure the actual placement you use. Verify keyboard and touch access, a slow network, any consent gate and your storefront’s performance metrics after adding it.