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

@wmtkrishan/chat-widget

v1.2.3

Published

Embeddable chat widget for React and Next.js applications

Downloads

343

Readme

@wmtkrishan/chat-widget

Embeddable live chat widget for React and Next.js. Connects to ECVue guest APIs for ticket creation, real-time messaging via Socket.IO, and session resume.

Features

  • Floating widget (closed by default) with open, minimize, and close states
  • Welcome flow: name, email, phone, then first message (General category by default)
  • Guest registration via user-service (sessionId + ticketId persisted in sessionStorage)
  • Real-time chat via Socket.IO (send/receive, typing indicators, read receipts)
  • REST fallback for message send when socket is unavailable
  • Session resume on page reload (history + reconnect)
  • Live chat header with wait timer until agent joins
  • Session feedback UI when conversation is resolved/closed
  • Settings panel (read-only contact details, transcript download, maximize, notifications)
  • Self-contained CSS with Shadow DOM isolation — no style conflicts with host Tailwind, Bootstrap, or global resets
  • Compatible with React (Vite) and Next.js App Router

Installation

npm install @wmtkrishan/chat-widget

Configuration

Configure REST and WebSocket endpoints via configureChatWidget() or props.

| Setting | Description | |---------|-------------| | apiBaseUrl | KrakenD gateway for REST (e.g. http://localhost:8000) | | socketUrl | WebSocket edge for Socket.IO (e.g. ws://localhost:8090) — not the KrakenD port | | platformCode | Platform header value (default: ecvue) | | supportHotline | Hotline number shown when a message fails to send (default placeholder: XXXXXX) |

React (Vite)

Create src/config/chatWidget.ts:

export const chatWidgetConfig = {
  apiBaseUrl: import.meta.env.VITE_API_BASE_URL ?? '',
  socketUrl: import.meta.env.VITE_SOCKET_URL ?? '',
  platformCode: 'ecvue',
  supportHotline: import.meta.env.VITE_SUPPORT_HOTLINE ?? '',
};

Add .env:

VITE_API_BASE_URL=http://localhost:8000
VITE_SOCKET_URL=ws://localhost:8090
VITE_SUPPORT_HOTLINE=0221XXXXXXX

Initialize in main.tsx:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { configureChatWidget } from '@wmtkrishan/chat-widget';
import { chatWidgetConfig } from './config/chatWidget';
import App from './App';

configureChatWidget(chatWidgetConfig);

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
);

Next.js (App Router)

Create config/chatWidget.ts:

export const chatWidgetConfig = {
  apiBaseUrl: process.env.NEXT_PUBLIC_API_BASE_URL ?? '',
  socketUrl: process.env.NEXT_PUBLIC_SOCKET_URL ?? '',
  platformCode: 'ecvue',
};

Add .env.local:

NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_SOCKET_URL=ws://localhost:8090

Use in a client component:

'use client';

import { ChatWidget, configureChatWidget } from '@wmtkrishan/chat-widget';
import { chatWidgetConfig } from '../config/chatWidget';

configureChatWidget(chatWidgetConfig);

export default function ChatWidgetDemo() {
  return <ChatWidget />;
}

Styles: By default the widget mounts in a Shadow DOM with bundled CSS, so you do not need to import dist/style.css and host-page styles will not leak in. For legacy setups, pass isolateStyles={false} and import the CSS file (see Style isolation).

Usage

import { ChatWidget } from '@wmtkrishan/chat-widget';

function App() {
  return <ChatWidget />;
}

No separate CSS import is required — styles are injected into the widget's Shadow DOM automatically.

Or pass config as props:

<ChatWidget
  apiBaseUrl="http://localhost:8000"
  socketUrl="ws://localhost:8090"
  platformCode="ecvue"
/>

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | agentName | string | "Watermelon" | Display name in the header after agent joins | | agentStatus | string | "Available" | Status text below agent name | | defaultOpen | boolean | false | Whether the widget starts open | | className | string | "" | Additional class on the root container | | apiBaseUrl | string | — | REST API base URL (overrides config) | | socketUrl | string | — | Socket.IO WebSocket URL (overrides config) | | platformCode | string | "ecvue" | Platform code sent to chat service | | isolateStyles | boolean | true | Mount in Shadow DOM with bundled CSS (recommended). Set false to use global dist/style.css instead. |

Style isolation

The widget is designed to embed safely in any React or Next.js app without CSS conflicts:

| Mode | How | When to use | |------|-----|-------------| | Shadow DOM (default) | isolateStyles={true} — styles bundled inside the package | React, Next.js, Tailwind, MUI, Bootstrap hosts | | Global CSS (legacy) | isolateStyles={false} + import '@wmtkrishan/chat-widget/dist/style.css' | Custom styling overrides, non-Shadow environments |

