@inov-ai/feedback-widget
v1.0.2
Published
Modern React feedback widget with surveys, analytics, and Next.js 15 support. Collect user feedback and run surveys in your SaaS applications.
Maintainers
Readme
@inov-ai/feedback-widget
A modern, customizable React feedback widget with surveys, feedback collection, and analytics. Perfect for SaaS applications with full Next.js 15 support and TypeScript.
About inov-ai
inov-ai is a comprehensive feedback collection and analytics platform designed to help businesses gather valuable insights from their users. With advanced analytics, real-time feedback processing, and intelligent survey management, Inov-AI empowers companies to make data-driven decisions and improve their products based on actual user feedback.
To get started with this widget, you'll need to:
- Sign up for a free account at https://www.inov-ai.tech/
- Create a new project in your dashboard
- Get your unique site key
- Install and configure this widget in your application
Features
- ✅ Next.js 15 Compatible - No CSP issues, SSR-safe, hydration-friendly
- ✅ TypeScript Support - Full type safety out of the box
- ✅ Dual Collection Methods - Quick feedback + detailed surveys
- ✅ Smart Path Control - Show widget only on specific routes
- ✅ Theme Detection - Auto-detects light/dark themes or use custom
- ✅ Highly Customizable - Colors, positions, triggers, animations
- ✅ Zero Dependencies - Only requires React as peer dependency
- ✅ Mobile Responsive - Works perfectly on all devices
- ✅ Real-time Analytics - Track feedback and survey responses
Installation
npm install @inov-ai/feedback-widget
# or
yarn add @inov-ai/feedback-widget
# or
pnpm add @inov-ai/feedback-widgetQuick Start
The simplest way to get started is to add the widget to your app with minimal configuration:
1. Basic Setup
import { InovaiWidget } from '@inov-ai/feedback-widget';
function App() {
return (
<div>
{/* Your app content */}
<h1>My Amazing SaaS App</h1>
{/* Add the feedback widget */}
<InovaiWidget siteKey="your-site-key" />
</div>
);
}2. Complete Example (Recommended)
This is the most common setup that works great for most applications:
import { InovaiWidget } from '@inov-ai/feedback-widget';
function App() {
return (
<div>
{/* Your app content */}
<h1>My SaaS Dashboard</h1>
{/* Feedback widget with full configuration */}
<InovaiWidget
siteKey="your-site-key"
primaryColor="#f97316"
fontFamily="Inter, system-ui, -apple-system, sans-serif"
fontSize="16px"
buttonRadius="8px"
position="bottom-right"
buttonText="Feedback"
buttonIcon="💬"
theme="auto"
animation="slide"
trigger="manual"
triggerDelay={0}
surveyFrequency="every-visit"
minimized={false}
feedbackTypes={["Bug", "Feature", "Suggestion", "Question"]}
paths={["/", "/dashboard", "/feedback", "/analytics"]}
onSubmit={(data) => {
console.log('Feedback submitted:', data);
// Integrate with your analytics or logging system
}}
onError={(error) => {
console.error('Widget error:', error);
}}
/>
</div>
);
}3. Next.js 15 Setup
// app/layout.tsx (App Router) or pages/_app.tsx (Pages Router)
import { InovaiWidget } from '@inov-ai/feedback-widget';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
{/* Add feedback widget to every page */}
<InovaiWidget
siteKey={process.env.NEXT_PUBLIC_FEEDBACK_SITE_KEY}
primaryColor="#f97316"
position="bottom-right"
theme="auto"
paths={["/dashboard", "/app", "/settings"]} // Only show on specific routes
/>
</body>
</html>
);
}Configuration Options
Required Props
| Prop | Type | Description |
|------|------|-------------|
| siteKey | string | Your unique site key from inov-ai dashboard |
Appearance Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| primaryColor | string | #f97316 | Main color for buttons and highlights |
| textColor | string | Auto-detected | Text color (auto-detected from theme) |
| backgroundColor | string | Auto-detected | Modal background color |
| theme | 'light' \| 'dark' \| 'auto' \| 'system' | auto | Color theme preference |
| fontFamily | string | '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' | Font family |
| fontSize | string | 16px | Base font size |
| buttonRadius | string | 8px | Border radius for buttons |
| position | 'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left' | bottom-right | Widget position |
| buttonText | string | Feedback | Text on the trigger button |
| buttonIcon | string | '' | Icon/emoji for the button |
| animation | 'slide' \| 'fade' \| 'none' | slide | Opening animation |
Behavior Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| trigger | 'manual' \| 'auto' \| 'timer' \| 'scroll' \| 'exit' | manual | How the widget opens |
| triggerDelay | number | 0 | Delay in milliseconds for auto triggers |
| paths | string[] | [] | URL paths where widget should appear (empty = all paths) |
| surveyFrequency | 'once' \| 'every-visit' \| 'daily' \| 'weekly' | every-visit | How often to allow feedback |
| minimized | boolean | false | Start in minimized state |
| feedbackTypes | string[] | ['Feature Request', 'Bug Report', 'Integration', 'Question'] | Available feedback categories |
Event Props
| Prop | Type | Description |
|------|------|-------------|
| onOpen | () => void | Called when widget opens |
| onClose | () => void | Called when widget closes |
| onSubmit | (data: FeedbackSubmission) => void | Called when feedback is submitted |
| onError | (error: Error) => void | Called when an error occurs |
Path Configuration
The paths prop allows you to control where the widget appears:
// Show on specific pages only
<InovaiWidget
siteKey="your-key"
paths={["/", "/dashboard", "/settings"]}
/>
// Show on all dashboard routes
<InovaiWidget
siteKey="your-key"
paths={["/dashboard*"]}
/>
// Show everywhere (default)
<InovaiWidget
siteKey="your-key"
// paths prop omitted or empty array
/>Survey Integration
The widget automatically fetches and displays surveys from your inov-ai dashboard. Users can:
- Quick Feedback: Submit general feedback with categories
- Surveys: Answer detailed survey questions when available
Advanced Examples
With Custom Styling
.fb-widget-button {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
## Advanced Examples
### With Custom Styling
```jsx
<InovaiWidget
siteKey="your-site-key"
primaryColor="#6366f1"
theme="dark"
position="bottom-left"
buttonText="Help Us Improve"
buttonIcon="📝"
customCSS={`
[data-feedback-widget] {
--feedback-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
`}
/>With Analytics Integration
<InovaiWidget
siteKey="your-site-key"
onSubmit={(data) => {
// Send to your analytics
analytics.track('Feedback Submitted', {
category: data.category,
page: data.metadata.page_url,
rating: data.rating
});
// Show success message
toast.success('Thank you for your feedback!');
}}
onError={(error) => {
// Log errors
console.error('Feedback widget error:', error);
Sentry.captureException(error);
}}
/>Timer-based Trigger
<InovaiWidget
siteKey="your-site-key"
trigger="timer"
triggerDelay={30000} // Show after 30 seconds
surveyFrequency="once" // Only show once per user
/>Path-specific Configuration
// Show different configurations on different routes
function App() {
const { pathname } = useLocation();
if (pathname.startsWith('/dashboard')) {
return (
<InovaiWidget
siteKey="your-site-key"
feedbackTypes={["Bug Report", "Feature Request", "Performance Issue"]}
paths={["/dashboard*"]}
/>
);
}
if (pathname === '/') {
return (
<InovaiWidget
siteKey="your-site-key"
feedbackTypes={["General Feedback", "Question"]}
trigger="timer"
triggerDelay={60000}
paths={["/"]}
/>
);
}
return null;
}TypeScript Support
Full TypeScript support with exported types:
import {
InovaiWidget,
FeedbackConfig,
FeedbackSubmission,
Survey
} from '@inov-ai/feedback-widget';
const config: FeedbackConfig = {
siteKey: 'your-site-key',
primaryColor: '#f97316',
theme: 'auto'
};
const handleSubmit = (data: FeedbackSubmission) => {
console.log('Feedback received:', data);
};
function App() {
return <InovaiWidget {...config} onSubmit={handleSubmit} />;
}Migration from Script Widget
If you're migrating from the script-based widget, here's how the props map:
| Script Attribute | React Prop | Notes |
|-------------------|------------|-------|
| site_key | siteKey | ✅ Same functionality |
| data-primary-color | primaryColor | ✅ Same functionality |
| data-theme | theme | ✅ Same functionality |
| data-position | position | ✅ Same functionality |
| data-button-text | buttonText | ✅ Same functionality |
| data-paths | paths | ✅ Same functionality |
| data-feedback-types | feedbackTypes | ✅ Same functionality |
| data-trigger | trigger | ✅ Same functionality |
Troubleshooting
Widget not appearing?
- Check paths configuration: Make sure current route is in
pathsarray - Verify siteKey: Ensure your site key is correct
- Check browser console: Look for error messages
Surveys not loading?
- Verify site key: Must match your inov-ai dashboard
- Check active surveys: Ensure you have active surveys in your dashboard
- Network issues: Check browser network tab for failed requests
Styling issues?
- CSS conflicts: Use
customCSSprop to override styles - Theme detection: Set explicit
themeif auto-detection fails - Z-index issues: Widget uses z-index: 999999
Support
- 📖 Documentation: https://docs.inov-ai.tech
- 💬 Discord: Join our community
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
- 🔗 Repository: https://github.com/godbright/inov-ai-package.git
License
MIT License - see LICENSE file for details. ); }
### useThemeDetection
Detect the current theme:
```jsx
import { useThemeDetection } from '@inov-ai/feedback-widget';
function MyComponent() {
const theme = useThemeDetection(); // 'light' | 'dark'
return <div>Current theme: {theme}</div>;
}Path Monitoring
Control which pages show the widget:
<InovaiWidget
siteKey="your-site-key"
paths={[
'/dashboard/*', // All dashboard pages
'/app/settings', // Specific page
'/blog/*', // All blog pages
]}
/>Environment Variables
For Next.js projects, use environment variables:
# .env.local
NEXT_PUBLIC_FEEDBACK_SITE_KEY=your-site-key<InovaiWidget
siteKey={process.env.NEXT_PUBLIC_FEEDBACK_SITE_KEY}
/>Triggers
Manual (Default)
Widget only opens when user clicks the button or you call openWidget().
Auto
Widget opens immediately when the page loads.
Timer
Widget opens after a specified delay:
<InovaiWidget
trigger="timer"
triggerDelay={5000} // 5 seconds
/>Scroll
Widget opens when user scrolls 50% down the page:
<InovaiWidget trigger="scroll" />Exit Intent
Widget opens when user moves mouse towards browser top (exit intent):
<InovaiWidget trigger="exit" />Styling
CSS Variables
The widget respects CSS custom properties:
:root {
--feedback-primary-color: #f97316;
--feedback-text-color: #111827;
--feedback-background-color: #ffffff;
}Custom CSS
Add custom styles:
<InovaiWidget
customCSS={`
.fb-widget-button {
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
transform: scale(1.1);
}
.fb-widget-modal {
backdrop-filter: blur(10px);
}
`}
/>TypeScript
Full TypeScript support with exported types:
import type {
FeedbackConfig,
FeedbackSubmission,
Survey,
SurveyQuestion
} from '@inov-ai/feedback-widget';
const config: FeedbackConfig = {
siteKey: 'your-site-key',
primaryColor: '#f97316',
// ... other options
};Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE for details.
Support
- 📧 Email: [email protected]
- 📖 Documentation: https://docs.inov-ai.tech
- 🐛 Issues: https://github.com/godbright/inov-ai-package/issues
- 🔗 Repository: https://github.com/godbright/inov-ai-package.git
