Medusa 2.0 plugin to integrate Chat Widget for seller/buyer communication

- Easy Integration
- Simple script to copy-paste on your website, no coding required
- No need to handle backend infrastructure — ConnectyCube takes care of it
- Superior feature set
- Not just another basic chat widget - it's a complete chat system!
- Customizable UI
- Modify colors, themes, and layout to match your brand’s design
- Real-time Messaging
- Smooth, instant communication with no delays
- Moderation tools
- Keep chats safe with message filtering, user bans, and admin controls
- Multimedia support
- Send images, files, and emojis for richer conversations
-
Add plugin to your Medusa 2.0 core app:
yarn add @connectycube/chat-widget-medusa-plugin
-
Create ConnectyCube account https://connectycube.com/signup and application, obtain credentials:

Also, go to Chat -> Custom Fields and create a new custom field called externalId
:

-
Add the following variables to your
.env
file:VITE_BACKEND_URL=http://localhost:9000 VITE_CHAT_APP_ID=<YOUR CONNECTYCUBE APP ID> VITE_CHAT_AUTH_KEY=<YOUR CONNECTYCUBE AUTH KEY>
VITE_BACKEND_URL
- The URL of your Medusa backend, required for custom admin components.VITE_CHAT_APP_ID
- This is essential for authenticating your application with the ConnectyCube platform and accessing its chat services.VITE_CHAT_AUTH_KEY
- This key is used to authorize your application and ensure secure communication with the ConnectyCube SDK.
-
Add the following code to your
medusa-config.ts
file:module.exports = defineConfig({ admin: { vite: (config) => { config.define["__VITE_CHAT_APP_ID__"] = JSON.stringify(process.env.VITE_CHAT_APP_ID); config.define["__VITE_CHAT_AUTH_KEY__"] = JSON.stringify(process.env.VITE_CHAT_AUTH_KEY); return { optimizeDeps: { include: ["qs", "eventemitter3", "@xmpp/iq/callee", "@xmpp/resolve", "@xmpp/session-establishment", "@xmpp/client-core", "@xmpp/sasl-plain", "@xmpp/stream-features", "@xmpp/resource-binding", "@xmpp/reconnect", "@xmpp/middleware", "@xmpp/sasl-anonymous", "@xmpp/websocket", "@xmpp/iq/caller", "@xmpp/sasl"], // Will be merged with config that we use to run and build the dashboard. }, }; }, }, projectConfig: { ... }, plugins: [ { resolve: "@connectycube/chat-widget-medusa-plugin", options: {}, }, ], })
This code connect plugin and helps to resolve an issue similar to medusajs/medusa#11248.
-
Start the project:
yarn dev
-
Add chat widget to your Storefront app:
yarn add @connectycube/chat-widget
-
Add the following variables to your
.env
file:NEXT_PUBLIC_CHAT_APP_ID=<YOUR CONNECTYCUBE APP ID> NEXT_PUBLIC_CHAT_AUTH_KEY=<YOUR CONNECTYCUBE AUTH KEY> NEXT_PUBLIC_STORE_ID=<YOUR MEDUSA STORE ID> NEXT_PUBLIC_STORE_NAME=<YOUR MEDUSA STORE NAME>
-
Create
src/ChatWidget.tsx
component with the following content:"use client" import React, { useEffect, useState } from "react" import ConnectyCubeChatWidget from "@connectycube/chat-widget/react19" import { StoreCustomer, StoreProduct } from "@medusajs/types" export interface ChatWidgetProps { customer: StoreCustomer | null product: StoreProduct chatPerProduct?: boolean } export default function ChatWidget({ customer, product, chatPerProduct, }: ChatWidgetProps) { const quickActions = { title: "Quick Actions", description: "Select an action from the options below or type a first message to start a conversation.", actions: [ "Hi, I'm interested in this product.", "Can you tell me more about the price and payment options?", "Is the product still available?", "Can I schedule a viewing?", ], } if (!customer) { return null } const [defaultChat, setDefaultChat] = useState<any>(null) const [isOpen, setIsOpen] = useState<boolean>(false) const onOpenCloseWidget = (isOpen: boolean) => { setIsOpen(isOpen) } const storeId = process.env.NEXT_PUBLIC_STORE_ID const storeName = process.env.NEXT_PUBLIC_STORE_NAME useEffect(() => { if (isOpen) { console.log("Widget is open:", isOpen) const defaultChatKey = chatPerProduct ? product.id : storeId const defaultChatName = chatPerProduct ? product.title : storeName setDefaultChat({ id: defaultChatKey, opponentUserId: storeId, type: "group", name: defaultChatName, }) } }, [isOpen]) return ( <div> <ConnectyCubeChatWidget // credentials appId={process.env.NEXT_PUBLIC_CHAT_APP_ID} authKey={process.env.NEXT_PUBLIC_CHAT_AUTH_KEY} userId={customer.id} userName={`${customer.first_name} ${customer.last_name}`} // settings showOnlineUsersTab={false} splitView={true} // quick actions quickActions={quickActions} // notifications showNotifications={true} playSound={true} // moderation enableContentReporting={true} enableBlockList={true} // last seen enableLastSeen={true} // url preview enableUrlPreview={true} limitUrlsPreviews={1} // attachments settings attachmentsAccept={"image/*,video/*,.pdf,audio/*"} // default chat defaultChat={defaultChat} onOpenChange={onOpenCloseWidget} /> </div> ) }
-
update
tsconfig.json
:{ "compilerOptions": { "module": "nodenext", "moduleResolution": "nodenext", ... } }
-
update
storefront/src/app/[countryCode]/(main)/products/[handle]/page.tsx
to retrieve customer info and pass it toProductTemplate
:const customer = await retrieveCustomer() return ( <ProductTemplate product={pricedProduct} region={region} countryCode={params.countryCode} customer={customer} /> )
-
Finally, connect
ChatWidget
component on product details page, e.g.src/modules/products/templates/index.tsx
<ChatWidget customer={customer} product={product} chatPerProduct={true} />
The complete demo app (backend + storefront) available https://github.com/ConnectyCube/chat-widget-medusa-plugin-demo-app
On storefront, once logged in and opened product page, there will be a Chat toggle button bottom right:

Once clicked, a chat with seller will be opened where you can ask any product's related questions:

From Medusa dashboard there will be a new page called Chat, with the widget embedded, where all customers' chats are displayed, so you as a merchant can reply:

Join our Discord for quick answers to your questions or file a GitHub issue
- Blog
- X (twitter)@ConnectyCube
Apache 2.0