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
The built-in widget does not automatically emit conversation, message, or
error events. Callback props and subscriptions run only for events your
custom code emits with useSupportEventEmitter(). Do not use these props as
built-in analytics instrumentation yet.
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
- Hooks Reference for the hook-level APIs used on this page
- Types Reference for the shared event and message types
Was this page helpful?
Open a prefilled documentation issue so the team can act on your feedback.