Adding a third-party widget to a React app is where a lot of teams accidentally tank their Core Web Vitals — a synchronous script in the wrong place blocks hydration. The good news: a support widget should be the last thing that loads, and React gives you clean ways to do exactly that. Here’s how to add one to Next.js (App Router and Pages Router) and to a plain React app.
Next.js — App Router (app/)
Use next/script with strategy="lazyOnload" so the widget loads after the page is interactive. Add it once in your root layout:
// app/layout.tsx
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://app.simplesupport.uk/widget/widget.js"
data-key="your-api-key"
strategy="lazyOnload"
/>
</body>
</html>
);
}
lazyOnload is the key: the support button isn’t above-the-fold and doesn’t need to block anything.
Next.js — Pages Router (pages/)
Same idea in pages/_app.tsx:
import Script from "next/script";
export default function App({ Component, pageProps }) {
return (
<>
<Component {...pageProps} />
<Script
src="https://app.simplesupport.uk/widget/widget.js"
data-key="your-api-key"
strategy="lazyOnload"
/>
</>
);
}
Plain React (Vite, CRA, etc.)
No next/script? Inject the script once on mount and guard against double-loading (important with React 18 Strict Mode, which mounts effects twice in dev):
import { useEffect } from "react";
export function SupportWidget() {
useEffect(() => {
if (document.querySelector("script[data-key][src*='widget.js']")) return;
const s = document.createElement("script");
s.src = "https://app.simplesupport.uk/widget/widget.js";
s.setAttribute("data-key", "your-api-key");
s.async = true;
document.body.appendChild(s);
}, []);
return null;
}
Render <SupportWidget /> once near the root of your tree.
A note for SPAs
The widget mounts a single floating button and manages its own DOM, so it survives client-side route changes — you don’t need to re-initialise it on navigation. Load it once, leave it alone.
Keep your API key public-safe
The data-key is a publishable widget key, scoped to creating tickets from your authorised domain — it’s meant to live in client code, like a Stripe publishable key. Set your domain in the dashboard so the key only works from your site.
That’s the whole integration: one script, loaded lazily, and every support request from your app becomes a tracked ticket. Start free — 100 tickets a month, no credit card.