English | 한국어
A lightweight npm module to collect user feedback and bug reports with visual context (screenshot, DOM selector, comments).
KokFeedback mounts as a sandboxed widget on your web application, allowing users to report issues by capturing screen areas, selecting DOM elements, and adding inline comments.
- 🎯 Intuitive DOM Targeting: Highlight and select problem areas via hover (desktop) or touch (mobile).
- 📸 Automatic Screen Capture: Automatically encodes selected screen areas to Base64 images.
- 💬 Inline Comments: Add text feedback directly over captured screen areas.
- 🎨 Style Isolation (Shadow DOM): Rendered inside Shadow DOM, strictly isolated from host app CSS.
- ⚡ Performance Optimized: Utilizes Debounce and RequestAnimationFrame to minimize reflows (~63KB gzipped).
- 🌐 Automatic i18n & Localization: Auto-detects browser language (
en/ko) or supports explicit override vialangconfig. - ♿ Accessibility: Focus Trap and
ESCkey shortcuts supported. - 📱 Responsive: Native support for PC (mouse) and Mobile (touch) interactions.
- 🔧 Highly Customizable: Theme, colors, positioning, z-index, and text labels are fully configurable.
# npm
npm install kok-feedback
# yarn
yarn add kok-feedback
# pnpm
pnpm add kok-feedbackConnect seamlessly with a Supabase backend without building a custom server.
import KokFeedback from 'kok-feedback';
KokFeedback.init({
projectId: process.env.NEXT_PUBLIC_PROJECT_ID, // Unique project key
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL,
supabasePublishableKey: process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
});Environment Variables Example (.env)
# Next.js
NEXT_PUBLIC_PROJECT_ID=MY-SERVICE-WEB
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...
# Vite
VITE_PROJECT_ID=MY-SERVICE-WEB
VITE_SUPABASE_URL=https://xxxx.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=sb_publishable_...💡 Why is
projectIdrequired?
- Multi-project Identification: Serves as a unique identifier when sharing a single Supabase backend across multiple web applications.
- Storage Folder Segmentation: Automatically categorizes uploaded screenshot images into subfolders named after the
projectId.
If using your own backend API, specify the endpoint URL.
KokFeedback.init({
projectId: 'MY-SERVICE-WEB',
endpoint: 'https://api.example.com/v1/feedback',
// Customization Options (Optional)
theme: 'dark', // 'light' | 'dark'
zIndex: 9999, // Widget z-index
buttonPosition: 'bottom-right', // 'bottom-right' | 'bottom-left'
buttonColor: '#FF6B6B', // Button accent color
buttonText: 'Feedback', // Button label
});👉 [Click to Expand] Supabase SQL Tables, RLS Security Policies & Storage Setup Script
Execute the following script inside the SQL Editor in your Supabase Dashboard:
-- 1. Create feedbacks table
CREATE TABLE public.feedbacks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
project_id TEXT NOT NULL,
type TEXT NOT NULL,
priority TEXT NOT NULL,
message TEXT NOT NULL,
status TEXT DEFAULT 'new',
image_url TEXT,
page_url TEXT,
selector TEXT,
viewport TEXT,
user_agent TEXT
);
-- 2. Enable RLS and setup policies
ALTER TABLE public.feedbacks ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Enable insert feedback for all"
ON public.feedbacks FOR INSERT TO anon, authenticated WITH CHECK (true);
CREATE POLICY "Enable select feedback for authenticated users only"
ON public.feedbacks FOR SELECT TO authenticated USING (true);
CREATE POLICY "Enable update feedback for authenticated users only"
ON public.feedbacks FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
-- 3. Create feedback comments table & RLS
CREATE TABLE IF NOT EXISTS public.feedback_comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ DEFAULT now(),
feedback_id UUID REFERENCES public.feedbacks(id) ON DELETE CASCADE,
user_id UUID DEFAULT auth.uid(),
message TEXT NOT NULL
);
ALTER TABLE public.feedback_comments ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow select comments" ON public.feedback_comments FOR SELECT TO authenticated, anon USING (true);
CREATE POLICY "Allow insert comments" ON public.feedback_comments FOR INSERT TO authenticated, anon WITH CHECK (true);
-- 4. Create View for feedback comments with user email
CREATE OR REPLACE VIEW public.feedback_comments_with_email AS
SELECT fc.id, fc.created_at, fc.feedback_id, fc.user_id, fc.message, au.email AS user_email
FROM public.feedback_comments fc
LEFT JOIN auth.users au ON fc.user_id = au.id;
GRANT SELECT ON public.feedback_comments_with_email TO authenticated, anon;
-- 5. Create storage bucket & policies
INSERT INTO storage.buckets (id, name, public)
VALUES ('feedbacks', 'feedbacks', true)
ON CONFLICT (id) DO NOTHING;
CREATE POLICY "Enable upload for anonymous users"
ON storage.objects FOR INSERT TO public WITH CHECK (bucket_id = 'feedbacks');
CREATE POLICY "Enable public read access"
ON storage.objects FOR SELECT TO public USING (bucket_id = 'feedbacks');Initializes the feedback widget on the DOM.
interface Config {
projectId: string; // Required: Unique project identifier
endpoint?: string; // Custom API endpoint URL
supabaseUrl?: string; // Supabase URL (Recommended)
supabasePublishableKey?: string;// Supabase Publishable Key (Recommended)
theme?: 'light' | 'dark'; // Default: 'light'
lang?: 'auto' | 'en' | 'ko'; // Default: 'auto'
zIndex?: number; // Default: 9999
buttonPosition?: string; // Default: 'bottom-right'
buttonColor?: string; // Default: '#007BFF'
buttonText?: string; // Default: 'Feedback'
}Unmounts the widget and cleans up all event listeners.
KokFeedback.destroy();{
"type": "bug",
"priority": "p1",
"message": "The login button is unresponsive.",
"imageData": "data:image/png;base64,iVBORw0KGgoAAAAN...",
"metadata": {
"url": "https://example.com/login",
"selector": "body > div.container > button#login",
"viewport": "1920x1080",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
}
}- 🐙 GitHub Repository: postforty/kok-feedback
- 🐛 Issue Tracker: Report Bug / Feature Request
- 📜 PRD Specification: Product Requirements Document
- 🇰🇷 Korean Documentation: 한국어 문서