Usero Journal
How to Collect User Feedback in a Next.js App (in 5 Minutes)
You can add user feedback to a Next.js app in about five minutes with a drop-in widget, in three steps: install the SDK, mount the widget in your root layout, and identify the signed-in user.
The fastest way to collect user feedback in a Next.js App Router app is a widget you embed once. Run npm install @usero/sdk, render a small 'use client' component that mounts the widget inside app/layout.tsx, then call identify() so submissions arrive tagged with the logged-in user. That is the whole job. No backend route, no form table, no email parsing.
This guide walks through the three steps with copy-pasteable code, then compares the widget approach against building your own form plus API route and against embedding a third-party survey, so you can pick the one that fits.
Step 1: Install the SDK
The widget ships as a package on npm. Add it to your Next.js project with your package manager of choice.
npm install @usero/sdk
# or
pnpm add @usero/sdk
# or
yarn add @usero/sdkThat is the only dependency. The package exposes a React entry point at @usero/sdk/react plus a vanilla JS embed if you ever need it outside React. It is open source, so you can read exactly what runs in your users’ browsers before you ship it.
Step 2: Mount the Widget in Your Root Layout
In the App Router, app/layout.tsx is a Server Component by default. A feedback widget needs the browser (it renders a button, opens a form, reads the URL), so it has to run on the client. The clean pattern is a small client component that wraps the widget, then render that component inside your server-rendered layout.
Create a client widget component
Add app/feedback-widget.tsx. The 'use client' directive at the top tells Next.js to hydrate this file in the browser.
'use client'
import { FeedbackWidget } from '@usero/sdk/react'
export function Feedback() {
return <FeedbackWidget projectId={process.env.NEXT_PUBLIC_USERO_PROJECT_ID!} />
}Put your project ID in an environment variable. Anything prefixed with NEXT_PUBLIC_ is exposed to the browser, which is what you want here, since the widget runs client-side. Add it to .env.local:
NEXT_PUBLIC_USERO_PROJECT_ID=your_project_idRender it in the layout
Drop the client component into the body of app/layout.tsx. Rendering it in the root layout means the widget loads on every page of the app, so users can send feedback from anywhere.
import { Feedback } from './feedback-widget'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang='en'>
<body>
{children}
<Feedback />
</body>
</html>
)
}The layout stays a Server Component. Only the small <Feedback /> island hydrates on the client. Your server-rendered HTML, streaming, and Lighthouse score are untouched, because the widget loads asynchronously after the page paints. Save the file, run npm run dev, and you should see the feedback button in the corner of every page.
The whole point of a widget is that it is one component in one file. If collecting feedback takes a sprint, you picked the wrong approach.
Step 3: Identify the Signed-In User
Anonymous feedback is half useful. If you know who is logged in, tag every submission with their user ID and a few traits so you can reply, see their plan, and spot which accounts keep hitting the same problem. Call the identify() API once your session loads.
Update the client component to read your session and identify the user. This example uses a generic useUser() hook, but the shape works with NextAuth, Clerk, your own context, or anything that gives you the current user on the client.
'use client'
import { useEffect } from 'react'
import { FeedbackWidget, identify } from '@usero/sdk/react'
import { useUser } from '@/lib/auth'
export function Feedback() {
const user = useUser()
useEffect(() => {
if (!user) return
identify(user.id, {
email: user.email,
plan: user.plan,
})
}, [user])
return <FeedbackWidget projectId={process.env.NEXT_PUBLIC_USERO_PROJECT_ID!} />
}Now every message that arrives in your dashboard carries the user ID, email, and plan, alongside the page URL and browser the widget captures for free. That context is the difference between “a user reported a bug somewhere” and “this Pro customer hit a 500 on the billing page.”
Three Ways To Collect Feedback in Next.js
A drop-in widget is the fastest path, but it is not the only one. Here is how it compares to rolling your own and to embedding a survey tool.
| Approach | Setup time | Maintenance | Routing | Best for |
|---|---|---|---|---|
| Drop-in widget | ~5 minutes | None (vendor hosts) | Dashboard, Slack, GitHub | Anyone who wants feedback today |
| Build your own form + API route | Hours to days | Ongoing (yours) | Whatever you wire up | Teams with strict data rules |
| Third-party survey embed | ~15 minutes | Low | Vendor dashboard, CSV | Structured, scheduled questions |
When to build your own instead
A form posting to a Next.js route.ts handler that writes to your database is the right call when feedback must never leave your infrastructure, or when it is deeply tied to your own data model. The tradeoff is real, though. You own the form UI, the API route, the storage, spam handling, screenshots, notifications, and triage. For most teams that is weeks of work to rebuild what a widget gives you in an afternoon.
A survey embed (Typeform, a Google Form, a survey tool iframe) is good for structured questions you already know to ask on a schedule. It is a poor fit for always-on, user-initiated feedback, which is exactly what a widget is built for. The two are complements, not substitutes.
Related Reading
- What Is a Feedback Widget?Read
- How to Collect User Feedback In-App: 7 Methods ComparedRead
- Best User Feedback Tools (2026 Comparison)Read
- What Is Session Replay?Read
If You Want To Try Usero
The widget in the code above is Usero. The free tier is real, the SDK is open source on npm, and it drops into a Next.js app in the three steps you just read. The unusual part comes after collection: Usero clusters similar submissions with AI and can open a draft GitHub pull request with a first-pass fix for the request, so “ship the top ask” stops being a two-day project. Create a project and put the widget in front of real users this week.
Frequently Asked Questions
How do I add a feedback widget to Next.js?
Install a widget SDK from npm, mount it in a small client component, and render that component once in your root layout (app/layout.tsx). With Usero that is npm install @usero/sdk, a use client component rendering <FeedbackWidget projectId="..." />, and adding it to the layout body. The widget loads on every page and submissions land in your dashboard.
Does the widget work with the App Router and Server Components?
Yes. The App Router renders Server Components by default, and a feedback widget needs the browser, so you wrap it in a file that starts with the use client directive. You still render that client component inside the server-rendered root layout. Server Components stay server-rendered, and only the small widget island hydrates on the client.
Will a feedback widget hurt my Next.js performance or Lighthouse score?
A well-built widget loads asynchronously, weighs under 30 KB gzipped, and only mounts the form when a user clicks the trigger. It is a client island, so it does not block your server-rendered HTML or first paint. The Lighthouse impact is usually unmeasurable. Avoid widgets that bundle session replay by default unless you want it, since that is where the weight lives.
How do I attach the logged-in user to feedback?
Call the widget identify API once you know who the user is, for example identify(user.id, { email, plan }). Do it in a client component or effect after your session loads, so every submission arrives tagged with the user ID and traits. Tagged feedback lets you reply, see the plan and history, and stop guessing who hit the bug.
Can I self-host or use this in the Pages Router?
The Usero SDK is open source on npm, so you can read and pin the source. For the Pages Router, render the same client widget component inside pages/_app.tsx instead of app/layout.tsx. The vanilla JS embed also works in any framework or a plain HTML page if you are not on React at all.
Where does the feedback go after a user submits?
Submissions land in your dashboard with the page URL, browser, and any user traits you passed via identify. From there you can route to Slack, GitHub, or Linear. Usero also clusters similar messages with AI and can open a draft GitHub pull request with a first-pass fix for a clustered request.
Is there a free option?
Yes. Usero has a real free tier, not a 14-day trial, and paid plans start at 19 dollars a month. The SDK is open source on npm, signup takes under a minute, and you can have a working widget in a Next.js app in about five minutes.
Continue reading
How to Collect User Feedback In-App: 7 Methods Compared
How to collect user feedback in-app: 7 methods compared (widget, microsurveys, session replay, voting, chat) with response rates and what to ship first.
9 min read
NPS vs CSAT vs CES: Which One to Track
NPS vs CSAT vs CES explained: what each metric measures, the exact survey questions, benchmarks, and which one a startup should actually track.
8 min read
AI-Generated PRs From User Feedback: How It Works
How AI-generated PRs from user feedback work: collect, cluster, draft a GitHub pull request, then a human reviews and merges. Honest about the limits.
8 min read
Build a feedback loop your team actually uses
Usero collects, clusters, and turns user feedback into shipped fixes.
Get started free