loupfeed › Feedback
A user long-presses the thing that is wrong and types a sentence. What reaches you is not a screenshot and a guess — it is that exact element, resolved to src/file.tsx:54, with the session that led there and everything your app knew at the time.
React, Vue, Svelte, React Native and Expo · npm i @loupfeed/react
Your users do the first one. The other three happen on their own.
Long-press any element in the running app, or open the composer from your own button. The pin sticks to that element.
The element's identity, the route, the release, your app context, the breadcrumb trail, and the last seconds of replay.
Only an opaque hash leaves the browser. The map from hash to source stays on your server.
The dashboard — or your agent over MCP — resolves it against the manifest for that exact release.
Most feedback tools pin a comment to x/y coordinates on a page, which stops meaning anything the moment the layout changes. loupfeed tags every element at build time with an opaque, deterministic id and pins the thread to that.
id → src:line into a manifest, keyed by version@commitIf the plugin is not installed, the SDK falls back to a root-relative CSS path so feedback still works — you just do not get the jump to source.
This is not a setting. Runtime packages never import the build packages — the two halves meet only through the data-fb attribute and the manifest format. CI greps the built bundles for src/ and .tsx: and fails the build on a hit.
Run pnpm check:privacy yourself — it is the same check that guards every release of loupfeed.
Turning an id back into a path happens behind your ingest API, on infrastructure you control.
beforeSend hands you the whole event before it leaves the device, to redact or drop.
Every pin opens a thread on that element. You reply from the dashboard or straight from your agent, and the reporter sees the answer inside the app they reported from — not in an email they will not open.
open, resolved, wontfixReact Native has no DOM, so the opaque id rides as an fbId prop threaded onto the native view's testID. The inspector hit-tests a touch with measureInWindow — the native analogue of the web overlay — and pins feedback to the nearest tagged view.
The adapter mounts the overlay in a shadow DOM, so nothing of yours is restyled and nothing of ours leaks into your CSS. Pick the plugin that matches your bundler — they all share one tagger and one manifest format.
| Layer | Packages |
|---|---|
| Web adapters | @loupfeed/react, /vue, /svelte |
| Mobile | @loupfeed/react-native, /expo-inspector |
| Bundlers | vite-plugin, webpack-plugin, rollup-plugin, esbuild-plugin |
| Compilers | babel-plugin (Next, Metro), svelte-preprocess, vue-plugin |
Feedback is exposed through @loupfeed/mcp, so the agent you already use picks it up with everything attached — the resolved source line, the contexts, the breadcrumbs and a readable replay — then replies to the reporter and sets the status itself.
Free to self-host, forever, and source-available so you can read every line before you trust it with your users.