Skip to content

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 (or script-src-elem) to load app.js.
  • style-src (or style-src-elem) because the widget adds app.css to the document head automatically.
  • connect-src for the feedback POST request.

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.