Add a feedback board to Next.js

Add a Feedback button to your Next.js app with the usernote npm package or next/script, open it from your own button, or put the board and roadmap on their own pages. About 5 KB over the network, loaded after your page is interactive.

Before you start

Sign up free at getusernote.com, create a board, and copy your board ID from the board’s Install tab (it starts with ws_). Replace ws_YOUR_BOARD_ID in the snippets below with it.

With the npm package (recommended)

Install the usernote package, then add the component once in your root layout, so the Feedback button appears on every page. It’s marked “use client”, so you can use it directly in a Server Component layout.

npm install usernote
import { UserNote } from 'usernote/react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <UserNote board="ws_YOUR_BOARD_ID" />
      </body>
    </html>
  );
}

A board or roadmap page of its own, which works with client-side navigation:

// app/roadmap/page.tsx
import { UserNote } from 'usernote/react';

export default function Roadmap() {
  return <UserNote board="ws_YOUR_BOARD_ID" inline view="roadmap" />;
}

Your own button instead of the floating one:

import { UserNote, open } from 'usernote/react';

<UserNote board="ws_YOUR_BOARD_ID" launcher={false} />
<button onClick={open}>Give feedback</button>

Without the package: App Router (app/layout.tsx)

Add the script once in your root layout, so the Feedback button appears on every page:

import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://getusernote.com/widget.js" data-workspace="ws_YOUR_BOARD_ID" strategy="afterInteractive" />
      </body>
    </html>
  );
}

Without the package: Pages Router (pages/_app.tsx)

import Script from 'next/script';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Script src="https://getusernote.com/widget.js" data-workspace="ws_YOUR_BOARD_ID" strategy="afterInteractive" />
    </>
  );
}

Use your own button

Add data-launcher="false" to hide the floating button, then open the board from anywhere in your app, such as a menu item:

<Script src="https://getusernote.com/widget.js" data-workspace="ws_YOUR_BOARD_ID" data-launcher="false" strategy="afterInteractive" />

// anywhere in your app
<button onClick={() => (window as any).UserNote?.open()}>Give feedback</button>

A roadmap page

With the npm package, use <UserNote inline view="roadmap" /> on the page (above). With the plain script tag, the script finds an inline board’s target element once, when it loads, so an inline embed on one route doesn’t suit client-side navigation; link to your hosted roadmap instead (a plain <a>, not next/link):

<a href="https://getusernote.com/b/ws_YOUR_BOARD_ID?view=roadmap">Roadmap</a>

Content Security Policy

If you set a CSP header (for example in middleware or next.config), allow UserNote in two directives. No unsafe-inline is needed for styles.

script-src  https://getusernote.com
connect-src https://getusernote.com

Next steps

  • Settings → Allowed websites: add your domain so nobody can embed your board elsewhere.
  • Settings → Accent color: match the button to your brand.
  • Turn on Require approval if you want to check ideas before they appear.