The support widget is a chat bubble your users open from anywhere in your app. It installs with one script tag and runs in an isolated iframe, so it never clashes with your styles or scripts.
Add the script#
Paste this before the closing </body> tag on every page where the widget should appear. Thedata-key is your workspace’s public key: it tells Relay whose widget this is. It isn’t a secret (it’s visible in your page source, like any embed) and it only lets someone start a chat with your support team. The same snippet, with your host and your key filled in, is under Inbox → Settings → Install the support widget.
<script>
window.RelaySettings = {
// all optional: pass them when the user is signed in
userId: "usr_123",
name: "Jane Cooper",
email: "jane@company.com",
meta: { plan: "Pro", company: "Company Inc" }
};
</script>
<script src="https://support.notaislop.xyz/widget.js" data-key="wk_XXXXXXXXXXXXXXXXXXXXXXXX" async></script>That’s it. A launcher bubble appears in the bottom-right corner. RelaySettings is optional; see Identify your users for what each field does.
Framework examples#
The script only needs to load once per page. In a single-page app, load it once at the root, not on every route change.
import Script from "next/script";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script src="https://support.notaislop.xyz/widget.js" data-key="wk_XXXXXXXXXXXXXXXXXXXXXXXX" strategy="afterInteractive" />
</body>
</html>
);
}import { useEffect } from "react";
export function SupportWidget({ user }) {
useEffect(() => {
window.RelaySettings = user ? { userId: user.id, name: user.name, email: user.email } : {};
if (document.querySelector("script[data-relay]")) return;
const s = document.createElement("script");
s.src = "https://support.notaislop.xyz/widget.js";
s.dataset.key = "wk_XXXXXXXXXXXXXXXXXXXXXXXX";
s.async = true;
s.dataset.relay = "";
document.body.appendChild(s);
}, [user]);
return null;
}<script src="https://support.notaislop.xyz/widget.js" data-key="wk_XXXXXXXXXXXXXXXXXXXXXXXX" async></script>Note
Relay("identify", …) at that point; see the JavaScript API.How it works#
widget.jsis a tiny loader. It adds an iframe served from your Relay host, sized to just the launcher until it opens.- On phones (under 480px wide) the open widget fills the screen.
- The visitor id lives in the iframe’s
localStorage, so returning visitors see their past conversations. - Replies arrive live over Server-Sent Events, with polling as a fallback, and an unread badge shows on the launcher.
- Pressing Esc closes the panel.
Content Security Policy#
If your app sets a CSP, allow your Relay host as a script source and a frame source:
script-src https://support.notaislop.xyz;
frame-src https://support.notaislop.xyz;Troubleshooting#
The bubble doesn’t appear#
- Open the browser console and check that
widget.jsloaded (no 404 and no CSP error). - Make sure the script runs after
<body>exists; the loader waits for it if needed. - An element with a higher
z-indexthan2147483000would cover it. - Check the script tag has your
data-key. Without it the console warns “The widget needs your workspace key”. - If your subscription has lapsed the widget hides itself until you renew (see Plans & billing). Nothing is deleted.
Past conversations disappear#
The visitor id is stored per browser. Private windows, cleared site data or a different device start fresh. Pass email so you can still recognize the person in your inbox.