JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 162
  • Score
    100M100P100Q98082F
  • License MIT

BetterCX Chat Widget - Production-ready embeddable chat widget built with Stencil.js

Package Exports

  • bettercx-widget
  • bettercx-widget/bettercx-widget
  • bettercx-widget/loader
  • bettercx-widget/react

Readme

BetterCX Widget

npm version License: MIT Built With Stencil

Production-ready, embeddable chat widget built with Stencil.js and TypeScript

BetterCX Widget is a lightweight, secure, and highly customizable chat widget that integrates seamlessly with the BetterCX backend. It's designed to be embedded in any website with minimal setup and maximum flexibility.

Features

  • 🚀 Lightweight & Fast - Optimized bundles with lazy loading
  • 🔒 Secure - JWT-based authentication with origin validation
  • 🎨 Customizable - CSS custom properties and runtime theming
  • 📱 Responsive - Mobile-first design with touch-friendly controls
  • Accessible - ARIA support and keyboard navigation
  • 🌐 Universal - Works with any framework or vanilla HTML
  • 🔧 TypeScript - Full type safety and IntelliSense support
  • 📊 Observable - Custom events for analytics and monitoring

Quick Start

npm install bettercx-widget
import React from 'react';
import { BetterCXWidgetReact } from 'bettercx-widget/react';

function App() {
  return (
    <div>
      <h1>My App</h1>
      <BetterCXWidgetReact publicKey="pk_your_widget_key_here" theme="auto" autoInit={true} />
    </div>
  );
}

Web Component

npm install bettercx-widget
import 'bettercx-widget';

// Use the web component
<bettercx-widget public-key="pk_your_widget_key_here" org-id="123" theme="auto" />;

Script Tag

<script type="module" src="https://unpkg.com/bettercx-widget@latest/dist/bettercx-widget/bettercx-widget.esm.js"></script>

<bettercx-widget public-key="pk_your_widget_key_here" org-id="123" theme="auto"></bettercx-widget>

React Integration

Basic Usage

import React from 'react';
import { BetterCXWidgetReact } from 'bettercx-widget/react';

function App() {
  return (
    <BetterCXWidgetReact
      publicKey="pk_your_widget_key_here"
      theme="auto"
      onWidgetEvent={event => {
        console.log('Widget event:', event);
      }}
    />
  );
}

Advanced Usage with Controls

import React, { useRef } from 'react';
import { BetterCXWidgetReact, BetterCXWidgetReactRef } from 'bettercx-widget/react';

function App() {
  const widgetRef = useRef<BetterCXWidgetReactRef>(null);

  const handleOpenChat = () => {
    widgetRef.current?.open();
  };

  const handleSendMessage = () => {
    widgetRef.current?.sendMessage('Hello from React!');
  };

  return (
    <div>
      <button onClick={handleOpenChat}>Open Chat</button>
      <button onClick={handleSendMessage}>Send Message</button>

      <BetterCXWidgetReact ref={widgetRef} publicKey="pk_your_widget_key_here" theme="auto" onWidgetEvent={event => console.log('Widget event:', event)} />
    </div>
  );
}

Props

Prop Type Default Required Description
publicKey string - Your widget public key
theme 'light' | 'dark' | 'auto' 'auto' Widget theme
debug boolean false Enable debug logging
baseUrl string 'http://localhost:8000' DB service URL
aiServiceUrl string 'http://localhost:8081' AI service URL
autoInit boolean true Auto-initialize on load
onWidgetEvent function - Event handler
className string - CSS class name
style object - Inline styles

Methods

const widgetRef = useRef<BetterCXWidgetReactRef>(null);

// Open the chat widget
await widgetRef.current?.open();

// Close the chat widget
await widgetRef.current?.close();

// Toggle the chat widget
await widgetRef.current?.toggle();

// Send a message programmatically
await widgetRef.current?.sendMessage('Hello!');

Configuration

Required Properties

Property Type Description
publicKey string Your widget public key (starts with pk_)

Optional Properties

Property Type Default Description
orgId number - Organization ID for fetching configuration
theme 'light' | 'dark' | 'auto' 'auto' Theme preference
palette string - Custom color palette name
disableShadow boolean false Disable Shadow DOM for CSS override
debug boolean false Enable debug logging
baseUrl string - Backend service URL
aiServiceUrl string - AI service URL

Events

The widget emits custom events for monitoring and analytics:

