Embed the Maison concierge chat widget in a React application using a reusable component that handles script loading and cleanup via useEffect. React official site ↗
Prerequisites
- React 16.8+ (hooks support required)
- Your Client UUID — find it in the Business Console under Settings
- A client-side rendering context (not SSR — see note below)
Steps
Create the MaisonChat component
Create a new file
MaisonChat.tsxin your components folder. The component injects the bundle script on mount and removes it on unmount, so it is safe to use in a component tree.tsximport { useEffect } from 'react'; export function MaisonChat({ clientId }: { clientId: string }) { useEffect(() => { const script = document.createElement('script'); script.src = 'https://agent.maison-labs.com/agent-inject.bundle.js'; script.setAttribute('data-cfasync', 'false'); script.setAttribute('data-no-minify', '1'); script.setAttribute('data-no-optimize', '1'); script.setAttribute('data-no-defer', '1'); script.setAttribute('data-noptimize', '1'); script.onload = () => { const sessionId = new URLSearchParams(window.location.search).get('mcbsid'); const mcbs = (window as any).initMcbs({ clientId, sessionId, // locale: 'en-US', // Override browser locale // iconPosition: { top: 0, bottom: 20, left: 0, right: 20 }, // Chat icon position (px) // loadChatWindow: 'load', // When the chat window loads: 'load' (default), 'interaction', 'lazy' or 'eager' // onSessionUpdate: (id) => console.log('Session:', id), // onLocaleUpdate: (locale) => console.log('Locale:', locale), }); mcbs.showIcon(); }; document.head.appendChild(script); return() => { document.head.removeChild(script); }; }, [clientId]); return null; }Render MaisonChat in your app
Import and render the component near the root of your application. Pass your Client UUID as the
clientIdprop.tsximport { MaisonChat } from './MaisonChat'; export default function App() { return( <> <MaisonChat clientId="YOUR_CLIENT_UUID" /> {/* rest of your app */} </> ); }Optionally wire up session callbacks
If you need to persist or observe the session ID (for example to resume a conversation), extend the component to accept an
onSessionUpdateprop. The callback receives the session ID first and a{ clientId }meta object second — for a hotel group the clientId changes when the guest is handed off to one of the properties, so persist both to restore the right conversation.tsximport { useEffect } from 'react'; export function MaisonChat({ clientId, onSessionUpdate, }: { clientId: string; onSessionUpdate?: (sessionId: string, meta?: { clientId: string }) => void; }) { useEffect(() => { const script = document.createElement('script'); script.src = 'https://agent.maison-labs.com/agent-inject.bundle.js'; script.setAttribute('data-cfasync', 'false'); script.setAttribute('data-no-minify', '1'); script.setAttribute('data-no-optimize', '1'); script.setAttribute('data-no-defer', '1'); script.setAttribute('data-noptimize', '1'); script.onload = () => { const sessionId = new URLSearchParams(window.location.search).get('mcbsid'); const mcbs = (window as any).initMcbs({ clientId, sessionId, // locale: 'en-US', // Override browser locale // iconPosition: { top: 0, bottom: 20, left: 0, right: 20 }, // Chat icon position (px) // loadChatWindow: 'load', // When the chat window loads: 'load' (default), 'interaction', 'lazy' or 'eager' onSessionUpdate, // onLocaleUpdate: (locale) => console.log('Locale:', locale), }); mcbs.showIcon(); }; document.head.appendChild(script); return() => { document.head.removeChild(script); }; }, [clientId, onSessionUpdate]); return null; }Verify in DevTools
Open your browser DevTools, switch to the Elements tab, and look for
#maison-chat-iconin the DOM. If it's present, the widget initialised correctly.
For the full list of configuration options, control methods, and callbacks, see the Widget SDK Reference.
Common mistakes
script.src and immediately calling window.initMcbs() will fail because the script has not finished loading. Always call initMcbs inside script.onload.window does not exist on the server. This component is safe because useEffect only runs in the browser. Do not import or call initMcbs at module level in any file that may be server-rendered.MaisonChat is rendered in multiple places simultaneously, multiple script tags will be injected. Keep a single instance at the top level of your app (e.g. in App.tsx or the root layout).bottom: 20, not bottom: '20px'. Values are plain numbers representing pixels — do not include units.Not sure if it's set up correctly? Use the Site Diagnostic tool.