How to add a live chat widget to a React or Next.js app
By The Roper team · Published · 4 min read
The short answer
To add a live chat widget to a React or Next.js app, load the widget's script once in your root layout (with next/script in Next.js, or an effect in a plain React app), pass the logged-in user before it loads or call identify after login, and open it from your own button with the widget's JavaScript API. Because the widget runs in its own iframe, route changes do not reload it.
1. Load the script once
Put the script in the root of your app so it loads on every page and only once. The widget needs your public workspace key as data-key; it is not a secret.
- Next.js (App Router): in the root layout, render
<Script src="https://your-roper-host/widget.js" data-key="wk_XXXX" strategy="afterInteractive" />fromnext/script. Check your installed Next.js version's docs for the currentScriptoptions. - Plain React: in your top-level component, add the script element once in an effect and remove it on cleanup, or add the tag to
index.htmlbefore</body>. - Any site: paste the snippet from Settings → Install before the closing body tag.
2. Pass the logged-in user
If you know who the user is, define window.RoperSettings before the widget script runs, with userId, name, email and any meta such as plan and company. They then appear in your inbox sidebar and you never ask "what's your email?".
In a single-page app the user often logs in after the script has loaded. In that case call window.Roper("identify", { userId, name, email, meta }) once the user is known. Identity set this way is not verified: anyone can set any userId, so do not use it to authorize anything.
3. Open it from your own button
Call window.Roper("open") from a Help link in your menu, and window.Roper("close") to close it. Guard the call: the script may still be loading, so check that window.Roper exists first.
4. Things that trip people up
- Content Security Policy. If your app sets a CSP, allow your Roper host in
script-srcandframe-src. - Loaded twice. In development, React strict mode runs effects twice. Load the script from the layout, or guard against adding it again.
- Server rendering. The widget is browser-only. Do not reference
windowduring server render; use an effect or an event handler. - Logout. If a different user can log in on the same browser, call identify with the new user, and consider the privacy implications of shared devices.
- Ad blockers. Some block chat widgets. Offer an email address as a fallback.
5. Check it works
- Reload the app and look for the launcher in the bottom-right corner.
- Send a message as a test customer and confirm it appears in your inbox with the user's details.
- Reply from the inbox and confirm the reply appears live in the widget.
- Open it from your Help link.
More on what the widget does is on the live chat widget page, and you can try it on the live demo.
Questions
Common questions
- How do I add a chat widget to a Next.js app?
- Add the widget's script to your root layout using
next/scriptwithafterInteractive, pass the user throughwindow.RoperSettingsor call identify after login, and open it withwindow.Roper("open")from your own button. - Will the widget reload on every route change?
- No. It loads once and runs in its own iframe, so client-side navigation does not reload it, provided you load the script from the layout and not from a page.
- Can I hide the launcher and use my own button?
- Roper's widget shows its own launcher. You can add your own Help link that calls
window.Roper("open"), but hiding the launcher is not a documented option. - Does the widget work with server components?
- The script and its calls run in the browser. Place the script in a layout and put any calls to
window.Roperin client components or event handlers.
Sources and how we wrote this
Roper is made by the team that wrote this post. Figures for other tools come from their own public pages, listed under Sources, and are list prices in US dollars that can change. If something here is out of date, tell us on the feedback board and we'll correct it.