message.comDevelopers

Widget events Live

The widget emits lifecycle events you can subscribe to from your page. Use them to wire analytics, trigger UI changes, or chain extra automation on top of the chat.

Subscribing

Use Message.on(name, handler) to subscribe and Message.once(name, handler) for a one-shot listener. The return value of both is an unsubscribe function. Handlers receive a single payload object whose shape depends on the event.

JavaScript
// Subscribe to an event. Returns an unsubscribe function.
const off = Message.on('message:received', (msg) => {
  console.log('agent reply:', msg.body);
});

// Later, stop listening.
off();

// One-shot listener: fires once, then unsubscribes itself.
Message.once('ready', () => {
  console.log('widget booted');
});

Subscriptions are local to the browser session and not persisted. Re-register them on every page load (or inside your framework's mount lifecycle).

Lifecycle events

EventFires whenPayload
readyBundle has loaded and public config has resolved.None.
openPanel is opened (programmatically or by click).None.
closePanel is closed.None.
conversation:startedThe visitor sends their first message in a session.Conversation object.
conversation:assignedAn agent picks up the conversation.Conversation with assignedAgent.
conversation:closedAgent or visitor closes the conversation.Conversation object.
message:sentVisitor sends a message.Message object.
message:receivedAgent reply arrives.Message object with agent details.
agent:typingAgent typing indicator starts.{ conversationId, agentId }
agent:typing-stoppedAgent typing indicator clears.{ conversationId, agentId }
visitor:identifiedSuccessful identify call (server confirmed).Visitor record.
errorTransport, auth, or rate-limit error.{ code, message }

Payload shapes

Payload examples for the most common events. The full set of fields is documented in the Messages API.

JavaScript · payload examples
// message:received
{
  id: 'uuid',
  conversationId: 'uuid',
  body: 'Plain text reply',
  bodyHtml: '<p>Sanitized HTML</p>',
  agent: { id: 'uuid', name: 'Sam', avatarUrl: '...' },
  createdAt: '2026-05-13T15:30:00Z'
}

// conversation:started
{
  id: 'uuid',
  channel: 'chat',
  status: 'open',
  createdAt: '...'
}

// conversation:assigned
{
  id: 'uuid',
  assignedAgent: { id: 'uuid', name: 'Sam', avatarUrl: '...' }
}

// agent:typing
{
  conversationId: 'uuid',
  agentId: 'uuid'
}

// error
{
  code: 'connection_failed' | 'auth_failed' | 'rate_limited',
  message: 'Human-readable description'
}

Wiring analytics

Conversation started, first response received, and conversation closed are the highest-signal events for buyer-intent and CSAT instrumentation. Fire them into your analytics tool of choice.

JavaScript · analytics example
Message.on('conversation:started', (conv) => {
  // Fire analytics. Buyer-intent signal.
  gtag('event', 'chat_started', {
    conversation_id: conv.id,
    page: location.pathname
  });
});

Message.on('message:received', (msg) => {
  // Track agent response latency.
  if (window.__msgStarted) {
    const ms = Date.now() - window.__msgStarted;
    gtag('event', 'first_response', { duration_ms: ms });
  }
});

For more on chat-to-paid attribution, see Track chat-to-paid conversion.

Server-side equivalents

If you need the same events server-side (for example, to log a conversation into your data warehouse), use outgoing webhooks. The widget events listed here mirror the relevant subset of agent-namespace Socket.io events. See Agent namespace and Webhooks overview.

Common pitfalls

  • Listening before ready. Calling Message.on before the bundle loads throws. Use MessageOnReady to defer registration.
  • Leaking handlers. In a single-page app, register listeners inside onMount and remove them in onUnmount. Without cleanup, listeners stack up across route changes.
  • Treating events as the source of truth. Events fire optimistically. For audit-grade data, use the REST API timeline at Conversations.
  • Unknown event names. Subscribing to an event we do not emit is a silent no-op. Typos do not throw.