@mhosaic/feedback
v0.36.0
Published
Embeddable feedback + bug-report widget. Preact + Shadow DOM (renders inside any host app without leaking styles), opt-in modules for session replay, Web Vitals, and automatic error capture.
Readme
@mhosaic/feedback
Embeddable feedback + bug-report widget. Preact + Shadow DOM (renders inside any host app without leaking styles), opt-in modules for session replay, Web Vitals, and automatic error capture.
The fastest way to integrate is the guided Claude Code skill — it walks you through both halves (operator provisioning + consumer install), framework-aware, with a live smoke test that confirms a report lands in admin before declaring done.
The 30-second install (guided)
# 1. One-time: drop the skill into ~/.claude/skills/
npx @mhosaic/feedback-cli@latest install-skill
# 2. In any project where you want the widget:
cd ~/path/to/your-app
claudeInside Claude Code:
/integrate-feedbackThe skill asks one question (operator / consumer / both) and drives the rest: framework detection, env files, provider wiring, identify() recipe for your auth provider, smoke test in Chrome. Full docs: docs/INTEGRATING.md in the source repo.
Manual install
npm install @mhosaic/feedbackimport { createFeedback } from '@mhosaic/feedback'
import { withErrorTracking } from '@mhosaic/feedback/error-tracking'
import { withReplay } from '@mhosaic/feedback/replay'
import { withWebVitals } from '@mhosaic/feedback/webvitals'
const fb = withErrorTracking(
withReplay(
withWebVitals(createFeedback({
apiKey: 'pk_proj_…',
endpoint: 'https://your-feedback-backend.example.com',
env: 'prod',
}))
)
)
// Call identify() once auth resolves; FAB stays hidden until then.
fb.identify({ id: 'user-id', email: '[email protected]', name: 'User' })Or via CDN with pinned SRI:
<script
src="https://cdn.jsdelivr.net/npm/@mhosaic/[email protected]/dist/embed.min.js"
integrity="sha384-…"
crossorigin="anonymous"
data-key="pk_proj_…"
data-endpoint="https://your-feedback-backend.example.com"
data-env="prod"
defer
></script>Pin the exact version + integrity hash — @latest breaks SRI. Hash is published in each GitHub Release.
React provider
For React hosts, @mhosaic/feedback/react exposes <FeedbackProvider> + useFeedback():
import { FeedbackProvider } from '@mhosaic/feedback/react'
<FeedbackProvider apiKey={…} endpoint={…} env="prod">
<App />
</FeedbackProvider>The CLI auto-wires this for Vite + React apps on init. For Next/Remix/Vue/SvelteKit/Astro/Nuxt, see the framework-specific reference docs at packages/cli/skills/integrate-feedback/references/ (or ~/.claude/skills/integrate-feedback/references/ after install-skill).
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | — | Required. Public key for this project (e.g. pk_proj_…). Obtained during mhosaic-feedback provision. |
| endpoint | string | — | Required. Base URL of your mhosaic-feedback backend (e.g. https://feedback.example.com). The widget POSTs reports to ${endpoint}/api/feedback/v1/reports/. |
| env | string | prod | Environment tag (e.g. prod, staging, dev). Sent with every report; falls back to prod when unset. Useful for filtering backend reports by deployment. |
| user | UserIdentity | undefined | Host-supplied user identity (id, email, name). Set via fb.identify(…) after auth resolves; the FAB stays hidden until then. |
| metadata | object | undefined | Free-form key-value metadata sent with each report. Updated via fb.setMetadata(…). |
| getCurrentPage | function | () => window.location.pathname | Router-aware page-path resolver. Return the current page path (e.g. /dashboard) or null to fall back to pathname. Enables "feedback on this page" grouping when the Board is scoped. |
| openToCurrentPageFeedback | boolean | false | When true, opening the FAB jumps to the Board scoped to the current page (if that page has feedback), else the Send form. Default false — the FAB opens to Send by default so the primary submit flow is uninterrupted. The "This page" chip on the Send tab and the Board's page-scope toggle are always available. Note: the Send-tab strip now passively surfaces the same "feedback on this page" info regardless of this flag. |
| showPageActivity | boolean | true | Ambient page-activity surfaces: FAB count badge, hover peek panel, and the Send-tab "open reports on this page" strip. Identified users only. Set false to hide all three. The Board's This page / All pages control is always available. |
| showFAB | boolean | true | Show/hide the main feedback FAB. Set false to hide; call fb.show() / fb.hide() to toggle at runtime. |
| theme | string | auto | light | dark | auto | none accepted by the type, but not yet wired to a resolver — the widget always follows the host's prefers-color-scheme (i.e. auto behavior) regardless of this setting. |
| locale | string | auto-detected from navigator.language | Language code for UI text. Falls back to English for any locale other than fr, which ships built-in. |
| maskAllInputs | boolean | false | Accepted by the type but not currently wired to screenshot capture — setting it has no effect today. Screenshots are user-attached only (dropzone/paste/file picker/annotator); nothing in the current submit flow auto-captures or masks the DOM. |
| sanitizeUrl | function | — | Optional hook to redact sensitive URL segments before sending (e.g. tokens, session IDs). Receives the report's page_url; return the sanitized version. |
| beforeSend | function | — | Optional hook to intercept/modify a report before submission. Receives the payload; return modified payload, false to cancel, or a promise. Useful for adding custom fields or blocking reports by type/severity. |
| onSubmitSuccess | function | — | Optional callback on successful submission. Receives the SubmittedReport object (id, status, created_at). |
| onError | function | — | Optional callback on widget errors (e.g. network failures, validation errors). Receives the Error object. |
| attachTo | string | Element | — | CSS selector or DOM element for widget mount point. Defaults to document body. |
| translations | object | — | Override UI text strings. Merges with built-in locale strings. |
| qaMeter | QaMeterConfig | undefined | Opt-in QA Meter (second FAB). Set qaMeter.source to enable (URL, inline artifact, or async loader). See QA Meter integration. |
Opt-in modules
| Subpath | What it does | Approx gzip |
|---|---|---|
| @mhosaic/feedback/replay | rrweb session replay (last N seconds) | ~15 KiB |
| @mhosaic/feedback/webvitals | Core Web Vitals capture | ~3 KiB |
| @mhosaic/feedback/error-tracking | Auto-files synthetic reports on window.error + unhandledrejection | ~2 KiB |
All three are middleware wrappers — chain them around createFeedback(). See the install snippet above.
Backend
The widget POSTs to your mhosaic-feedback Django backend at /api/feedback/v1/reports/. The backend is multi-tenant (Company → Project → Report) and authenticates the widget by pk_proj_… Bearer key + origin allow-list. Source + deployment: https://github.com/mhosaic-technologies/feedback-tool-mhosaic.
Links
- Source code + issues: https://github.com/mhosaic-technologies/feedback-tool-mhosaic
- Design spec:
docs/superpowers/specs/2026-04-21-feedback-plugin-design.md - CLI:
@mhosaic/feedback-cli
