A lightweight, embeddable feedback widget for games and web applications. Allow your users to submit bug reports, feature suggestions, and support tickets directly from your app.
- Three Feedback Types: Bug reports, suggestions, and support tickets
- Flexible Contact Handling: 5 different modes for capturing user email (anonymous, required, prefilled visible/hidden, auto)
- Virtual User Creation: Automatically creates/links users by email without requiring full registration
- Zero Dependencies: Pure vanilla JavaScript with no external libraries
- Shadow DOM Isolation: Complete CSS isolation - won't conflict with your app's styles
- Beautiful Design: Pastel blue minimalistic light theme
- Custom Metadata: Include game version, player level, and any custom data with submissions
- Responsive: Works on desktop and mobile devices
- Programmable API: Open the widget programmatically via JavaScript
- Game Engine Compatible: Works with PixiJS, Phaser, Unity WebGL, Three.js, and any HTML5 game
- View Live Demo - See the widget in action!
The widget comes with three built-in color themes:
<script src="betahub-widget.js"></script>BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-auth-token'
});That's it! The widget will appear as a floating button in the bottom-right corner.
- Go to your BetaHub project dashboard
- Navigate to Project → Integrations → Auth Tokens
- Create a new auth token with these permissions:
can_create_bug_reportcan_create_feature_requestcan_create_support_ticket(if using support tickets)
- Copy your project ID and the generated token
- Use them in the widget initialization
| Parameter | Description |
|---|---|
projectId |
Your BetaHub project ID |
authToken |
Authentication token (format: tkn-...) |
| Parameter | Type | Default | Description |
|---|---|---|---|
apiBaseUrl |
string | 'https://app.betahub.io' |
BetaHub API endpoint |
releaseLabel |
string | null |
Version label for bug reports (auto-creates release if doesn't exist). If not provided, bugs are assigned to the project's latest release |
position |
string | 'bottom-right' |
Button position: 'bottom-right', 'bottom-left', 'top-right', 'top-left' |
buttonText |
string | 'Feedback' |
Custom text for the floating button |
customFields |
object | {} |
Custom metadata sent with every submission |
userEmail |
string | null |
Pre-filled user email (creates/links virtual user) |
requireEmail |
boolean | false |
Require email for bugs/suggestions (tickets always require) |
showEmailField |
string | 'auto' |
Email field visibility: 'auto', 'always', 'never' |
theme |
string | 'pastel-blue' |
Color theme: 'pastel-blue', 'light', 'dark' |
styleOverrides |
object | {} |
CSS variable overrides for custom colors |
enabledTypes |
array | ['bug', 'suggestion', 'support'] |
Enabled feedback types |
BetaHubWidget.init({
projectId: 'pr-1234567890',
authToken: 'tkn-your-auth-token-here',
// Optional configuration
apiBaseUrl: 'https://app.betahub.io',
releaseLabel: '1.2.3', // Version label (auto-creates release if not exists)
position: 'bottom-right',
buttonText: 'Report Bug',
// Theme customization
theme: 'pastel-blue', // 'pastel-blue', 'light', or 'dark'
enabledTypes: ['bug', 'suggestion', 'support'], // Enabled feedback types
// Contact information
userEmail: 'player@example.com', // Pre-filled user email
requireEmail: false, // Require email for bugs/suggestions
showEmailField: 'auto', // 'auto', 'always', or 'never'
// Custom fields (great for games!)
customFields: {
platform: 'web',
playerLevel: 15,
currentScene: 'battle-arena',
sessionId: 'abc-123-def-456'
}
});These custom fields will be automatically included with every bug report, feature request, and support ticket submission.
The widget supports flexible contact information handling to suit different use cases:
BetaHubWidget.init({
projectId: 'pr-123',
authToken: 'tkn-abc'
// No email config
});- Bugs/Suggestions: Anonymous (no email field)
- Support Tickets: Email field shown (required)
- Best for: Public feedback where user identity is optional
BetaHubWidget.init({
projectId: 'pr-123',
authToken: 'tkn-abc',
requireEmail: true
});- All Types: Email field shown and required
- Best for: Tracking all feedback to specific users
BetaHubWidget.init({
projectId: 'pr-123',
authToken: 'tkn-abc',
userEmail: 'player@example.com',
showEmailField: 'always'
});- All Types: Email shown as readonly (user can see but not edit)
- Best for: Logged-in users where email is known
Mode 4: Prefilled Hidden
BetaHubWidget.init({
projectId: 'pr-123',
authToken: 'tkn-abc',
userEmail: 'player@example.com',
showEmailField: 'never'
});- All Types: Email sent in header but not visible in UI
- Best for: Silent user tracking without showing email
BetaHubWidget.init({
projectId: 'pr-123',
authToken: 'tkn-abc',
userEmail: 'player@example.com'
// showEmailField defaults to 'auto'
});- All Types: Shows readonly email field automatically when
userEmailis provided - Best for: Most use cases (smart defaults)
When you provide userEmail, the widget:
- Sends email in the authorization header:
FormUser tkn-abc,email:user@example.com - Creates or reuses a "virtual user" in BetaHub
- Links all feedback from that email together
- Allows BetaHub to send notifications about feedback updates
Note: Support tickets ALWAYS require contact information. If using anonymous mode, users must enter email manually for tickets.
Open the widget programmatically from your code:
// Open the feedback widget
BetaHubWidget.open();This is useful for:
- Custom "Report Bug" buttons in your UI
- Keyboard shortcuts (e.g., press F1 to report a bug)
- Context-specific feedback (e.g., "Report issue with this level")
Update custom fields after initialization to capture real-time game state:
// Update custom fields as game state changes
BetaHubWidget.updateCustomFields({
level: '5',
score: '1250',
health: '75'
});This is useful for:
- Capturing current game state (level, score, health) when feedback is submitted
- Updating player progress dynamically during gameplay
- Including real-time context with bug reports
Example: PixiJS Game Integration
// Initialize once at game start
BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-token',
customFields: {
gameVersion: '1.0.0',
level: '1',
score: '0'
}
});
// Update dynamically during gameplay
function onLevelUp(newLevel) {
BetaHubWidget.updateCustomFields({
level: newLevel.toString()
});
}
function onScoreChange(newScore) {
BetaHubWidget.updateCustomFields({
score: newScore.toString()
});
}Notes:
- New fields are merged with existing
customFields(doesn't replace them) - Call this method anytime after
init()to update values - Updated fields will be included in the next feedback submission
- All values should be strings for consistency
// Add to your game initialization
BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-token',
customFields: {
gameVersion: '1.0.0',
currentLevel: game.currentLevel,
playerScore: player.score
}
});// In your game's create() function
BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-token',
customFields: {
gameVersion: '1.0.0',
scene: this.scene.key
}
});// In your HTML template file
<script src="betahub-widget.js"></script>
<script>
// Initialize after Unity loads
createUnityInstance(canvas, config).then(function(unityInstance) {
BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-token',
customFields: {
unityVersion: '2022.3.1f1',
platform: 'webgl'
}
});
});
</script>import { useEffect } from 'react';
function App() {
useEffect(() => {
// Load and initialize widget
const script = document.createElement('script');
script.src = '/betahub-widget.js';
script.onload = () => {
window.BetaHubWidget.init({
projectId: 'your-project-id',
authToken: 'tkn-your-token',
customFields: {
appVersion: '1.0.0',
environment: process.env.NODE_ENV
}
});
};
document.body.appendChild(script);
}, []);
return <div>Your App</div>;
}- Requires: Description + Steps to Reproduce
- Email: Optional (unless
requireEmail: true) - Use for: Crashes, errors, unexpected behavior
- Endpoint:
POST /projects/{projectId}/issues.json
- Requires: Description only
- Email: Optional (unless
requireEmail: true) - Use for: Feature requests, improvements, ideas
- Endpoint:
POST /projects/{projectId}/feature_requests.json
- Requires: Description + Email (always required)
- Email: Always required (user must provide or use prefilled)
- Use for: Help requests, questions, general support
- Endpoint:
POST /projects/{projectId}/tickets.json
All requests use FormUser authentication with your auth token. Email can be provided via:
userEmailconfig (sent in header:FormUser tkn-abc,email:user@example.com)- User input in the form field
- Form field takes precedence over header
- Description: 2000 characters
- Steps to Reproduce: 1000 characters
Requires browsers with Shadow DOM support:
- Chrome 53+
- Firefox 63+
- Safari 10.1+
- Edge 79+
The widget uses a fixed pastel blue light theme. To customize colors, edit the getStyles() method in betahub-widget.js:
// Primary brand color
background: #237390; // Change to your brand color
// Button hover state
background: #1E627B; // Darker shade of brand colorSee CLAUDE.md for the complete color palette and design guidelines.
This is a single-file widget with zero build process. To modify:
- Edit
betahub-widget.js - Test with
demo.html(use a local web server) - No compilation or bundling needed!
# Serve demo locally
python3 -m http.server 8080
# Open http://localhost:8080/demo.html- Never commit auth tokens to version control
- Use environment-specific tokens (dev/staging/prod)
- Tokens support rate limiting (default: 8 submissions per day per type per IP)
- Use the BetaHub dashboard to rotate tokens if compromised
betahub-html-widget/
├── betahub-widget.js # Main widget (single file, zero dependencies)
├── demo.html # Live demo with documentation
├── README.md # This file
└── CLAUDE.md # Development guide and architecture docs
[Add your license here]
For issues with the widget itself, open a GitHub issue.
For BetaHub API questions, visit BetaHub Documentation or contact support@betahub.io.
Contributions welcome! Please:
- Test your changes with
demo.html - Ensure Shadow DOM isolation isn't broken
- Maintain the zero-dependency philosophy
- Update
CLAUDE.mdif changing architecture
Made with ❤️ for BetaHub


