Step-by-step setup for popular frameworks.
Next.js (App Router)
1. Install the SDK
npm install @conclude-fyi/react
2. Create a client component
// app/feedback-widget.tsx
"use client";
import { ConcludeProvider, FeedbackButton } from "@conclude-fyi/react";
export function FeedbackWidget() {
return (
<ConcludeProvider
apiKey={process.env.NEXT_PUBLIC_CONCLUDE_API_KEY!}
submitter={{
externalId: currentUser.id,
name: currentUser.name,
email: currentUser.email,
}}
>
<FeedbackButton />
</ConcludeProvider>
);
}
3. Add to your layout
// app/layout.tsx
import { FeedbackWidget } from "./feedback-widget";
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<FeedbackWidget />
</body>
</html>
);
}
No frame-src CSP needed — the SDK renders natively, not in an iframe. If your app has a connect-src CSP directive, add https://www.conclude.fyi so the SDK can fetch your widget config and submit feedback.
React (Vite / CRA)
1. Install
npm install @conclude-fyi/react
2. Add to your App component
// src/App.tsx
import { ConcludeProvider, FeedbackButton } from "@conclude-fyi/react";
function App() {
return (
<ConcludeProvider
apiKey={import.meta.env.VITE_CONCLUDE_API_KEY}
submitter={{
externalId: user.id,
name: user.name,
email: user.email,
}}
>
<div className="app">
{/* Your app content */}
</div>
<FeedbackButton />
</ConcludeProvider>
);
}
That's it — no iframe or routing config. If your app sends a CSP header, allow https://www.conclude.fyi in connect-src.
Vanilla JavaScript / any website
No build step, no framework. Paste this before </body>:
<script src="https://www.conclude.fyi/conclude-widget.js"></script>
<script>
Conclude.init({
apiKey: "pk_live_YOUR_BOARD_KEY",
// All optional — uses dashboard config by default:
// position: "bottom-right",
// label: "Feedback",
// accentColor: "#8083ff",
submitter: {
externalId: "user-123",
name: "Jane Doe",
email: "jane@acme.com",
companies: [
{ id: "co_acme", name: "Acme Inc", monthlySpend: 5000 }
]
}
});
</script>
The script fetches your widget config from the dashboard (theme, colors, modes, label). Override any option in the init() call. On mobile, the button shows just an icon. See Identifying users and companies for the full submitter shape.
Common patterns
Identify the user only after they sign in
In React, conditionally render ConcludeProvider only after auth resolves. Or pass the user as a stable, possibly-null object — the SDK handles partial identification gracefully.
Hide the button on certain pages
Use route-based conditional rendering. The SDK only renders what you tell it to.
Multiple boards
If you want different boards on different parts of your app, instantiate separate ConcludeProviders with different API keys, scoped by route.