App Router and Pages Router. RSC-safe, no hydration flash, zero config.
Mount the widget inside a Client Component anywhere under your root layout. Because the trigger is dormant until clicked, it is safe to place at the layout level without affecting streaming or partial prerender.
npm install @usero/sdk'use client'
import { UseroFeedbackWidget } from '@usero/sdk/react'
export function Feedback() {
return <UseroFeedbackWidget clientId='YOUR_CLIENT_ID' />
}import { Feedback } from './feedback'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang='en'>
<body>
{children}
<Feedback />
</body>
</html>
)
}Replace YOUR_CLIENT_ID with the id from your Usero dashboard.
Built for Next.js
Wrap the widget in a Client Component. Server Components stream as normal. No special config in next.config.js.
The trigger button renders identically on server and client, so React does not re-render it during hydration.
The component does not touch Node APIs. Pages using the Edge runtime keep working without changes.
Placed in the root layout, the widget persists across route transitions, so half-typed feedback survives a soft navigation.
Featurebase ships a script tag that blocks hydration. Usero is a React component, so it streams alongside your tree.
Verify
Run next dev and load any route under your root layout.
Confirm the feedback bubble appears bottom-right on every page, since it lives in the layout.
Soft-navigate to another route with a Link. The bubble should stay mounted, not flash or reset.
Click it, submit a test message, and check the row lands in your Usero inbox.
Watch the server logs and browser console for hydration warnings; there should be none.
Troubleshooting
The widget uses React hooks, so its file needs 'use client' at the top, or it must be imported into a file that has it. In App Router, put <UseroFeedbackWidget /> inside a Client Component and render that from your layout.
Render it in pages/_app.tsx so it wraps every page, rather than inside an individual page. That keeps it mounted across navigations.
You are rendering the widget conditionally on something that differs between server and client, such as typeof window or a media query read during render. Render it unconditionally inside the client boundary instead.
It is mounted inside a page component, so Next unmounts it on each route change. Move it into the root layout (App Router) or _app.tsx (Pages Router) so it persists.
The widget touches no Node APIs, so the Edge runtime is fine. If a page 500s, the cause is usually elsewhere in that route segment. Check the segment does not import a Node-only module alongside the widget.
FAQ
In a Client Component imported from your root layout. Add 'use client' at the top of the file that renders <UseroFeedbackWidget />.
No. The widget is a leaf Client Component. RSC streaming above it is unaffected.
No. The widget renders a stable trigger button that matches between server and client. The panel only appears after a click.
Yes. The widget has its own scoped styles. It does not inherit font-family from your app unless you pass a theme override.
Free tier. No credit card. Two-minute install. Cancel by deleting two lines of code.
Install guides