Skip to content

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.

In your .env:

Fenêtre de terminal
VITE_SUPPORTDESK_APP_ID=your-app-id
VITE_SUPPORTDESK_PUBLIC_KEY=pk_live_xxxxxxxxxxxx
VITE_SUPPORTDESK_WIDGET_URL=https://supportdesk-widget.vercel.app/v1/supportdesk-widget.js
src/providers/SupportDeskProvider.tsx
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:

src/App.tsx
import { SupportDeskProvider } from './providers/SupportDeskProvider';
export default function App() {
return (
<SupportDeskProvider>
<YourRoutes />
</SupportDeskProvider>
);
}

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>
);
}
const [unread, setUnread] = useState(0);
useEffect(() => {
const unsubscribe = window.SupportDesk?.onUnreadChange(setUnread);
return () => unsubscribe?.();
}, []);