1. Load the widget
Inject the widget script dynamically once the page has loaded:2. Expose the cart
Tell the widget which cart the shopper is using by settingwindow.__totebotMedusa and dispatching totebot:medusa-cart. cartId is not a value you hard-code — read it from wherever your storefront keeps the shopper’s current cart (a cookie, your cart store, localStorage, etc.). Leave it undefined when the shopper has no cart yet; the agent creates one on first add and hands it back via the totebot:medusa-cart-adopt event (step 3).
Push on load, and again whenever your cart changes so the agent always sees the latest cart. The lines marked YOU: are where you plug in your own cart logic — Totebot can’t know how your storefront stores its cart.
3. Live refresh & cart bootstrap
When the agent (or an in-chat add) changes the cart, the write happens on Totebot’s backend (out-of-band from the shopper’s browser), so your storefront’s mini-cart would otherwise stay stale. Totebot pushes two browser events to close that gap — handle both in your storefront (see the complete examples):-
totebot:medusa-cart-refresh— fired after any cart write. Re-read your cart and re-render your mini-cart. This is the Medusa analog of WooCommerce’swc_fragment_refresh. Example: the shopper’s mini-cart says “2 items”; they ask the agent to add a tee; the icon updates to “3 items” without a reload. The rule: if your storefront reads the cart through a server-side cache that isn’t auto-invalidated on out-of-band writes, you must bust that cache in this handler — otherwise repeat writes to the same cart stay stale. If your storefront fetches the cart fresh each time (most client-side/SPA setups), there’s no cache to bust — just re-fetch and re-render. Concretely: the Next.js starter reads the cart with aforce-cachetagged fetch, sorouter.refresh()alone is not enough — it also needs arevalidateTagserver action (totebotRevalidateCart, shown in the Next.js example). Remix →revalidator.revalidate(); Nuxt/SvelteKit → re-run the cart load; a plain SPA → just re-fetch. -
totebot:medusa-cart-adopt(carries the newcartId) — fired when the agent created a cart while the shopper had none. Persist the new cart id as the shopper’s cart (cookie / your cart store) so your own mini-cart and checkout point at the agent’s cart instead of an empty one.
4. Complete examples
Each example implements steps 2 and 3 in one place — pushing the cart out and reacting to the agent’s events — because a real bridge does both. They are illustrative: the helpers in commented blocks (getCartId, fetchCart, renderMiniCart, …) stand in for your storefront’s real cart code. Swap them for yours; the Totebot-facing parts (window.__totebotMedusa, the event names, the dispatch) stay exactly as written.
- Next.js starter
- React SPA (non-Next.js)
- Vanilla JS
On the official Medusa Next.js starter the cart id lives in an httpOnly cookie, so you read it server-side in the layout and pass it to a small client bridge component. Adoption uses a server action because only the server can write that cookie.
src/app/layout.tsx:src/modules/totebot/totebot-adopt-cart.ts (adopts the agent’s cart and busts the starter’s cart cache):src/modules/totebot/totebot-medusa-bridge.tsx:Notes
- Checkout URL on the Medusa Next.js starter: the starter’s
/checkoutpage renders nothing until it knows which step to show — it hangs on a “Shipping Address” spinner without astepquery param (its own checkout button always adds one). SetcheckoutUrltohttps://your-store.com/<region>/checkout?step=address, not…/checkout. Custom storefronts: pointcheckoutUrlat whatever URL actually renders your checkout. - The two
totebot:medusa-cart-*events are framework-agnostic — Totebot only dispatches plain DOM events. How you react is up to your stack: Next.js needsrevalidateTag+router.refresh()(shown above); Remix usesrevalidator.revalidate(); Nuxt/SvelteKit re-run the cart load; a plain SPA just re-fetches the cart. Only the handler is stack-specific, never the Totebot side. - In a SPA that mutates the cart without navigation, dispatch
totebot:medusa-cartafter your own cart ops so the widget picks up changes. - Region: the agent binds every new cart to a region (currency/tax/shipping). On a starter storefront you need nothing — Totebot derives the region from the
/<countryCode>/segment of the page URL (matched against your/store/regions). Custom storefronts that don’t carry a country in the URL may setregionIdonwindow.__totebotMedusaso the agent bootstraps the cart in the right region; otherwise it falls back to your store’s first region. publishableKeyis public by design (safe to expose client-side).- Only the server can write the httpOnly
_medusa_cart_idcookie, so adoption uses a server action (Next.js example). Totebot can’t write your cart cookie from another origin — it can only tell your storefront which cart to adopt.