What is isolated:

  • Host global resets, typography, and component libraries cannot restyle widget buttons, inputs, or bubbles.
  • Widget CSS does not inject Tailwind preflight or other global rules into the host page.
  • Image preview overlays render inside the same shadow root (not document.body), so they stay styled correctly.

Next.js note: Use a client component ('use client') as shown above. No next.config CSS changes are required for the default Shadow DOM mode.

Guest chat flow

  1. User fills name, email, phone on welcome screen
  2. POST /api/users/v1/public/guests → { sessionId, ticketId, guestId, expiresAt }
  3. GET /api/chats/v1/public/guest/conversations/tickets/{ticketId} → open/ensure conversation
  4. GET .../messages → load history
  5. Connect Socket.IO with auth: { sessionId, platformCode }
  6. conversation:join { ticketId } → live messaging via message:send / message:new
  7. On page reload, valid session resumes from sessionStorage

API integration

User service (public)

| Method | Path | When | |--------|------|------| | GET | /api/tickets/v1/public/categories | Background (General category id) | | POST | /api/users/v1/public/guests | On first message send |

Create guest request body:

{
  "name": "Jane Doe",
  "email": "[email protected]",
  "phone": "0771234567",
  "categoryId": 1,
  "subject": "Cannot log in"
}

Chat service (guest, Bearer sessionId)

Base: /api/chats/v1/public/guest/conversations

| Method | Path | Purpose | |--------|------|---------| | GET | /tickets/{ticketId} | Open/ensure conversation | | GET | /tickets/{ticketId}/messages?limit=50 | Message history | | POST | /tickets/{ticketId}/messages | REST send fallback |

Headers: Authorization: Bearer <sessionId>, X-Platform-Code: ecvue

Ticket feedback (after resolved/closed)

Base: /api/tickets/v1/public/guest/ticket

Headers: Authorization: Bearer <guestSessionToken>

| Method | Path | Purpose | |--------|------|---------| | GET | /{ticketId}/feedback | Load existing rating (null if not rated) | | POST | /{ticketId}/feedback | Submit/update { helpful, comment? } |

Shown in the widget as “Did we help you?” when the conversation ends.

Socket.IO

Connect to the WebSocket edge (e.g. ws://localhost:8090), not KrakenD.

import { io } from 'socket.io-client';

const socket = io('ws://localhost:8090', {
  transports: ['websocket'],
  auth: { sessionId: '<GUEST_SESSION_ID>', platformCode: 'ecvue' },
});

Key events: conversation:join, message:send, message:new, typing, conversation:assigned, conversation:status

Advanced: useChat hook

'use client';

import { configureChatWidget, useChat } from '@wmtkrishan/chat-widget';

configureChatWidget({
  apiBaseUrl: 'http://localhost:8000',
  socketUrl: 'ws://localhost:8090',
});

function CustomChat() {
  const { messages, sendMessage, guestSession, contactDetails } = useChat();

  return (
    <div>
      {guestSession && <p>Ticket: {guestSession.ticketId}</p>}
      {messages.map((m) => (
        <p key={m.id}>{m.text}</p>
      ))}
      <button onClick={() => sendMessage('Hello')}>Send</button>
    </div>
  );
}

Exports

  • Components: ChatWidget
  • Hooks: useChat
  • Config: configureChatWidget, getChatWidgetConfig
  • Enums: ConversationStatus, SenderType, MessageType
  • Types: ChatWidgetProps, GuestSession, GuestConversation, Message, etc.

Example apps

| App | Path | Port | Package source | |-----|------|------|----------------| | Vite (local dev) | examples/vite-demo | 3700 | file:../.. | | React | examples/react-demo | 3701 | npm | | Next.js | examples/nextjs-demo | 3702 | npm |

# Library
npm install
npm run build

# Local dev demo (linked package)
cd examples/vite-demo
cp .env.example .env
npm install
npm run dev

# React demo (npm package)
cd examples/react-demo
cp .env.example .env
npm install
npm run dev

# Next.js demo (npm package)
cd examples/nextjs-demo
cp .env.example .env.local
npm install
npm run dev

Development

npm install
npm run build      # Build JS + CSS to dist/
npm run dev        # Watch JS
npm run dev:css    # Watch CSS
npm run typecheck

Publishing

Log in to npm (scoped packages require 2FA):

npm login
npm run build
npm publish --access public --otp=YOUR_2FA_CODE

After publishing, update example apps:

cd examples/react-demo && npm install @wmtkrishan/chat-widget@^0.4.0
cd examples/nextjs-demo && npm install @wmtkrishan/chat-widget@^0.4.0

License

MIT