Support Widget
The FuzzyFlags support widget gives signed-in users a small feedback launcher inside your application. It turns feedback, requests, and bug reports into clear Linear issues with useful browser context.
Install
Load the widget bundle once, then mount it after your application confirms that the user is signed in:
<script src="https://support-widget.onfzf.app/app.js"></script><script> FzfSupport.mount({ apiKey: "YOUR_WIDGET_API_KEY", linearTeam: "YOUR_LINEAR_TEAM_ABBREVIATION", user: { id: currentUser.id, email: currentUser.email, name: currentUser.name, }, });</script>The script automatically loads its stylesheet and sends submissions to the
configured Linear team. Call FzfSupport.destroy() when the user logs out.
The copy button above copies this page as Markdown so it can be passed directly to an LLM or coding agent.
API key
Treat the widget API key as a server-side secret. Do not embed it in public HTML, a public JavaScript bundle, or a query string. Provide it to the frontend only through an authenticated endpoint that verifies the user’s session, then pass the returned value to FzfSupport.mount().
This reduces the risk of exposing the key to unauthenticated visitors and public source repositories. For a stronger installation boundary, use the signed-token flow described in the project README.
React
Load the widget script once and mount it when the authenticated user is available. Destroy it when the user signs out so a previous user’s identity is not left in the widget:
import { useEffect } from "react";
declare global { interface Window { FzfSupport?: { mount(options: { apiKey: string; linearTeam: string; user?: { id?: string; email?: string; name?: string }; }): void; destroy(): void; }; }}
type User = { id: string; email: string; name?: string };
export function SupportWidget({ user, apiKey,}: { user: User | null; apiKey: string;}) { useEffect(() => { if (!user) { window.FzfSupport?.destroy(); return; }
const mount = () => window.FzfSupport?.mount({ apiKey, linearTeam: "YOUR_LINEAR_TEAM_ABBREVIATION", user, });
if (window.FzfSupport) { mount(); return () => window.FzfSupport?.destroy(); }
const script = document.createElement("script"); script.src = "https://support-widget.onfzf.app/app.js"; script.async = true; script.onload = mount; document.head.append(script);
return () => { script.remove(); window.FzfSupport?.destroy(); }; }, [apiKey, user]);
return null;}Content Security Policy
The widget uses three cross-origin capabilities:
script-src(orscript-src-elem) to loadapp.js.style-src(orstyle-src-elem) because the widget addsapp.cssto the document head automatically.connect-srcfor the feedbackPOSTrequest.
For a policy that otherwise allows same-origin resources, add:
script-src 'self' https://support-widget.onfzf.app;style-src 'self' https://support-widget.onfzf.app;connect-src 'self' https://support-widget.onfzf.app;If the policy uses script-src-elem or style-src-elem, add the support origin
there too. The widget does not require unsafe-inline, unsafe-eval, image
sources, font sources, or inline-style allowances. The inline React bootstrap
shown above is still subject to your app’s normal inline-script policy: put it
in a bundled file, or add your app’s nonce/hash to that bootstrap when needed.