React integration
Create a provider that loads the widget once the user is logged in. The script is dynamically loaded client-side, so it’s compatible with Next.js, Remix, React Router v7 and any SSR setup.
Environment variables
Section titled “Environment variables”In your .env:
VITE_SUPPORTDESK_APP_ID=your-app-idVITE_SUPPORTDESK_PUBLIC_KEY=pk_live_xxxxxxxxxxxxVITE_SUPPORTDESK_WIDGET_URL=https://supportdesk-widget.vercel.app/v1/supportdesk-widget.jsThe provider
Section titled “The provider”import { useEffect, useRef } from 'react';import { useAuth } from '@/hooks/useAuth'; // your auth hook
declare global { interface Window { SupportDesk?: { init: (config: any) => void; destroy: () => void; open: () => void; close: () => void; toggle: () => void; isOpen: () => boolean; onUnreadChange: (cb: (n: number) => void) => () => void; }; }}
const WIDGET_URL = import.meta.env.VITE_SUPPORTDESK_WIDGET_URL;const APP_ID = import.meta.env.VITE_SUPPORTDESK_APP_ID;const PUBLIC_KEY = import.meta.env.VITE_SUPPORTDESK_PUBLIC_KEY;
export function SupportDeskProvider({ children }: { children: React.ReactNode }) { const { user } = useAuth(); const scriptLoadedRef = useRef(false); const currentUserIdRef = useRef<string | null>(null);
useEffect(() => { if (!user || !WIDGET_URL) return;
const init = () => { window.SupportDesk?.destroy(); window.SupportDesk?.init({ appId: APP_ID, apiKey: PUBLIC_KEY, customer: { externalId: user.id, email: user.email, name: user.name, }, theme: { primaryColor: '#2563eb', showButton: false }, }); currentUserIdRef.current = user.id; };
if (scriptLoadedRef.current && window.SupportDesk) { if (currentUserIdRef.current !== user.id) init(); return; }
const script = document.createElement('script'); script.src = WIDGET_URL; script.async = true; script.onload = () => { scriptLoadedRef.current = true; init(); }; document.head.appendChild(script); }, [user]);
return <>{children}</>;}Wrap your app with the provider:
import { SupportDeskProvider } from './providers/SupportDeskProvider';
export default function App() { return ( <SupportDeskProvider> <YourRoutes /> </SupportDeskProvider> );}Custom button
Section titled “Custom button”With showButton: false, the default floating button is hidden. Use your own UI to open the widget:
function SupportButton() { return ( <button onClick={() => window.SupportDesk?.toggle()}> Contact support </button> );}Unread messages badge
Section titled “Unread messages badge”const [unread, setUnread] = useState(0);
useEffect(() => { const unsubscribe = window.SupportDesk?.onUnreadChange(setUnread); return () => unsubscribe?.();}, []);