Next.js Feedback Widget: Add In-App Feedback Without Building Another Dashboard
Add a feedback widget to a Next.js app without building your own feedback backend, admin dashboard, screenshot flow, or NPS tooling from scratch.
I almost built a feedback system again.
You know the shape of it:
- a button somewhere in the app
- a modal with a textarea
- maybe a rating field
- an API route
- a database table
- an admin page
- email notifications
- screenshots, later, if you hate your weekend
It starts as “just a small feedback form”.
Then it quietly becomes another product inside your product.
For a small SaaS team, that is usually the wrong trade.
Not because feedback is unimportant. The opposite. Feedback is one of the few things that tells you whether people actually understand what you are building.
But building feedback infrastructure from scratch is rarely the best use of founder time.
So if you are building a Next.js app and want product feedback, the better move is usually simple: add an in-app feedback widget, ask good questions, and keep building your actual product.
This guide shows how to add SeggWat to a Next.js app without building your own feedback backend or dashboard.
Why not just use a normal form?
Most early SaaS products collect feedback in one of three ways:
- a Google Form
- a “send us an email” link
- a custom form someone built at midnight
All three work, technically.
But they lose context.
If a user is confused on your billing page, you do not want them to open a separate form, explain where they were, describe what happened, and maybe attach a screenshot if they feel generous.
They probably will not.
They will close the tab, silently judge you, and go make coffee.
In-app feedback works better because it catches the moment while it is still fresh.
That is the whole point.
What we are adding
We will add a small feedback widget to a Next.js app.
The widget can sit in your layout, load on every page, and let users send feedback from inside the product.
The setup is intentionally boring:
- add the script
- set your project key
- verify it loads
- ship
No backend route. No database migration. No admin dashboard to build before you even have feedback.
Option 1: Add the widget to the App Router layout
If your Next.js app uses the App Router, add the widget script in app/layout.tsx.
// app/layout.tsx
export const metadata: Metadata = {
title: "My SaaS",
description: "A small product that listens to users",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://seggwat.com/static/widgets/v1/seggwat-feedback.js"
strategy="afterInteractive"
data-project-key="YOUR_PROJECT_KEY"
/>
</body>
</html>
);
}Replace YOUR_PROJECT_KEY with your project's key from the SeggWat dashboard. That is the only configuration the widget needs.
strategy="afterInteractive" is usually the right choice here. The feedback widget does not need to block rendering. Let the page load, then load feedback.
Option 2: Wrap it in a small component
If you prefer to keep third-party scripts out of your layout file, create a small component.
// components/FeedbackWidget.tsx
export function FeedbackWidget() {
return (
<Script
src="https://seggwat.com/static/widgets/v1/seggwat-feedback.js"
strategy="afterInteractive"
data-project-key="YOUR_PROJECT_KEY"
/>
);
}Then use it in your layout:
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<FeedbackWidget />
</body>
</html>
);
}This is the version I usually prefer once an app grows a bit. It keeps the integration visible without turning the layout into a junk drawer.
Option 3: Only show feedback inside the app
Sometimes you only want feedback inside the actual product, not on marketing pages.
In that case, put the widget in your authenticated app layout instead of the root layout.
For example:
// app/(dashboard)/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="min-h-screen">
{children}
<FeedbackWidget />
</div>
);
}That way the widget appears where feedback is most useful: inside the product experience.
Turn on screenshots (it is one attribute)
Remember “screenshots, later, if you hate your weekend”?
Here, it is one attribute:
<Script
src="https://seggwat.com/static/widgets/v1/seggwat-feedback.js"
strategy="afterInteractive"
data-project-key="YOUR_PROJECT_KEY"
data-enable-screenshots="true"
/>Users get an “Add Screenshot” button in the feedback form. The widget captures the visible page, opens an annotation editor (arrows, rectangles, text, a blackout tool for redacting sensitive data), and attaches the result to the submission. I wrote about how the capture pipeline works if you are curious.
A few other attributes worth knowing:
data-button-color— match your brand colordata-button-position—bottom-right,right-side, oricon-onlydata-button-text— change the button labeldata-language—en,de, orsv(auto-detects from the browser by default)
The full list is in the widget installation docs.
Tell the widget who is talking
If your users are logged in, attach their identity to submissions. Feedback from “anonymous” is a guessing game. Feedback from a known user is a conversation you can continue.
The widget loads asynchronously, so wait until it is available, then call setUser:
// components/IdentifyFeedbackUser.tsx
"use client";
export function IdentifyFeedbackUser({
userId,
email,
}: {
userId: string;
email?: string;
}) {
useEffect(() => {
const timer = setInterval(() => {
if (window.SeggwatFeedback) {
window.SeggwatFeedback.setUser(userId, email);
clearInterval(timer);
}
}, 250);
return () => clearInterval(timer);
}, [userId, email]);
return null;
}Drop it into your authenticated layout next to the widget. Passing the email also pre-fills the email field in the form, so users do not have to type it.
TypeScript will want a declaration for the global:
declare global {
interface Window {
SeggwatFeedback?: {
setUser(userId: string | null, email?: string | null): void;
};
}
}What should the widget ask?
This part matters more than the script tag.
Do not just ask:
Any feedback?
That is too vague.
People are busy. Vague questions create vague answers.
You have two levers here.
The first is the button label. data-button-text replaces the default “Feedback” with something pointed:
- “Something confusing?”
- “What is missing?”
- “Report a problem”
A specific label invites a specific answer.
The second is asking an actual question at an actual moment — “Did this feature do what you expected?” right after someone used the feature. That is what in-app surveys are for: a targeted question, shown only where and when it is relevant.
For early SaaS, my favorite default question is:
What is one thing that would make this product more useful for you?
It is simple, but it points users toward concrete product feedback instead of general vibes.
Where to place the feedback trigger
A feedback widget does not need to scream.
Put it somewhere persistent but quiet:
- bottom-right corner
- inside the app shell
- near help/support
- after important actions, if you want contextual feedback
Do not interrupt users every five seconds. That is how feedback tools become pop-up spam with nicer fonts.
The best feedback UI feels available, not needy.
Why I would not build this from scratch again
Could you build this yourself?
Of course.
A basic form is easy.
The annoying parts come after that:
- screenshot capture
- spam handling
- rating/NPS variants
- idea voting
- statuses
- notification flow
- privacy/GDPR defaults
- a dashboard you do not hate opening
- keeping all of it maintained while also building your actual product
That is where the “small form” stops being small.
For an indie hacker or tiny SaaS team, the right question is not:
Can I build this?
It is:
Is this the thing I should spend my next few evenings building?
Usually, no.
Quick checklist before shipping
Before you call it done:
- test the widget in production, not only locally
- submit one fake feedback item yourself
- check that it appears in your dashboard
- ask a specific question, not “any feedback?”
- make sure it appears only where it makes sense
- add a small internal note for what kind of feedback you want to collect
That last one helps. If you do not know what signal you want, users will not magically give it to you.
Final thought
Feedback should be close to the moment where the user feels friction.
That is the main reason I like in-app widgets over external forms.
Not because forms are evil. They are fine.
But if someone is already inside your product, confused by your product, or excited about a feature in your product, sending them somewhere else to explain it is a weird move.
Keep the feedback close.
Keep the setup small.
Spend the saved time building the thing users are actually asking for.
If you want the lightweight version, SeggWat is built for exactly this: in-app feedback for small SaaS teams without enterprise bloat.
You can add it to your Next.js app in a few minutes and start collecting feedback where the friction actually happens.
