Skip to main content

Manual events reference

Emit and subscribe to Support events from custom widget code.

Reach for this page when custom widget code needs an in-process event channel.

If you are still shipping the widget, start with Overview, Change One Thing, or Pages & Layouts.

Use this page when

  • you want custom pages to publish events to app-level callbacks
  • you want custom error logging tied to your own widget actions
  • you are building custom pages that need to emit Support events

Smallest working snippet

Put the callback and emitter under the same <Support.Root> runtime.

import { Support, useSupportEventEmitter } from "@cossistant/react";
 
function StartConversationButton() {
  const events = useSupportEventEmitter();
 
  return (
    <button
      onClick={() => events.emitConversationStart("01K0000000000000000000000")}
      type="button"
    >
      Start conversation
    </button>
  );
}
 
export function SupportWidget() {
  return (
    <Support.Root
      onConversationStart={({ conversationId }) => {
        analytics.track("support_conversation_started", { conversationId });
      }}
    >
      <StartConversationButton />
    </Support.Root>
  );
}

Event payloads

onConversationStart

Parameter

Type

onConversationEnd

Parameter

Type

onMessageSent

Parameter

Type

onMessageReceived

Parameter

Type

onError

Parameter

Type

Subscribe inside custom UI

Use useSupportEvents() when the listener belongs inside a custom widget component.

"use client";
 
import { useSupportEvents } from "@cossistant/react";
import { useEffect } from "react";
 
export function AnalyticsTracker() {
  const events = useSupportEvents();
 
  useEffect(() => {
    if (!events) {
      return;
    }
 
    const unsubscribe = events.subscribe("messageSent", (event) => {
      analytics.track("message_sent", event);
    });
 
    return unsubscribe;
  }, [events]);
 
  return null;
}

Emit from custom pages

Use useSupportEventEmitter() when your own page needs to emit the same widget events other listeners expect. Emission is synchronous and local to the current runtime. Cossistant does not persist, retry, deduplicate, or server-confirm these events.

"use client";
 
import { useSupportEventEmitter } from "@cossistant/react";
 
export function CustomConversationPage({
  conversationId,
  onArchive,
}: {
  conversationId: string;
  onArchive: (conversationId: string) => Promise<void>;
}) {
  const emitter = useSupportEventEmitter();
 
  const handleArchive = async () => {
    try {
      await onArchive(conversationId);
      emitter.emitConversationEnd(conversationId);
    } catch (cause) {
      const error =
        cause instanceof Error ? cause : new Error("Could not archive conversation");
      emitter.emitError(error, "conversation_archive_failed");
    }
  };
 
  return <button onClick={() => void handleArchive()}>Archive</button>;
}

Pass your application action as onArchive. Emit only after that action reaches the state your analytics contract defines. Message events require the actual TimelineItem; do not fabricate one from a message ID.

Next step

Was this page helpful?

Open a prefilled documentation issue so the team can act on your feedback.