quala-widget
v1.2.0
Published
Smart feedback widget for SaaS trial optimization
Maintainers
Readme
🚀 Quala Widget v1.2.0
Turn "it's broken" into actionable debugging intelligence with contextual feedback widgets.
✨ What's New in v1.2.0
- 🎯 Conditional Micro Widgets: Micro widgets only load when enabled for your project
- 🧠 Contextual Intelligence: Questions and feedback options adapt to trigger type
- 🛡️ Advanced Anti-Spam: Intelligent widget frequency management
- 📱 Enhanced Offline Support: Queue feedback when offline, sync when online
- 🔧 Technical Context Capture: Automatic collection of errors, device info, and user actions
- ⚡ Performance Optimized: Minimal overhead when features aren't enabled
- 🎨 Trigger-Specific Styling: Different emoji sets per trigger type
📦 Installation
NPM
npm install quala-widgetCDN
<script src="https://unpkg.com/[email protected]/dist/quala.umd.js"></script>🚀 Quick Start
1. Initialize the SDK
import { qualaSdk } from 'quala-widget';
// Initialize with your API key
await qualaSdk.initialize('your-api-key', {
debug: true, // Enable for development
apiBaseUrl: 'https://www.getquala.xyz/api/widget' // Optional custom URL
});2. Identify Users
// Identify the user to enable feedback
await qualaSdk.identifyUser({
userId: 'user-123',
email: '[email protected]',
trialStartDate: '2025-01-01' // Optional
});3. Ready! 🎉
That's it! The SDK will automatically:
- ✅ Show regular feedback widgets if configured
- ✅ Enable micro widgets if configured for your project
- ✅ Set up intelligent triggers based on user behavior
- ✅ Capture technical context when issues occur
🎣 React Hooks
For React applications, use the provided hooks for cleaner integration:
useQualaInit Hook
Initialize Quala in your app component with automatic cleanup:
import { useQualaInit } from 'quala-widget';
function App() {
useQualaInit({
apiKey: 'your-api-key',
options: {
debug: true,
apiBaseUrl: 'https://www.getquala.xyz/api/widget' // Optional
}
});
return <div>Your App</div>;
}useQuala Hook
Access Quala functionality in any component:
import { useQuala } from 'quala-widget';
function UserProfile({ userId, email }) {
const { identifyUser, trackEvent, triggerSmartFeedback } = useQuala();
useEffect(() => {
// Identify user when component mounts
identifyUser({
userId,
email,
trialStartDate: '2025-01-01'
});
}, [userId, email]);
const handleFeatureUsed = () => {
trackEvent('feature_used', {
feature: 'user-profile',
section: 'settings'
});
};
const handleFeedbackRequest = async () => {
await triggerSmartFeedback();
};
return (
<div>
<button onClick={handleFeatureUsed}>Use Feature</button>
<button onClick={handleFeedbackRequest}>Give Feedback</button>
</div>
);
}TypeScript Support
Full TypeScript support with proper typing:
import { useQuala, type QualaUser } from 'quala-widget';
const user: QualaUser = {
userId: 'user-123',
email: '[email protected]',
trialStartDate: '2025-01-01'
};
const { identifyUser } = useQuala();
identifyUser(user); // ✅ Fully typedHook Benefits
- Automatic Cleanup:
useQualaInithandles SDK destruction on unmount - React-Friendly: No need to manage SDK lifecycle manually
- TypeScript Ready: Full type safety out of the box
- Lightweight: Hooks only wrap the core SDK, no extra overhead
🎯 Micro Widgets (Conditional Feature)
Micro widgets are conditionally loaded based on your project configuration. They only activate when:
- Your project has micro widgets enabled in the dashboard
- Valid trigger configuration exists
- Anti-spam conditions are met
Smart Triggers
When enabled, micro widgets respond to 5 intelligent triggers:
| Trigger | When It Shows | Default Question | Emoji Set | |---------|---------------|------------------|-----------| | 🕒 Time | After user spends time on page | "How has your experience been so far?" | Detailed (😍😊😐😕😤) | | 🚪 Exit Intent | When user moves to leave | "Before you go, how can we improve?" | Exit-focused (👍🤷😕) | | ⚡ Console Error | When JavaScript errors occur | "We noticed some technical issues. How can we help?" | Technical (✅🤔🐞) | | 📝 Form Failure | When form submissions fail | "Having trouble with the form?" | Technical (✅🤔🐞) | | 🔧 API Failure | When API calls fail | "Something went wrong. What can we fix?" | Technical (✅🤔🐞) |
Contextual Intelligence
Each trigger type gets contextual questions and appropriate feedback options:
// Example: Console error detected
// Question: "We noticed some technical issues. How can we help?"
// Options: ✅ Working fine 🤔 Something's off 🐞 It's broken
// Example: Exit intent detected
// Question: "Before you go, how can we improve?"
// Options: 👍 All good 🤷 Just browsing 😕 Something's wrong📊 Technical Context Capture
When micro widgets are enabled, the SDK automatically captures:
{
device: {
userAgent: "Chrome/91.0...",
viewport: "1920x1080",
timezone: "America/New_York"
},
performance: {
loadTime: 1250,
memoryUsage: "45MB",
connectionType: "4g"
},
errors: [
{
message: "Cannot read property 'x' of undefined",
stack: "...",
timestamp: "2025-01-15T10:30:00Z"
}
],
networkFailures: [
{
url: "/api/users",
status: 500,
timestamp: "2025-01-15T10:29:55Z"
}
],
userActions: [
{ type: "click", element: "button#submit", timestamp: "..." },
{ type: "form_submit", form: "login-form", timestamp: "..." }
]
}🛡️ Anti-Spam System
Intelligent frequency management prevents widget fatigue:
- Global Cooldown: Minimum 45 seconds between any widgets
- Trigger Priorities: Critical errors override time-based triggers
- Session Limits: Maximum 3 widgets per session
- Individual Cooldowns: Each trigger type has its own cooldown
- Smart Override: High-priority triggers can override cooldowns
// Check anti-spam status (debug mode only)
const status = qualaSdk.getAntiSpamStatus();
console.log(status);
// {
// enabled: true,
// globalCooldownRemaining: 15000,
// sessionWidgetCount: 1,
// lastWidgetType: 'time',
// canShow: true
// }🎮 Runtime Configuration
Configure Micro Widgets
qualaSdk.configureMicroWidget({
position: 'bottom-left',
question: 'Custom question for all triggers',
emojiSet: 'simple', // 'default' | 'simple' | 'detailed'
autoHide: true,
hideDelay: 8000
});Check Availability
// Check if regular feedback trigger is available
const available = await qualaSdk.checkTriggerAvailable();
// Refresh trigger status
const refreshed = await qualaSdk.refreshTriggerStatus();📱 Regular Feedback Widgets
Traditional feedback forms still work as before:
// These will show automatically when triggers are configured
// Or manually trigger:
await qualaSdk.triggerSmartFeedback();🔧 Advanced Configuration
Event Listeners
// Listen to SDK events
qualaSdk.on('micro_widget_shown', ({ triggerType, config }) => {
console.log(`Micro widget shown for ${triggerType}`);
});
qualaSdk.on('micro_feedback_submitted', ({ feedback, triggerType, technicalContext }) => {
console.log('Feedback submitted:', feedback);
});
qualaSdk.on('user_identified', ({ user, session }) => {
console.log('User identified:', user.userId);
});
qualaSdk.on('config_updated', ({ config, reason }) => {
console.log('Config updated:', reason);
});
// Remove listeners
qualaSdk.off('micro_widget_shown');Debug Mode
await qualaSdk.initialize('your-api-key', {
debug: true
});
// Debug-only methods
qualaSdk.forceAllowNextWidget(); // Bypass anti-spam
qualaSdk.resetAntiSpamState(); // Reset anti-spam counters
await qualaSdk.forceConfigRefresh(); // Force config updateGet Session Info
const info = qualaSdk.getSessionInfo();
console.log(info);
// {
// sessionToken: "abc123...",
// questionGroupId: "uuid...",
// isInitialized: true,
// microWidgetEnabled: true,
// antiSpam: { ... } // Debug mode only
// }Get Technical Context
// Only available when micro widgets are enabled
const context = qualaSdk.getTechnicalContext();
if (context) {
console.log('Current technical state:', context);
}📊 Analytics & Tracking
The SDK automatically tracks key events:
// Manual event tracking
qualaSdk.trackEvent('feature_used', {
feature: 'advanced-search',
userId: 'user-123'
});
qualaSdk.trackEvent('milestone_reached', {
milestone: 'onboarding_complete',
timeToComplete: 120000
});Automatic Events:
user_identified- When user is identifiedmicro_widget_shown- When micro widget appearsmicro_feedback_submitted- When micro feedback is submittedfeedback_widget_triggered- When regular widget triggersanti_spam_blocked- When anti-spam prevents displayconfig_updated- When configuration changes
🌐 Offline Support
The SDK gracefully handles offline scenarios:
- Offline Queue: Feedback is queued when offline
- Auto-Sync: Syncs when connection returns
- Persistence: Uses localStorage as backup
- Retry Logic: Automatic retry with exponential backoff
// Feedback submitted offline will be automatically synced
// when the user comes back online🎯 Conditional Loading
Key features are conditionally loaded based on configuration:
| Feature | Loads When | |---------|------------| | Micro Widgets | Project has micro widgets enabled | | Technical Context | Micro widgets are enabled | | Anti-Spam Manager | Micro widgets are enabled | | Trigger Listeners | Micro widgets enabled + triggers configured | | Config Refresh | Micro widgets are enabled |
This ensures minimal overhead when features aren't needed.
🚫 Error Handling
try {
await qualaSdk.initialize('invalid-key');
} catch (error) {
console.error('SDK initialization failed:', error);
}
// Listen for errors
qualaSdk.on('sdk_error', ({ error, phase }) => {
console.error(`SDK error in ${phase}:`, error);
});
qualaSdk.on('widget_load_error', ({ error }) => {
console.error('Widget failed to load:', error);
});🔐 Security & Privacy
- Domain Filtering: Sensitive domains (auth, payment) are excluded from context
- Data Minimization: Only necessary technical data is collected
- Local Storage: Minimal use of localStorage for offline support
- Session-Based: All data tied to user sessions
🗂️ Project Configuration
Configure your project's feedback strategy through the Quala dashboard:
- Trigger Selection: Choose which behavioral triggers to enable
- Contextual Questions: Customize questions per trigger type
- Emoji Sets: Select appropriate feedback styles for each context
- Technical Context: Enable detailed error and performance capture
- Anti-Spam Settings: Configure frequency and priority rules
🧪 Testing
// Test in development
await qualaSdk.initialize('your-api-key', {
debug: true,
apiBaseUrl: 'http://localhost:3001/api/widget'
});
// Check what features are enabled
const info = qualaSdk.getSessionInfo();
console.log('Micro widgets enabled:', info.microWidgetEnabled);
// Debug mode provides additional testing methods
qualaSdk.forceAllowNextWidget(); // Bypass anti-spam
qualaSdk.resetAntiSpamState(); // Reset anti-spam counters📚 TypeScript Support
Full TypeScript definitions included:
import { qualaSdk, QualaUser, MicroWidgetConfig } from 'quala-widget';
const user: QualaUser = {
userId: 'user-123',
email: '[email protected]'
};
await qualaSdk.identifyUser(user);Ready to turn vague complaints into actionable insights? 🚀
Get started at getquala.xyz
