A drop-in feedback widget for capturing user feedback and turning it into actionable pull requests.
Features:
- π― Shadow DOM isolation β no style conflicts with host page
- π Privacy-first β PII redaction (emails, phone numbers, SSNs, credit cards)
- π Lightweight β ~38KB gzipped (includes loader, main chunk, and bootstrap capture)
- πΈ Rich context capture β console errors, network requests, DOM interactions, viewport state
- π Content Security Policy compliant β works in strict CSP environments (one known exception, see docs/CSP.md)
- π Multi-locale β English, Polish, and more
- π SSO-ready β optional JWT-verified submitter identity for B2B apps
Works everywhere:
- Script tag embed (any website)
- React/Vue/Svelte (same script tag, loaded from a lifecycle hook)
- Vanilla JavaScript
Add this to your HTML <head>, before the opening <body>:
<meta name="feedby-build-sha" content="your-app-version">
<script>
window.FeedbyConfig = {
widgetKey: "wk_live_YOUR_WIDGET_KEY",
locale: "en",
position: "bottom-right"
};
</script>
<script async src="https://feedby.borg.tools/v1/feedby.global.js"></script>The widget loads asynchronously and won't block your page.
This is a source repo (build it yourself, or use the hosted
feedby.global.js above) β there is no importable npm package. In a
React/Vue/Svelte app, load the same script tag from a top-level lifecycle
hook instead of hardcoding it in HTML:
import { useEffect } from 'react';
export default function RootLayout({ children }) {
useEffect(() => {
// Set config
window.FeedbyConfig = {
widgetKey: "wk_live_YOUR_WIDGET_KEY",
locale: navigator.language.split('-')[0],
buildSha: process.env.REACT_APP_VERSION
};
// Load widget
const script = document.createElement('script');
script.async = true;
script.src = 'https://feedby.borg.tools/v1/feedby.global.js';
document.head.appendChild(script);
}, []);
return (
<>
{children}
</>
);
}Set window.FeedbyConfig before the widget script loads:
window.FeedbyConfig = {
// Required
widgetKey: "wk_live_xxx",
// Recommended
locale: "pl", // 'en', 'pl', 'de', 'fr', etc.
position: "bottom-right", // 'bottom-right', 'bottom-left', 'top-right', 'top-left'
theme: "auto", // 'light', 'dark', 'auto'
buildSha: "v1.2.3+abc123", // Your app version for debugging
// Optional: multi-tenant + SSO
user: {
id: "u-123", // User's internal ID
email: "user@example.com", // (requires ssoJwt)
name: "Jane Doe", // (requires ssoJwt)
companyId: "org-456", // (requires ssoJwt)
role: "admin" // (requires ssoJwt)
},
ssoJwt: "eyJ..." // HS256 JWT signed by your backend
};For apps with authentication, mint a server-side JWT and pass it to the widget:
Backend (Python Flask/FastAPI example):
import jwt, time, os
def mint_feedby_jwt(user_id, email, name, company_id):
secret = os.environ["FEEDBY_SSO_SECRET"]
project_id = os.environ["FEEDBY_PROJECT_ID"]
payload = {
"sub": str(user_id),
"aud": project_id,
"iat": int(time.time()),
"exp": int(time.time()) + 3600,
"email": email,
"name": name,
"company_id": company_id
}
return jwt.encode(payload, secret, algorithm="HS256")Frontend:
// After user logs in
async function initFeedbyWithAuth() {
const token = localStorage.getItem("auth_token");
const response = await fetch("/api/feedby-jwt", {
headers: { "Authorization": `Bearer ${token}` }
});
const { ssoJwt, user } = await response.json();
window.FeedbyConfig = {
widgetKey: "wk_live_xxx",
user,
ssoJwt
};
// Now load widget
const script = document.createElement("script");
script.async = true;
script.src = "https://feedby.borg.tools/v1/feedby.global.js";
document.head.appendChild(script);
}The widget lives in a Shadow DOM tree isolated from your page's styles and scripts. CSS from your page won't leak into the widget, and widget styles won't affect your app.
Before sending feedback, the widget automatically redacts:
- Email addresses (user@example.com β u***@example.com)
- Phone numbers (555-1234 β 5***1234)
- Social security numbers (*--4321)
- Credit card numbers (****4321)
- API keys and tokens
Redaction happens client-side before transmission.
submitter_source: 'verified'β JWT signature valid, identity provensubmitter_source: 'jwt_claimed'β JWT provided but not verified server-side (public submission)submitter_source: 'unverified'β No JWT; user context is a claim only
To enable server-side verification, the Feedby platform must:
- Store an
sso_secretper project - Enable the
SSO_ENFORCE_INGESTflag on your Feedby admin instance - Your host application must mint a valid HS256 JWT using that secret
See docs/SSO.md for detailed SSO implementation.
The widget is CSP-compliant and works in strict CSP environments:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://feedby.borg.tools;
connect-src 'self' https://feedby-admin.borg.tools;No inline styles, no eval, no unsafe-inline for the core widget β one lazy-loaded optional feature (the screenshot annotate overlay) is a known exception, see docs/CSP.md.
- docs/EMBED.md β Comprehensive embedding guide (script tag, React, Vue, Svelte, multi-tenant)
- docs/CSP.md β Content Security Policy compliance
- docs/SSO.md β SSO JWT authentication and server-side verification
- docs/BUDGET.md β Bundle size audit and optimization notes
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run dev
# Run tests
npm run test
npm run test:watch
# Type check
npm run typecheck
# Check bundle size
npm run size
# CSP compliance audit (currently reports 1 known violation β the
# annotate overlay's <style> tag, see docs/CSP.md#known-limitation-annotate-overlay)
npm run csp-auditloader (feedby.global.js) β IIFE that:
- Seeds shared capture buffers
- Installs always-on hooks (console, fetch, XHR, errors, clicks)
- Runs PII classifier
- Lazy-loads the main widget when user clicks FAB
main chunk (feedby-main.mjs) β Opens panel, handles UI, processes screenshot + annotations
bootstrap (feedby-bootstrap.global.js) β Optional early-load script that captures events before main widget loads (closes a capture blackout window during script loading)
See tsup.config.ts for entry points and src/ for module organization.
This widget is open source (MIT). The Feedby platform (admin dashboard, backend, CRM integration, analytics) is a separate commercial product at https://feedby.borg.tools.
MIT Β© 2026 Wojciech Wiesner
Questions? Open an issue on GitHub or visit feedby.borg.tools.