fdback.iofdback.io

Next.js Integration

Server-side helpers for Next.js App Router

npm install @fdback.io/sdk server-only

The /next subpath includes server-only protection to prevent accidental client-side imports.

Option 1: API Route Handler

Create a route that handles signing:

// app/api/fdback/sign/route.ts
import { createSignHandler } from "@fdback.io/sdk/next";

export const POST = createSignHandler({
  workspaceId: process.env.FDBACK_WORKSPACE_ID!,
  workspaceSecret: process.env.FDBACK_WORKSPACE_SECRET!,
});

With Authentication

// app/api/fdback/sign/route.ts
import { createSignHandler } from "@fdback.io/sdk/next";
import { auth } from "@/server/auth";

export const POST = createSignHandler({
  workspaceId: process.env.FDBACK_WORKSPACE_ID!,
  workspaceSecret: process.env.FDBACK_WORKSPACE_SECRET!,
  authorize: async () => {
    const session = await auth();
    return !!session?.user;
  },
  getUser: async () => {
    const session = await auth();
    if (!session?.user?.email) return null;
    return {
      email: session.user.email,
      name: session.user.name ?? undefined,
      avatar: session.user.image ?? undefined,
    };
  },
});

Option 2: Server Action

Create a server action for use with React Server Components:

// lib/fdback.ts
"use server";
import { createSignAction } from "@fdback.io/sdk/next";
import { auth } from "@/server/auth";

const _signAction = createSignAction({
  workspaceId: process.env.FDBACK_WORKSPACE_ID!,
  workspaceSecret: process.env.FDBACK_WORKSPACE_SECRET!,
});

// Wrap with auth check
export async function signFdbackLogin() {
  const session = await auth();
  if (!session?.user?.email) {
    return { success: false as const, error: "Unauthorized" };
  }
  return _signAction({
    email: session.user.email,
    name: session.user.name ?? undefined,
    avatar: session.user.image ?? undefined,
  });
}

Use in client component:

"use client";
import { signFdbackLogin } from "@/lib/fdback";
import { useFdback } from "@fdback.io/sdk/react";

export function FeedbackButton() {
  const { open } = useFdback();

  const handleClick = async () => {
    const result = await signFdbackLogin();
    if (result.success) {
      open(result.data);
    } else {
      console.error(result.error);
    }
  };

  return <button onClick={handleClick}>Feedback</button>;
}

API Reference

ExportDescription
createSignHandler(options)Creates a POST route handler
createSignAction(options)Creates a server action factory

SignHandlerOptions

interface SignHandlerOptions {
  workspaceId: string;
  workspaceSecret: string;
  baseUrl?: string;
  authorize?: (request: Request) => Promise<boolean> | boolean;
  getUser?: (request: Request) => Promise<FdbackUser | null> | FdbackUser | null;
}

SignActionOptions

interface SignActionOptions {
  workspaceId: string;
  workspaceSecret: string;
  baseUrl?: string;
}

Complete Example

1. Environment variables

FDBACK_WORKSPACE_ID=your-workspace-id
FDBACK_WORKSPACE_SECRET=your-workspace-secret
NEXT_PUBLIC_FDBACK_WORKSPACE_ID=your-workspace-id

2. API route

// app/api/fdback/sign/route.ts
import { createSignHandler } from "@fdback.io/sdk/next";
import { auth } from "@/server/auth";

export const POST = createSignHandler({
  workspaceId: process.env.FDBACK_WORKSPACE_ID!,
  workspaceSecret: process.env.FDBACK_WORKSPACE_SECRET!,
  authorize: async () => !!(await auth())?.user,
  getUser: async () => {
    const session = await auth();
    if (!session?.user?.email) return null;
    return {
      email: session.user.email,
      name: session.user.name ?? undefined,
    };
  },
});

3. Provider setup

// app/layout.tsx
import { FdbackProvider } from "@fdback.io/sdk/react";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <FdbackProvider
          workspaceId={process.env.NEXT_PUBLIC_FDBACK_WORKSPACE_ID!}
          signEndpoint="/api/fdback/sign"
        >
          {children}
        </FdbackProvider>
      </body>
    </html>
  );
}

4. Feedback button

// components/feedback-button.tsx
"use client";
import { FeedbackButton } from "@fdback.io/sdk/react";
import { useSession } from "next-auth/react";

export function AppFeedbackButton() {
  const { data: session } = useSession();

  if (!session?.user?.email) return null;

  return (
    <FeedbackButton
      user={{
        email: session.user.email,
        name: session.user.name ?? undefined,
        avatar: session.user.image ?? undefined,
      }}
      className="fixed bottom-4 right-4 rounded-full bg-primary px-4 py-2 text-white"
    >
      Feedback
    </FeedbackButton>
  );
}

On this page