React widget for bug reporting and feedback with Linear integration
npm install @kamyarme/ticketing-widget---
- 🎯 Zero Configuration - Works out of the box with minimal setup
- 📝 Smart Console Capture - Automatically captures console logs, warnings, and errors (last 100 messages)
- 🔐 Secure & Licensed - License-based activation with backend validation
- 📸 File Attachments - Upload screenshots, images, and documents (up to 10MB)
- 🔗 Linear Integration - Automatically creates issues in your Linear workspace
- 💾 MongoDB Storage - All tickets stored securely in your database
- 🌐 Rich Context - Captures URL, user token, browser info, screen size, and timestamp
- 🎨 Fully Customizable - Light/dark themes, custom positioning, and custom styles
- 🌍 Internationalization - Built-in support for English and Persian (Farsi)
- ⚡ Lightweight - Small bundle size with tree-shaking support
- 📱 Responsive - Works perfectly on desktop, tablet, and mobile
- ♿ Accessible - Keyboard navigation and screen reader support
---
``bash`
npm install @kamyarme/ticketing-widgetor
yarn add @kamyarme/ticketing-widgetor
pnpm add @kamyarme/ticketing-widget
Requirements:
- React 17.0.0 or higher
- React DOM 17.0.0 or higher
---
`jsx
import React from 'react';
import { TicketingWidget } from '@kamyarme/ticketing-widget';
function App() {
return (
export default App;
`
You'll need a backend server to handle tickets. See Backend Setup section below.
---
> 📹 Coming soon: Live demo and screenshots
---
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| apiUrl | string | ✅ Yes | - | URL of your ticketing API server |licenseKey
| | string | ✅ Yes | - | Your license key (get one from backend) |getUserToken
| | () => string \| null | ⬜ No | undefined | Function to retrieve user's auth token for user identification |position
| | 'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left' | ⬜ No | 'bottom-right' | Position of the floating widget button |theme
| | 'light' \| 'dark' | ⬜ No | 'light' | Color theme for the widget |customStyles
| | React.CSSProperties | ⬜ No | {} | Custom CSS styles for the floating button |
`typescript`
interface TicketingWidgetProps {
apiUrl: string;
licenseKey: string;
getUserToken?: () => string | null;
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
theme?: 'light' | 'dark';
customStyles?: React.CSSProperties;
}
---
`jsx
import { TicketingWidget } from '@kamyarme/ticketing-widget';
function App() {
return (
<>
licenseKey="lic_1234567890abcdef"
/>
>
);
}
`
Track which users report issues by providing their auth token:
`jsx
import { TicketingWidget } from '@kamyarme/ticketing-widget';
function App() {
return (
licenseKey="lic_1234567890abcdef"
getUserToken={() => {
// Return the user's authentication token
return localStorage.getItem('authToken');
// or from your auth context/state
// return user?.token;
}}
/>
);
}
`
Place the widget button wherever you want:
`jsx`
licenseKey="lic_1234567890abcdef"
position="top-left" // Options: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
/>
Perfect for dark-mode applications:
`jsx`
licenseKey="lic_1234567890abcdef"
theme="dark"
/>
Customize the floating button to match your brand:
`jsx`
licenseKey="lic_1234567890abcdef"
customStyles={{
backgroundColor: '#ff6b6b',
width: '70px',
height: '70px',
borderRadius: '35px',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
}}
/>
`jsx
// app/layout.tsx or pages/_app.tsx
import { TicketingWidget } from '@kamyarme/ticketing-widget';
import { useAuth } from '@/hooks/useAuth';
export default function RootLayout({ children }) {
const { user } = useAuth();
return (
---
📊 What Gets Captured?
When a user submits a ticket, the widget automatically captures comprehensive debugging information:
| Data | Description |
|------|-------------|
| 📝 Console Logs | Last 100 console messages (log, warn, error, info) with timestamps |
| 🌐 Current URL | The exact page where the issue occurred |
| 👤 User Token | User authentication token (if
getUserToken is provided) |
| 💻 User Agent | Browser, OS, and device information |
| 📱 Screen Size | Current viewport dimensions (width × height) |
| ⏰ Timestamp | Exact date and time of submission |
| ⚠️ Error Stack Traces | Full stack traces for JavaScript errors |
| 📄 Description | User-provided title and detailed description |
| 🖼️ Files | User-uploaded screenshots and attachments |All data is sent securely to your backend and stored in MongoDB.
---
🔧 Backend Setup
This widget requires a backend server to process tickets. Here's how to set it up:
$3
We provide a ready-to-use backend built with Hono.js and MongoDB:
`bash
Clone or download the backend
git clone https://github.com/yourusername/ticketing.git
cd ticketing/packages/apiInstall dependencies
npm installSet up environment variables
cp .env.example .env
Edit .env with your configuration
Run the server
npm start
`Required Environment Variables:
`env
MongoDB
MONGODB_URI=mongodb://localhost:27017/ticketingJWT Secret
JWT_SECRET=your-super-secret-keyLinear Integration (optional)
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxServer
PORT=3000
`$3
The widget makes a
POST request to /api/tickets endpoint. Here's the expected request format:Endpoint:
POST /api/ticketsHeaders:
`
Content-Type: multipart/form-data
`Body:
`typescript
{
licenseKey: string; // License key for validation
subject: string; // Ticket title
description: string; // Detailed description
url: string; // Current page URL
userToken?: string; // Optional user auth token
userAgent: string; // Browser info
screenSize: {
width: number;
height: number;
};
consoleLogs: Array<{
level: 'log' | 'warn' | 'error' | 'info';
message: string;
timestamp: string;
}>;
files?: File[]; // Optional file attachments
}
`Response:
200 OK
`json
{
"success": true,
"ticketId": "ticket-id-here",
"linearIssueId": "optional-linear-issue-id"
}
`---
🔑 Getting a License Key
License keys are required to use this widget and are validated on your backend.
$3
Generate a test license key from your backend admin panel or using the CLI tool.
$3
1. Set up the backend server
2. Access the admin panel (typically at
https://your-api.com/admin)
3. Create a new license:
- Enter project name
- Set expiration date (optional)
- Configure Linear integration (optional)
- Generate license keyThe license key format:
lic_ followed by 20 random charactersExample:
lic_a1b2c3d4e5f6g7h8i9j0---
🎨 Styling & Customization
$3
The widget works great with Tailwind CSS:
`jsx
apiUrl={apiUrl}
licenseKey={licenseKey}
customStyles={{
backgroundColor: 'rgb(59 130 246)', // Tailwind blue-500
}}
/>
`$3
You can also customize using CSS variables (not yet implemented, but coming soon):
`css
:root {
--ticketing-widget-primary: #3b82f6;
--ticketing-widget-radius: 12px;
}
`---
🌍 Internationalization
The widget automatically detects the user's language and displays text accordingly.
Supported Languages:
- 🇬🇧 English (default)
- 🇮🇷 Persian (Farsi)
The widget detects browser language automatically. You can contribute more languages by submitting a PR!
---
🐛 Troubleshooting
$3
1. Make sure you've added the component to your app
2. Check browser console for errors
3. Verify your
apiUrl and licenseKey are correct
4. Ensure your backend server is running$3
1. Verify the license key is correct
2. Check that your backend server is accessible
3. Make sure the license hasn't expired
4. Check backend logs for validation errors
$3
1. Check file size (max 10MB per file)
2. Verify backend has proper file upload configuration
3. Check backend storage permissions
4. Review network tab in browser DevTools
$3
Console capture is automatic and requires no configuration. If logs aren't appearing:
1. Make sure errors actually occurred
2. Check browser console for the widget's own errors
3. Verify the widget loaded before the logs you want to capture
---
📖 Advanced Topics
$3
This package includes full TypeScript definitions:
`typescript
import { TicketingWidget, TicketingWidgetProps } from '@kamyarme/ticketing-widget';const config: TicketingWidgetProps = {
apiUrl: 'https://api.example.com',
licenseKey: 'lic_xxx',
theme: 'dark',
position: 'bottom-left',
};
`$3
The widget is designed to work with SSR frameworks like Next.js:
`jsx
'use client'; // Next.js 13+ app directoryimport { TicketingWidget } from '@kamyarme/ticketing-widget';
export default function TicketingWrapper() {
return ;
}
`$3
The widget is lazy-loaded and won't impact your initial page load:
- Bundle size: ~50KB gzipped
- No external dependencies (except React & Axios)
- Console capture has minimal performance impact
- Tree-shakable ES modules
---
🤝 Contributing
We welcome contributions! Here's how you can help:
1. Fork the repository
2. Create a feature branch:
git checkout -b feature/amazing-feature
3. Commit your changes: git commit -m 'Add amazing feature'
4. Push to the branch: git push origin feature/amazing-feature
5. Open a Pull RequestDevelopment Setup:
`bash
git clone https://github.com/yourusername/ticketing.git
cd ticketing/packages/react-widget
npm install
npm run dev
``---
Copyright © 2025 Kamyar Pouretesam
This software is provided under a commercial license. See LICENSE file for details.
Key Points:
- ✅ Free to use with a valid license key
- ✅ Can be used in commercial projects
- ❌ Cannot redistribute or resell this package
- ❌ Cannot remove license validation
---
Need help? We're here for you:
- 📧 Email: services@kamyar.me
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
- 📚 Docs: Full Documentation
---
- Built with React
- Powered by Axios
- Integrated with Linear
- UI inspired by modern design principles
---
Made with ❤️ by Kamyar Pouretesam