const widget = document.querySelector('bettercx-widget');

widget.addEventListener('widgetEvent', event => {
  const { type, data, timestamp } = event.detail;

  switch (type) {
    case 'opened':
      // Widget was opened
      break;
    case 'closed':
      // Widget was closed
      break;
    case 'message-sent':
      // User sent a message
      break;
    case 'message-received':
      // AI responded
      break;
    case 'error':
      // An error occurred
      break;
    case 'config-loaded':
      // Configuration was loaded
      break;
    case 'session-created':
      // Authentication session created
      break;
  }
});

Theming & Customization

CSS Custom Properties

The widget uses CSS custom properties for theming. You can override these in your stylesheet:

bettercx-widget {
  --bcx-primary: #007bff;
  --bcx-secondary: #6c757d;
  --bcx-background: #ffffff;
  --bcx-text: #212529;
  --bcx-border: #dee2e6;
  --bcx-shadow: rgba(0, 0, 0, 0.1);
}

Runtime Configuration

The widget automatically fetches configuration from your backend when orgId is provided. This includes:

  • Color schemes (light/dark mode)
  • Branding elements
  • Feature toggles
  • Custom styling

Platform-Specific Integration

WordPress

Create a shortcode in your theme's functions.php:

function bettercx_widget_shortcode($atts) {
    $atts = shortcode_atts(array(
        'public_key' => '',
        'org_id' => '',
        'theme' => 'auto'
    ), $atts);

    if (empty($atts['public_key'])) {
        return '<!-- BetterCX Widget: public_key required -->';
    }

    return sprintf(
        '<script type="module" src="https://unpkg.com/bettercx-widget@latest/dist/bettercx-widget/bettercx-widget.esm.js"></script>
        <bettercx-widget
            public-key="%s"
            org-id="%s"
            theme="%s">
        </bettercx-widget>',
        esc_attr($atts['public_key']),
        esc_attr($atts['org_id']),
        esc_attr($atts['theme'])
    );
}
add_shortcode('bettercx_widget', 'bettercx_widget_shortcode');

Usage: [bettercx_widget public_key="pk_your_key" org_id="123"]

Shopify

Add to your theme's theme.liquid before </body>:

<script type="module" src="https://unpkg.com/bettercx-widget@latest/dist/bettercx-widget/bettercx-widget.esm.js"></script>
<bettercx-widget
  public-key="{{ settings.bettercx_public_key }}"
  org-id="{{ settings.bettercx_org_id }}"
  theme="{{ settings.bettercx_theme | default: 'auto' }}">
</bettercx-widget>

Webflow

Add this custom embed code to your page:

<script type="module" src="https://unpkg.com/bettercx-widget@latest/dist/bettercx-widget/bettercx-widget.esm.js"></script>
<bettercx-widget public-key="pk_your_widget_key_here" org-id="123" theme="auto"> </bettercx-widget>

Development

Prerequisites

  • Node.js 18+
  • npm or yarn

Setup

git clone https://github.com/BetterCXAppWave/widget.git
cd widget
npm install

Development Server

npm start

Build

npm run build

Testing

# Unit tests
npm run test:unit

# E2E tests
npm run test:e2e

# All tests
npm test

Linting

npm run lint
npm run lint:fix

API Reference

BetterCXWidget Class

class BetterCXWidget {
  constructor(options: WidgetOptions);
  open(): Promise<void>;
  close(): Promise<void>;
  toggle(): Promise<void>;
  sendMessage(content: string): Promise<void>;
  on(event: string, callback: Function): void;
  off(event: string, callback: Function): void;
  destroy(): void;
}

WidgetOptions Interface

interface WidgetOptions {
  publicKey: string;
  orgId?: number;
  theme?: 'light' | 'dark' | 'auto';
  palette?: string;
  disableShadow?: boolean;
  debug?: boolean;
  baseUrl?: string;
  aiServiceUrl?: string;
  container?: HTMLElement;
}

Security

  • Origin Validation: Widget keys are validated against allowed origins
  • JWT Tokens: Short-lived tokens (1 hour) for API authentication
  • No Local Storage: Tokens are stored in memory only
  • CORS Protection: Backend validates all cross-origin requests
  • Rate Limiting: Built-in protection against abuse

Browser Support

  • Chrome 60+
  • Firefox 55+
  • Safari 12+
  • Edge 79+

Contributing

  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 Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support