npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

quala-widget

v1.2.0

Published

Smart feedback widget for SaaS trial optimization

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-widget

CDN

<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 typed

Hook Benefits

  • Automatic Cleanup: useQualaInit handles 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:

  1. Your project has micro widgets enabled in the dashboard
  2. Valid trigger configuration exists
  3. 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 update

Get 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 identified
  • micro_widget_shown - When micro widget appears
  • micro_feedback_submitted - When micro feedback is submitted
  • feedback_widget_triggered - When regular widget triggers
  • anti_spam_blocked - When anti-spam prevents display
  • config_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