npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

akk-feedback

v1.2.14

Published

Drop-in feedback widget for React apps with automatic context capture

Readme

@bernstein/feedback

npm version License TypeScript React

A drop-in feedback widget for React applications that captures user feedback with automatic context collection. Part of the Bernstein observability ecosystem.


Commercialization Architecture (ADR)

1. Persistent Configuration Strategy

Decision: We use a client-side useFeedbackConfig hook persisted via localStorage to manage the "Freemium" state (Adapter ID, Credentials, Theme). Context:

  • The widget must be usable without a backend (Free Tier).
  • The "Pro" upgrade (Supabase) happens client-side by injecting a generic SupabaseAdapter.
  • localStorage ensures settings survive reload without requiring a dedicated auth service for the widget itself.

2. Dependency Injection for Adapters

Decision: The <FeedbackProvider> accepts an adapter prop at runtime rather than hardcoding imports. Consequences:

  • Flexibility: We can hot-swap between ConsoleAdapter (Dev), LocalStorageAdapter (Offline), and SupabaseAdapter (Cloud) instantly.
  • Testing: Integration tests can inject a mock adapter without mocking network requests directly.
  • Security: Secrets (like Supabase keys) are injected into the adapter instance, not hardcoded in the bundle.

3. Security & Validation

Decision: We enforce a "Trust but Verify" model.

  • Frontend: Code strips sensitive data (redaction) before transmission.
  • Backend (Supabase): RLS policies (INSERT only for public) ensure that even if a key is exposed, malicious actors cannot read other users' feedback.

⚡ 5-Minute Quickstart

Add a fully functional feedback widget to your app in under 5 minutes. No backend required to test!

1. Install

npm install @bernstein/feedback

2. Drop it in

Add this to your root component (e.g., App.tsx or layout.tsx):

import { FeedbackProvider, FeedbackDialog, FeedbackButton } from "@bernstein/feedback";
import { consoleAdapter } from "@bernstein/feedback/adapters";
import "@bernstein/feedback/styles.css";

function App() {
  return (
    <FeedbackProvider
      config={{
        projectId: "test-project",
        // The console adapter logs feedback to your browser console
        // Perfect for testing without an API key!
        adapter: consoleAdapter(), 
      }}
    >
      <YourApp />
      
      {/* The floating trigger button */}
      <FeedbackButton />
      
      {/* The feedback modal/dialog */}
      <FeedbackDialog />
    </FeedbackProvider>
  );
}

3. Test it!

Click the "Feedback" button -> Select "Feedback" -> Type "Hello World" -> Submit. Check your browser console to see the captured data!


Integration Guide

To add Bernstein Feedback to your production website or app:

  1. Wrap your application root with FeedbackProvider.
  2. Add FeedbackDialog adjacent to your app content (it handles the modal overlay).
  3. Add a Trigger:
    • Use <FeedbackButton /> for the default floating button.
    • Use const { openFeedback } = useFeedback() to trigger it from your own buttons/menus.
  4. Configure a Real Adapter: Switch from consoleAdapter to httpAdapter or supabaseAdapter for production.

Features

  • Three feedback modes — Feedback, Feature Request, Bug Report
  • User-friendly bug triage — "How bad is it?" with Blocks me / Annoying / Minor
  • Automatic context capture — URL, viewport, console errors, network errors, user breadcrumbs
  • Screenshot capture — High-res, viewport-locked capture (Retina quality)
  • Highlight mode — Let users click to highlight a specific element
  • Consent toggles — "We'll include" section with clear opt-in/opt-out
  • Privacy-safe by default — No request/response bodies, no form values, no keystrokes
  • Auto-redaction — Emails, phone numbers, credit cards, API keys automatically redacted
  • Themeable — CSS custom properties with automatic dark mode support

Configuration

Required

| Prop | Type | Description | |------|------|-------------| | projectId | string | Project identifier | | adapter | FeedbackAdapter | Backend adapter |

Screen Identity

| Prop | Type | Description | |------|------|-------------| | screenId | string | Stable screen ID (e.g., 'checkout') | | pageName | string | Human-readable page name |

Build Identity

| Prop | Type | Description | |------|------|-------------| | appVersion | string | App version | | env | 'production' \| 'staging' \| 'development' | Environment |


Adapters

HTTP Adapter (Webhooks / Custom Backend)

import { httpAdapter } from "@bernstein/feedback/adapters";

const adapter = httpAdapter({
  endpoint: "https://api.yourcompany.com/feedback",
  headers: { "Authorization": "Bearer token" },
});

Supabase Adapter (Direct to Database)

import { supabaseAdapter } from "@bernstein/feedback/adapters";

const adapter = supabaseAdapter({
  supabaseUrl: process.env.VITE_SUPABASE_URL,
  supabaseKey: process.env.VITE_SUPABASE_ANON_KEY,
  table: "feedback", // Default
});

Theming & Dark Mode

The widget uses CSS variables and automatically respects [data-theme="dark"] on the <html> element.

:root {
  --feedback-primary: #3b82f6;
  --feedback-bg: #ffffff;
  --feedback-text: #111827;
}

[data-theme='dark'] {
  --feedback-bg: #1f2937;
  --feedback-text: #f3f4f6;
}

See docs/theming.md for full customization details.


License

Apache 2.0