Live chat for React apps — no SDK, no re-renders
chatrelay adds live chat to a React single-page app without touching your component tree: one script tag in index.html. The widget lives in its own Shadow DOM outside React, so it never re-renders your app, never fights your router, and survives route changes untouched.
Install chatrelay on React
- Create your free chatrelay account
Sign up (free plan, no credit card) and copy your embed snippet from the dashboard — it comes pre-filled with your real project id. The snippet below shows the shape;
your-projectis replaced by your id. - Paste the tag into index.html
Vite: the file is
index.htmlat the project root. Create React App: it'spublic/index.html. Either way, paste the embed right before</body>:<script src="https://www.chatwithdev.com/widget.js" data-chatrelay-project="your-project" data-chatrelay-convex="https://impressive-quail-820.convex.cloud" data-chatrelay-title="Chat with us" defer></script>
- Optional — identify signed-in users
If your app has accounts, tell the widget who is chatting once auth resolves. Their name shows in your inbox and you unlock reply-by-email:
// after your auth state resolves (any component) useEffect(() => { if (user) { (window as any).__cr?.identify({ name: user.name, email: user.email }); } else { (window as any).__cr?.identify(null); // signed out } }, [user]); - Ship it
That's the whole integration. The bubble persists across client-side route changes (React Router, TanStack Router — anything), because the widget is mounted outside the React root.
next/script in your layout instead — see the Next.js guide.How replies reach your visitors
Every message relays to a Telegram bot you own — created at @BotFather in a minute and connected once in the chatrelay setup. In group mode each visitor gets their own topic; in direct mode chats arrive in your DM with the bot. Your reply appears in the visitor's chat bubble live, and the web dashboard (with AI drafting) is always there as a second screen. How the Telegram relay works →
FAQ
Does it work with Vite, CRA and Remix SPAs?
Yes — anywhere you control the HTML shell. Vite and CRA have an index.html; in Remix you can add the tag in root.tsx's <body>. The widget itself is framework-agnostic.
Will it re-render my components or touch my state?
No. The widget mounts into its own container appended to <body>, inside a Shadow DOM. It is invisible to React — no context, no portals, no re-renders.
How do I identify logged-in users?
Call window.__cr?.identify({ name, email }) after your auth state resolves, and window.__cr?.identify(null) on sign-out. Identified visitors are marked premium in your inbox and you can also answer them by email.
Can I open the chat from my own button?
Yes — call window.__cr?.open() from any click handler, e.g. a “Chat with us” link in your navbar.
Do my visitors need Telegram?
No. Visitors only see the chat bubble on your site. Telegram is just where you answer from; replies appear in the visitor's widget live.