Install · Next.js
Bug reports and feedback from your Next.js site, in one script tag.
Where it goes
At the end of the <body> in your root layout, so it loads once and survives client-side navigation.
Setup
Adding the widget to Next.js
- 01
Copy your widget key
Open your project in UserWants, go to the Widget tab and copy the snippet. The key looks like uw_pk_ followed by 32 hexadecimal characters. It is public by design — it sits in your HTML where anyone can read it, and what protects it is the domain allowlist, not secrecy.
- 02
Add the tag to your root layout
In the App Router, put it directly in app/layout.tsx inside <body>. A plain <script> tag with defer is all it needs — no next/script wrapper, no client component.
tsx// app/layout.tsx export default function RootLayout({ children }) { return ( <html lang="en"> <body> {children} <script src="https://userwants.app/widget.js" data-userwants-key="uw_pk_..." defer /> </body> </html> ); } - 03
Allow your domain
Back in Widget, add your production domain under Allowed domains. Until you do, the widget only works on localhost — an empty list fails closed. Add your preview domain too if you deploy on Vercel: each preview gets its own hostname, so a wildcard entry saves you doing it per branch.
- 04
Identify signed-in users, if you have them
If your app knows who the visitor is, pass the id you already have and the widget stops asking for an email. Call identify on login and logout rather than re-initialising.
tsx'use client'; useEffect(() => { window.UserWants?.identify({ identifier: user.id, name: user.name, email: user.email }); }, [user]);
Worth knowing
What bites on Next.js
Do not wrap it in next/script with afterInteractive
It works, but it buys you nothing here: the file is already deferred and loaded from a CDN, and the wrapper re-runs the injection on route changes in some configurations, which the widget then ignores because it refuses to load twice. A plain tag is simpler and behaves the same.
The App Router renders layout.tsx on the server
That is fine — the tag is markup, not code that runs at render. You do not need "use client" on your layout to add it.
A strict CSP needs two directives
script-src https://userwants.app and connect-src https://userwants.app. Styles are injected as a constructable stylesheet, so you do not need unsafe-inline for the widget.
FAQ
Questions
- Does it affect my bundle size or build time?
- No. There is no package and no import — the browser fetches one file from a CDN after your page loads. Nothing enters your build.
- Will it break hydration?
- No. Everything the widget renders lives inside a closed shadow root attached to an element it creates itself, so React never sees it and never tries to reconcile it.
The full reference — every field the widget collects, the domain allowlist rules and the JavaScript API — is in the widget docs.
Try it on your Next.js site.
Paste the tag, add your domain, and the next report arrives with the screenshot and the JavaScript error already attached.