Events System
The Nexus Chat Widget emits events for all user interactions and widget lifecycle changes. Use these events to build analytics, custom UI, integrations, and advanced features.
Available Events
The widget supports 18+ event types covering UI lifecycle, sessions, messages, interactions, voice/TTS, and errors.
UI Lifecycle Events
| Event | Description | Data |
|---|---|---|
open | Widget opened by user | { sessionId, timestamp } |
close | Widget closed by user | { sessionId, timestamp } |
minimize | Widget minimized | { previousMode, sessionId } |
maximize | Widget maximized | { previousMode, sessionId } |
Session Events
| Event | Description | Data |
|---|---|---|
sessionStart | New chat session created | { sessionId, metadata } |
sessionEnd | Chat session ended | { sessionId, duration, messageCount } |
Message Events
| Event | Description | Data |
|---|---|---|
messageStart | User submitted a message | { message, timestamp } |
messageComplete | AI response completed | { answer, queryId, duration } |
messageChunk | Streaming message chunk received | { chunk, queryId } |
Interaction Events
| Event | Description | Data |
|---|---|---|
typing | User is typing | { text, length } |
typingStop | User stopped typing | { finalText } |
feedback | User submitted feedback | { rating, messageId, comment? } |
copy | User copied message content | { content, messageId } |
Voice & TTS Events
| Event | Description | Data |
|---|---|---|
voiceStart | Voice recognition started | { language, sessionId } |
voiceEnd | Voice recognition ended | { transcript, duration } |
ttsStart | Text-to-speech started | { text, messageId } |
ttsEnd | Text-to-speech ended | { duration, messageId } |
Error Events
| Event | Description | Data |
|---|---|---|
error | Error occurred | { type, message, stack?, details? } |
Listening to Events
Use the widget.on() method to register event listeners:
// Initialize widget
const widget = window.NexusChatWidget.init({
experienceId: "your-experience-id",
apiUrl: "http://localhost:3001",
});
// Listen to specific event
widget.on("messageComplete", (data) => {
console.log("AI responded:", data.answer);
console.log("Response time:", data.duration, "ms");
});Complete Example
Here’s a comprehensive example that listens to all event types:
const widget = window.NexusChatWidget.init({
experienceId: "your-experience-id",
apiUrl: "http://localhost:3001",
});
// UI Lifecycle Events
widget.on("open", (data) => {
console.log("Widget opened", data.sessionId);
});
widget.on("close", (data) => {
console.log("Widget closed", data.sessionId);
});
widget.on("minimize", (data) => {
console.log("Widget minimized from", data.previousMode);
});
widget.on("maximize", (data) => {
console.log("Widget maximized from", data.previousMode);
});
// Session Events
widget.on("sessionStart", (data) => {
console.log("Session started:", data.sessionId);
});
widget.on("sessionEnd", (data) => {
console.log("Session ended:", {
sessionId: data.sessionId,
duration: data.duration,
messageCount: data.messageCount,
});
});
// Message Events
widget.on("messageStart", (data) => {
console.log("User message:", data.message);
});
widget.on("messageComplete", (data) => {
console.log("AI response:", {
answer: data.answer,
queryId: data.queryId,
duration: data.duration,
});
});
// Interaction Events
widget.on("typing", (data) => {
console.log("User typing...", data.length, "characters");
});
widget.on("typingStop", () => {
console.log("User stopped typing");
});
widget.on("feedback", (data) => {
console.log("User feedback:", data.rating, "for message", data.messageId);
if (data.comment) {
console.log("Comment:", data.comment);
}
});
widget.on("copy", (data) => {
console.log("User copied message:", data.messageId);
});
// Voice Events
widget.on("voiceStart", (data) => {
console.log("Voice input started, language:", data.language);
});
widget.on("voiceEnd", (data) => {
console.log("Voice input ended:", {
transcript: data.transcript,
duration: data.duration,
});
});
// TTS Events
widget.on("ttsStart", (data) => {
console.log("TTS started for message:", data.messageId);
});
widget.on("ttsEnd", (data) => {
console.log("TTS ended, duration:", data.duration);
});
// Error Handling
widget.on("error", (error) => {
console.error("Widget error:", {
type: error.type,
message: error.message,
details: error.details,
});
});Analytics Integration
Google Analytics
Track key metrics with Google Analytics:
widget.on("sessionStart", (data) => {
gtag("event", "chat_session_start", {
session_id: data.sessionId,
});
});
widget.on("messageComplete", (data) => {
gtag("event", "chat_message_complete", {
session_id: data.sessionId,
response_time: data.duration,
answer_length: data.answer.length,
});
});
widget.on("feedback", (data) => {
gtag("event", "chat_feedback", {
session_id: data.sessionId,
rating: data.rating,
message_id: data.messageId,
});
});
widget.on("error", (error) => {
gtag("event", "chat_error", {
error_type: error.type,
error_message: error.message,
});
});Mixpanel
Track events with Mixpanel:
widget.on("sessionStart", (data) => {
mixpanel.track("Chat Session Started", {
session_id: data.sessionId,
timestamp: data.timestamp,
});
});
widget.on("messageComplete", (data) => {
mixpanel.track("Chat Message Completed", {
session_id: data.sessionId,
response_time: data.duration,
query_id: data.queryId,
});
});
widget.on("feedback", (data) => {
mixpanel.track("Chat Feedback", {
rating: data.rating,
message_id: data.messageId,
has_comment: !!data.comment,
});
});Segment
Send events to Segment:
widget.on("sessionStart", (data) => {
analytics.track("Chat Session Started", {
sessionId: data.sessionId,
});
});
widget.on("messageComplete", (data) => {
analytics.track("Chat Message Completed", {
sessionId: data.sessionId,
responseTime: data.duration,
queryId: data.queryId,
});
});Use Cases
Custom UI Updates
Update your UI based on widget state:
const statusIndicator = document.getElementById("chat-status");
widget.on("open", () => {
statusIndicator.textContent = "Chat Open";
statusIndicator.className = "status-active";
});
widget.on("close", () => {
statusIndicator.textContent = "Chat Closed";
statusIndicator.className = "status-inactive";
});
widget.on("messageStart", () => {
statusIndicator.textContent = "Processing...";
});
widget.on("messageComplete", () => {
statusIndicator.textContent = "Ready";
});Session Recording
Record chat sessions for playback:
const sessionData = {
events: [],
startTime: null,
endTime: null,
};
widget.on("sessionStart", (data) => {
sessionData.startTime = data.timestamp;
sessionData.events = [];
});
widget.on("messageStart", (data) => {
sessionData.events.push({
type: "userMessage",
content: data.message,
timestamp: data.timestamp,
});
});
widget.on("messageComplete", (data) => {
sessionData.events.push({
type: "assistantMessage",
content: data.answer,
timestamp: new Date(),
duration: data.duration,
});
});
widget.on("sessionEnd", (data) => {
sessionData.endTime = data.timestamp;
// Send to your backend for storage
fetch("/api/chat-sessions", {
method: "POST",
body: JSON.stringify(sessionData),
});
});Performance Monitoring
Track widget performance metrics:
const metrics = {
totalMessages: 0,
totalResponseTime: 0,
errors: 0,
};
widget.on("messageComplete", (data) => {
metrics.totalMessages++;
metrics.totalResponseTime += data.duration;
const avgResponseTime = metrics.totalResponseTime / metrics.totalMessages;
console.log("Average response time:", avgResponseTime, "ms");
});
widget.on("error", () => {
metrics.errors++;
console.log(
"Error rate:",
(metrics.errors / metrics.totalMessages) * 100,
"%",
);
});Error Tracking with Sentry
Send errors to Sentry:
widget.on("error", (error) => {
Sentry.captureException(new Error(error.message), {
tags: {
component: "chat-widget",
errorType: error.type,
},
extra: {
sessionId: error.sessionId,
details: error.details,
stack: error.stack,
},
});
});Event Data Reference
Common Fields
All events include:
timestamp- ISO 8601 format timestampsessionId- Current session identifier (when applicable)
Duration Fields
Duration measurements in milliseconds for:
sessionEnd.duration- Session lengthmessageComplete.duration- Response timevoiceEnd.duration- Voice input durationttsEnd.duration- TTS playback duration
Error Types
The error event includes a type field:
interceptor- Message interceptor errortimeout- Request timeoutbackend- Backend API errorfeedback- Feedback submission errorunknown- Unclassified error
Interactive Demo
See the Events System Demo to watch events fire in real-time as you interact with the widget.
Next Steps
- Interactive Demo - See events in action
- Message Interceptor - Handle messages programmatically
- Configuration - All widget options