Add a feedback widget to a Next.js app
Load https://escutaproduto.com/widget.js once in app/layout.tsx with <Script strategy="afterInteractive" data-key="pk_…" />, then push an identify call from a client component to attach the signed-in user.
By Rafael Thayto · Last updated
1. Load the script in the root layout
next/script forwards data-* props to the script tag, so the widget reads its options as usual.
// 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://escutaproduto.com/widget.js"
data-key="pk_your_product_key"
strategy="afterInteractive"
/>
</body>
</html>
);
}
Loading it in the root layout keeps one widget instance across client-side navigations. The widget records location.href at the moment of sending, so each message has the right page URL even in a single-page app.
2. Identify the signed-in user
Render this client component anywhere inside your authenticated layout. The queue form works whether or not the widget has finished loading.
// components/feedback-identity.tsx
"use client";
import { useEffect } from "react";
type User = { id: string; email: string; name?: string; plan?: string };
export function FeedbackIdentity({ user }: { user: User }) {
useEffect(() => {
const w = window as typeof window & { EscutaProduto?: { q?: unknown[][] } };
w.EscutaProduto = w.EscutaProduto || { q: [] };
(w.EscutaProduto.q ||= []).push(["identify", [user]]);
}, [user]);
return null;
}
3. Open the widget from your own UI (optional)
Add data-trigger="none" to the <Script> to hide the floating button, then use the data-escuta-open attribute on any element, including inside Server Components, because it needs no JavaScript of its own:
<button data-escuta-open="bug">Report a bug</button>
Content Security Policy
If your app sends a CSP header, allow the script and the API:
script-src 'self' https://escutaproduto.com;
connect-src 'self' https://escutaproduto.com;
Sending feedback from the server
For Server Actions, Route Handlers or background jobs, call the REST API directly instead of the widget. Requests without an Origin header are accepted from any server.
Frequently asked questions
Should I use next/script or a plain script tag in Next.js?
Use next/script with strategy="afterInteractive" in app/layout.tsx. It loads the widget once after hydration and keeps it across client-side navigations.
Does the widget work with the Next.js App Router and Server Components?
Yes. The script is loaded once in the root layout, and the data-escuta-open attribute works on elements rendered by Server Components because it needs no client-side React code.
Related
- Install the feedback widgetAdd the Escuta Produto feedback widget to any website with one script tag. Options, custom triggers, user identification and the JavaScript API.
- Feedback REST APISend customer feedback to Escuta Produto from servers, mobile apps and CLIs with one POST request. Fields, responses, errors, limits and the OpenAPI spec.
- Hosted feedback pageEvery product gets a public feedback form at escutaproduto.com/f/your-slug. Share it in emails, app store listings, support replies and QR codes.
- Slack and Discord notificationsGet a Slack or Discord message the moment a customer sends feedback. Set one incoming webhook URL per product in Escuta Produto.