Embed Chat Into A ReactJS SPA

New Member

So, is there an embed pattern to embed/integrate the chatbot into my reactJS SPA ? I couldn'y find an example or even an npm module for the chatbot. Is there a clean integration pattern for this into react ? Please share details.

10 Replies 10
HubSpot Alumni

Hi @amjadg,


I haven't done this myself but I've been doing some searching around our forums. Here's an example from a while back where someone added the tracking code to a React app: https://community.hubspot.com/t5/APIs-Integrations/Tracking-code-for-a-single-page-application-made-.... If you look at the bottom response there, the user built a page listener component. Maybe that would help with what you're trying to do?


I also found this: https://community.hubspot.com/t5/CMS-Development/Chat-integration-issue-with-React/m-p/275219 while doing a search, but I see you've already tried posting to that thread. Maybe we can get @Rajesh16 's attention here, and see if they've made any progress.


Also, maybe bumping this thread back to the top will get some more eyes on it.

Leland Scanlan

HubSpot Developer Support
Regular Contributor

Any updates on this?

I tried these methods:

1. Add the script in "index.html"
2. Append the script to the "body" element in a "useEffect" Hook defined in the top-level "App" component

None worked (with React 16.11.0). Unfortunately, this is a showstopper, forcing me to go find another live chat product.

    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script src="https://js.hs-scripts.com/MY_ID.js" async></script>
React.useEffect(() => {
  (function loadHubSpot() {
    const d = document;
    const s = d.createElement("script");

    s.async = true;
}, [])


New Contributor

Have same issue here, any updates?

New Member

Try adding <script .... /> to the <head></head> component instead of <body></body>

I've added to index.html this way and it's working for me

New Contributor

we have the same problem here, nothing worked

Occasional Contributor

This worked for me as well.

Occasional Contributor

Something like this should work:


// Create a hook to seperate out logic.
const useHubspotChat = (portalId) => { const [ hasLoaded, setHasLoaded ] = React.useState(false); const [ activeConversation, setActiveConversation ] = React.useState(false); const eventRef = React.useRef(null); React.useEffect(() => { console.log('hey') // Add event listener. window.hsConversationsOnReady = [() => { setHasLoaded(true); }]; // Create script component. let script = document.createElement('script'); script.src=`//js.hs-scripts.com/${portalId}.js`; script.async = true; document.body.appendChild(script); return () => { document.body.removeChild(script); window.hsConversationsOnReady = []; } }, []); // Subscripe to conversation events. React.useEffect(() => { eventRef.current = (payload) => { setActiveConversation(payload.conversation.conversationId); } if (hasLoaded) { window.HubSpotConversations.on( 'conversationStarted', eventRef.current); } return () => { window.HubSpotConversations.off('conversationStarted', eventRef.current); } }, [hasLoaded]); const openHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.open(); } }, [hasLoaded]); const closeHandler = React.useCallback(() => { if (hasLoaded) { window.HubSpotConversations.widget.close(); } }, [hasLoaded]) return { hasLoaded, activeConversation, openHandler, closeHandler }; } const App = () => { const { hasLoaded, activeConversation, openHandler, closeHandler } = useHubspotChat(<portalidhere>); return ( <div> hi {hasLoaded ? 'yes': 'no'} conversation: { activeConversation } <button onClick={openHandler}>click me to open</button> <button onClick={closeHandler}>click me to close</button> </div>) } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);


Regular Contributor | Elite Partner

It should work, but it may depend on how you're handling routing. Basically the way the chat function works is you add the standard HS scripts and then configure (in HubSpot) where and when the live chat should pop up. Basically the script needs to be available for the whole app, and then the triggers are handled on HubSpot's side instead of in your codebase. I'm not aware of an NPM or webpack-friendly method of bundling that script, however. I've always done it manually.


There may be a conflict between React versions since HubSpot uses React for a lot of their on-page tools. That shouldn't happen, but it is something I've run into in the past. React Dev Tools might help diagnose if there's something like that going on.

Occasional Contributor

I guess if you're using React Router - or some other router you can simply invoke window.HubSpotConversations.widget.refresh(); which apparently re-runs the page matching logic based on the current URL.

New Contributor
class App extends Component {

    componentDidMount() {

        const script = document.createElement("script");

        script.async = true;



    render() {

        return (