Skip to Content
WidgetEvents System

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

EventDescriptionData
openWidget opened by user{ sessionId, timestamp }
closeWidget closed by user{ sessionId, timestamp }
minimizeWidget minimized{ previousMode, sessionId }
maximizeWidget maximized{ previousMode, sessionId }

Session Events

EventDescriptionData
sessionStartNew chat session created{ sessionId, metadata }
sessionEndChat session ended{ sessionId, duration, messageCount }

Message Events

EventDescriptionData
messageStartUser submitted a message{ message, timestamp }
messageCompleteAI response completed{ answer, queryId, duration }
messageChunkStreaming message chunk received{ chunk, queryId }

Interaction Events

EventDescriptionData
typingUser is typing{ text, length }
typingStopUser stopped typing{ finalText }
feedbackUser submitted feedback{ rating, messageId, comment? }
copyUser copied message content{ content, messageId }

Voice & TTS Events

EventDescriptionData
voiceStartVoice recognition started{ language, sessionId }
voiceEndVoice recognition ended{ transcript, duration }
ttsStartText-to-speech started{ text, messageId }
ttsEndText-to-speech ended{ duration, messageId }

Error Events

EventDescriptionData
errorError 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 timestamp
  • sessionId - Current session identifier (when applicable)

Duration Fields

Duration measurements in milliseconds for:

  • sessionEnd.duration - Session length
  • messageComplete.duration - Response time
  • voiceEnd.duration - Voice input duration
  • ttsEnd.duration - TTS playback duration

Error Types

The error event includes a type field:

  • interceptor - Message interceptor error
  • timeout - Request timeout
  • backend - Backend API error
  • feedback - Feedback submission error
  • unknown - Unclassified error

Interactive Demo

See the Events System Demo to watch events fire in real-time as you interact with the widget.

Next Steps