featurely-feature-reporter
v1.0.22
Published
Embeddable widget for collecting user feature requests and bug reports with Featurely
Maintainers
Readme
featurely-feature-reporter
Embeddable widget for collecting user feature requests and bug reports with Featurely.
📦 Installation
npm install featurely-feature-reporter🚀 Quick Start
import { FeatureReporter } from "featurely-feature-reporter";
const reporter = new FeatureReporter({
apiKey: "your-featurely-api-key",
projectId: "your-project-id",
position: "bottom-right",
color: "blue",
icon: "comment",
});
reporter.init();✨ Features
- 💡 Feature Requests - Let users submit feature ideas
- 🐛 Bug Reports - Collect bug reports with screenshots
- 📸 Screenshot Capture - Automatic or manual screenshot capture
- 🎨 Customizable - Colors, icons, and positioning
- 🎯 Draggable Widget - Optional drag-to-reposition functionality
- 📱 Mobile Responsive - Works great on all devices
- 🔒 User Context - Track submissions by user
- 🔗 Dashboard Link - Optional link to your public roadmap
- 🎭 TypeScript - Fully typed with comprehensive definitions
📖 Usage
Basic Setup
import { FeatureReporter } from "featurely-feature-reporter";
// Initialize the widget
const reporter = new FeatureReporter({
apiKey: "ft_live_your_api_key",
projectId: "proj_123",
});
// Render the widget
reporter.init();With User Context
const reporter = new FeatureReporter({
apiKey: "ft_live_your_api_key",
projectId: "proj_123",
user: {
id: "user_123",
email: "[email protected]",
name: "John Doe",
},
});
reporter.init();
// Update user context later (e.g., after login)
reporter.setUser("user_456", "[email protected]", "Jane Smith");Full Customization
const reporter = new FeatureReporter({
apiKey: "ft_live_your_api_key",
projectId: "proj_123",
// Position
position: "bottom-right", // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'right-center' | 'left-center'
// Appearance
color: "purple", // 'blue' | 'green' | 'purple' | 'red' | 'orange' | 'pink'
icon: "lightbulb", // 'comment' | 'lightbulb' | 'bug' | 'message' | 'plus' | 'star'
// Features
enableFeatureRequests: true,
enableBugReports: true,
draggable: true,
showDashboardLink: true,
// Custom labels (all fields optional — see full list below)
labels: {
widgetTooltip: "Send feedback",
modalTitle: "Send Feedback",
featureRequestTitle: "💡 Request a Feature",
bugReportTitle: "🐛 Report a Bug",
featureTitleLabel: "Feature title",
bugTitleLabel: "Short description",
descriptionLabel: "Description",
featureTitlePlaceholder: "What would you like to see?",
bugTitlePlaceholder: "What went wrong?",
featureDescriptionPlaceholder: "Describe the feature and why it would be useful...",
bugDescriptionPlaceholder: "What happened? What did you expect to happen?",
emailLabel: "Email (optional)",
emailPlaceholder: "[email protected]",
emailHint: "Get notified when we ship this",
submitButton: "Submit",
cancelButton: "Cancel",
submittingText: "Submitting...",
featureSuccessMessage: "✅ Feature request submitted! Thanks for your feedback.",
bugSuccessMessage: "✅ Bug report submitted! We'll look into it.",
featureErrorMessage: "❌ Could not submit feature request. Please try again.",
bugErrorMessage: "❌ Could not submit bug report. Please try again.",
},
// Callbacks
onSubmit: (type, data) => {
console.log(`${type} submitted:`, data);
},
onError: (error) => {
console.error("Submission error:", error);
},
});
reporter.init();React Integration
import { useEffect, useRef } from "react";
import { FeatureReporter } from "featurely-feature-reporter";
function App() {
const reporterRef = useRef<FeatureReporter | null>(null);
useEffect(() => {
reporterRef.current = new FeatureReporter({
apiKey: process.env.REACT_APP_FEATURELY_API_KEY!,
projectId: process.env.REACT_APP_FEATURELY_PROJECT_ID!,
position: "bottom-right",
color: "blue",
});
reporterRef.current.init();
return () => {
reporterRef.current?.destroy();
};
}, []);
return <div>Your app content</div>;
}Next.js Integration
// app/layout.tsx or pages/_app.tsx
"use client";
import { useEffect } from "react";
import { FeatureReporter } from "featurely-feature-reporter";
export default function RootLayout({ children }) {
useEffect(() => {
if (typeof window !== "undefined") {
const reporter = new FeatureReporter({
apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
projectId: process.env.NEXT_PUBLIC_FEATURELY_PROJECT_ID!,
});
reporter.init();
return () => reporter.destroy();
}
}, []);
return (
<html>
<body>{children}</body>
</html>
);
}Vue Integration
<script setup>
import { onMounted, onUnmounted } from "vue";
import { FeatureReporter } from "featurely-feature-reporter";
let reporter = null;
onMounted(() => {
reporter = new FeatureReporter({
apiKey: import.meta.env.VITE_FEATURELY_API_KEY,
projectId: import.meta.env.VITE_FEATURELY_PROJECT_ID,
});
reporter.init();
});
onUnmounted(() => {
reporter?.destroy();
});
</script>🔧 Configuration
FeatureReporterConfig
| Option | Type | Required | Default | Description |
| ----------------------- | ---------------- | -------- | ------------------------ | ------------------------------------ |
| apiKey | string | ✅ | - | Your Featurely API key |
| projectId | string | ✅ | - | Your Featurely project ID |
| apiUrl | string | ❌ | 'https://featurely.no' | Custom API endpoint |
| position | WidgetPosition | ❌ | 'bottom-right' | Widget position |
| color | WidgetColor | ❌ | 'blue' | Widget color theme |
| icon | WidgetIcon | ❌ | 'comment' | Widget icon |
| draggable | boolean | ❌ | false | Allow widget dragging |
| enableFeatureRequests | boolean | ❌ | true | Enable feature requests |
| enableBugReports | boolean | ❌ | true | Enable bug reports |
| showDashboardLink | boolean | ❌ | false | Show dashboard link |
| user | UserInfo | ❌ | - | User context |
| labels | Labels | ❌ | - | Custom text labels (see table below) |
| onSubmit | function | ❌ | - | Submission callback |
| onError | function | ❌ | - | Error callback |
Position Options
'bottom-right'- Bottom right corner (default)'bottom-left'- Bottom left corner'top-right'- Top right corner'top-left'- Top left corner'right-center'- Right side, vertically centered'left-center'- Left side, vertically centered
Color Options
'blue'(default)'green''purple''red''orange''pink'
Icon Options
'comment'(default) - Chat bubble'lightbulb'- Light bulb'bug'- Bug icon'message'- Message icon'plus'- Plus sign'star'- Star icon
Labels Options
All labels are optional. Any label not provided falls back to the English default.
| Label key | Default (English) | Description |
| ------------------------------- | ----------------------------------------------------------- | ----------------------------------------- |
| widgetTooltip | "Send feedback" | Tooltip shown on the floating button |
| modalTitle | "Send Feedback" | Title bar of the modal dialog |
| featureRequestTitle | "💡 Request a Feature" | Tab/heading for feature requests |
| bugReportTitle | "🐛 Report a Bug" | Tab/heading for bug reports |
| featureTitleLabel | "Feature title" | Label for the feature title input |
| bugTitleLabel | "Short description" | Label for the bug title input |
| descriptionLabel | "Description" | Label for the description textarea |
| featureTitlePlaceholder | "What would you like to see?" | Placeholder for feature title |
| bugTitlePlaceholder | "What went wrong?" | Placeholder for bug title |
| featureDescriptionPlaceholder | "Describe the feature and why it would be useful..." | Placeholder for feature description |
| bugDescriptionPlaceholder | "What happened? What did you expect to happen?" | Placeholder for bug description |
| emailLabel | "Email (optional)" | Label for the email input |
| emailPlaceholder | "[email protected]" | Placeholder for email input |
| emailHint | "Get notified when we ship this" | Hint text below email input |
| submitButton | "Submit" | Submit button label |
| cancelButton | "Cancel" | Cancel/close button label |
| submittingText | "Submitting..." | Button label while submitting |
| featureSuccessMessage | "✅ Feature request submitted! Thanks for your feedback." | Toast after successful feature submission |
| bugSuccessMessage | "✅ Bug report submitted! We'll look into it." | Toast after successful bug submission |
| featureErrorMessage | "❌ Could not submit feature request. Please try again." | Toast when feature submission fails |
| bugErrorMessage | "❌ Could not submit bug report. Please try again." | Toast when bug submission fails |
🔒 Content Security Policy (CSP)
If your site uses a Content-Security-Policy header, you must allow connections to https://www.featurely.no. Without this, form submissions will fail silently.
Add to your connect-src directive:
connect-src 'self' https://www.featurely.no;Next.js example (next.config.js):
const cspHeader = `
connect-src 'self' https://www.featurely.no;
`.trim();If the SDK is blocked by CSP, you will see this in the browser console:
[FeatureReporter] ⚠️ Network error — this may be caused by a Content-Security-Policy.
Add "https://www.featurely.no" to your connect-src directive.⚠️ Error Messages
The widget logs actionable errors to the browser console:
| Situation | Console message |
| ------------------------ | ------------------------------------------------------------- |
| Invalid API key (401) | Link to API Keys settings page |
| Missing permission (403) | Reminder to add features:write and bugs:write permissions |
| CSP blocking request | Instruction to add connect-src https://www.featurely.no |
📸 Screenshot Capture
The widget includes built-in screenshot capability for bug reports:
Automatic Capture (Recommended)
Install html2canvas for automatic full-page screenshots:
npm install html2canvas<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/html2canvas.min.js"></script>When html2canvas is available, the widget will automatically capture full-page screenshots when users click "Capture Screenshot".
Manual Upload Fallback
If html2canvas is not available, the widget will fall back to a file upload input, allowing users to manually select screenshot files.
🎯 API Methods
init()
Initialize and render the widget on the page.
reporter.init();setUser(userId, email?, name?)
Update user context for submissions.
reporter.setUser("user_123", "[email protected]", "John Doe");show()
Show the widget if it was hidden.
reporter.show();hide()
Hide the widget.
reporter.hide();destroy()
Remove the widget from the page and clean up.
reporter.destroy();🌐 Environment Variables
Store your API credentials securely:
React/Vite:
VITE_FEATURELY_API_KEY=ft_live_your_key
VITE_FEATURELY_PROJECT_ID=proj_123Next.js:
NEXT_PUBLIC_FEATURELY_API_KEY=ft_live_your_key
NEXT_PUBLIC_FEATURELY_PROJECT_ID=proj_123Vanilla JS:
const reporter = new FeatureReporter({
apiKey: window.FEATURELY_API_KEY,
projectId: window.FEATURELY_PROJECT_ID,
});🎨 Custom Styling
The widget injects minimal styles with high specificity. You can override them:
/* Customize widget button */
.featurely-widget-button {
width: 64px !important;
height: 64px !important;
}
/* Customize modal */
.featurely-modal-content {
border-radius: 16px !important;
}All styles are prefixed with featurely- to avoid conflicts.
🔒 Privacy & Security
- Screenshots are captured client-side and sent directly to your Featurely project
- No third-party services are used for screenshots
- User data is only sent to your Featurely project
- API keys should be stored in environment variables
- All submissions are sent over HTTPS
📱 Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)
Screenshot capture requires:
- html2canvas for automatic capture
- FileReader API for manual upload (universally supported)
🤝 Contributing
Contributions are welcome! Please open an issue or PR.
📄 License
MIT License - see LICENSE file for details.
🔗 Links
💬 Support
For issues or questions:
- Open a GitHub issue
- Contact [email protected]
- Check the documentation
