Overview
Cossistant provides React hooks for programmatic control over every aspect of the support widget. These hooks follow a layered architecture:
- Core hooks (
useSupport,useVisitor) - Primary integration points - Widget state hooks (
useSupportConfig,useSupportNavigation) - Control widget behavior - Page hooks (
useHomePage,useConversationPage) - Build custom pages - Utility hooks (
useFileUpload,useMessageComposer) - Compose functionality
useSupport
Access support widget state and controls from any client component.
Basic Example
"use client";
import { useSupport } from "@cossistant/next";
export function CustomSupportButton() {
const { isOpen, toggle, unreadCount } = useSupport();
return (
<button
onClick={toggle}
className="relative rounded-lg bg-primary px-4 py-2 text-white"
>
Support
{unreadCount > 0 && (
<span className="absolute -right-1 -top-1 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 text-xs">
{unreadCount}
</span>
)}
</button>
);
}Return Values
Name
Type
useVisitor
Programmatically identify visitors and manage contact metadata.
Example: Identify on Auth
"use client";
import { useVisitor } from "@cossistant/next";
import { useEffect } from "react";
export function AuthHandler({ user }) {
const { visitor, identify } = useVisitor();
useEffect(() => {
// Only identify if we have a user and visitor isn't already a contact
if (user && !visitor?.contact) {
identify({
externalId: user.id,
email: user.email,
name: user.name,
image: user.avatar,
});
}
}, [user, visitor?.contact, identify]);
return null;
}Example: Update Metadata on Action
"use client";
import { useVisitor } from "@cossistant/next";
export function UpgradeButton() {
const { setVisitorMetadata } = useVisitor();
const handleUpgrade = async () => {
// Upgrade user's plan
await upgradeToPro();
// Update contact metadata so support agents see the change
await setVisitorMetadata({
plan: "pro",
upgradedAt: new Date().toISOString(),
mrr: 99,
});
};
return <button onClick={handleUpgrade}>Upgrade to Pro</button>;
}Return Values
Name
Type
identify() Parameters
Parameter
Type
Use the
IdentifySupportVisitor
component for a simpler, declarative approach to visitor identification in Server Components.
useSupportConfig
Access and control widget visibility and size configuration.
Basic Example
"use client";
import { useSupportConfig } from "@cossistant/next/support";
export function CustomToggle() {
const { isOpen, open, close, toggle, size } = useSupportConfig();
return (
<div className="flex gap-2">
<button onClick={toggle}>
{isOpen ? "Close Support" : "Open Support"}
</button>
<span>Size: {size}</span>
</div>
);
}Return Values
Name
Type
When using controlled mode (open and onOpenChange props on Support), these functions
will call onOpenChange instead of modifying internal state.
useSupportNavigation
Access navigation state and routing methods for the widget.
Basic Example
"use client";
import { useSupportNavigation } from "@cossistant/next/support";
export function NavigationButtons() {
const { page, navigate, goBack, canGoBack } = useSupportNavigation();
return (
<div className="flex gap-2">
{canGoBack && <button onClick={goBack}>← Back</button>}
<span>Current page: {page}</span>
<button onClick={() => navigate({ page: "HOME" })}>Go Home</button>
<button
onClick={() =>
navigate({
page: "CONVERSATION",
params: { conversationId: "conv_123" }
})
}
>
Open Conversation
</button>
</div>
);
}Return Values
Name
Type
useSupportHandle
Access the imperative handle from within the widget tree. Alternative to using refs on the Support component. The hook returns null outside the widget tree, and the table below describes the handle when it is available.
Basic Example
"use client";
import { useSupportHandle } from "@cossistant/next/support";
export function HelpButton() {
const support = useSupportHandle();
const handleNeedHelp = () => {
// Open support and start a new conversation
support?.startConversation("I need help with my order");
};
return (
<button onClick={handleNeedHelp}>
Need Help?
</button>
);
}Return Values
Name
Type
useHomePage
Logic hook for building custom home pages. Provides all state and actions needed for the home page.
Basic Example
"use client";
import { useHomePage } from "@cossistant/next";
export function CustomHomePage() {
const home = useHomePage({
onStartConversation: () => console.log("Conversation started"),
onOpenConversation: (id) => console.log("Opened:", id),
});
return (
<div>
<h1>Welcome!</h1>
{home.lastOpenConversation && (
<button onClick={() => home.openConversation(home.lastOpenConversation!.id)}>
Continue conversation
</button>
)}
<button onClick={() => home.startConversation()}>
Start new conversation
</button>
{home.availableConversationsCount > 0 && (
<button onClick={home.openConversationHistory}>
View {home.availableConversationsCount} conversations
</button>
)}
</div>
);
}Return Values
Name
Type
useConversationPage
Logic hook for building custom conversation pages. Manages the conversation lifecycle, messages, and composer.
Basic Example
"use client";
import { useConversationPage } from "@cossistant/next";
export function CustomConversationPage({ conversationId }: { conversationId: string }) {
const conversation = useConversationPage({
conversationId,
onConversationIdChange: (id) => console.log("Active:", id),
});
return (
<div>
{/* Messages */}
<div className="flex-1 overflow-y-auto">
{conversation.items.map((item) => (
<div key={item.id}>{/* Render message */}</div>
))}
</div>
{/* Composer */}
<form onSubmit={(e) => { e.preventDefault(); conversation.composer.submit(); }}>
<input
value={conversation.composer.message}
onChange={(e) => conversation.composer.setMessage(e.target.value)}
placeholder={conversation.isPending ? "Start the conversation..." : "Type a message..."}
/>
<button
type="submit"
disabled={!conversation.composer.canSubmit || conversation.composer.isSubmitting}
>
Send
</button>
</form>
</div>
);
}Return Values
Name
Type
useMessageComposer
Hook for managing message composition with file attachments.
Basic Example
"use client";
import { useMessageComposer } from "@cossistant/next";
export function MessageInput({ conversationId }: { conversationId: string }) {
const composer = useMessageComposer({
conversationId,
onMessageSent: () => console.log("Message sent!"),
});
return (
<form onSubmit={(e) => { e.preventDefault(); composer.submit(); }}>
<input
value={composer.message}
onChange={(e) => composer.setMessage(e.target.value)}
placeholder="Type a message..."
/>
<input
type="file"
multiple
onChange={(e) => {
if (e.target.files) {
composer.addFiles(Array.from(e.target.files));
}
}}
/>
{composer.files.map((file, index) => (
<span key={file.name}>
{file.name}{" "}
<button type="button" onClick={() => composer.removeFile(index)}>
×
</button>
</span>
))}
<button type="submit" disabled={!composer.canSubmit || composer.isSubmitting}>
{composer.isSubmitting ? "Sending..." : "Send"}
</button>
</form>
);
}Return Values
Name
Type
useFileUpload
Hook for handling file uploads with progress tracking.
Basic Example
"use client";
import { useFileUpload } from "@cossistant/next";
export function FileUploader() {
const upload = useFileUpload();
const conversationId = "conv_123";
return (
<div>
<input
type="file"
multiple
onChange={async (e) => {
if (e.target.files?.length) {
await upload.uploadFiles(Array.from(e.target.files), conversationId);
}
}}
/>
{upload.isUploading && (
<div>
<progress value={upload.progress} max={100} />
<span>{upload.progress}%</span>
</div>
)}
{upload.error && <p className="text-red-500">{upload.error.message}</p>}
</div>
);
}Return Values
Name
Type
useSupportText
Access the localization system for the support widget.
Basic Example
"use client";
import { useSupportText } from "@cossistant/next/support";
export function LocalizedButton() {
const format = useSupportText();
return (
<button>
{format("common.actions.askQuestion")}
</button>
);
}Returned Formatter
useSupportText() returns a formatter function. The table below documents that
function reference.
Name
Type
useSupportEvents
Access the events context for subscribing to widget lifecycle events. The hook returns null when used outside the widget's event provider, and the table below documents the event context when present.
Basic Example
"use client";
import { useSupportEvents } from "@cossistant/next/support";
import { useEffect } from "react";
export function AnalyticsTracker() {
const events = useSupportEvents();
useEffect(() => {
if (!events) return;
const unsubscribe = events.subscribe("messageSent", (event) => {
// Track in your analytics
analytics.track("support_message_sent", {
conversationId: event.conversationId,
});
});
return unsubscribe;
}, [events]);
return null;
}Return Values
Name
Type
useSupportEventEmitter
Convenience hook for emitting events from within the widget.
Return Values
Name
Type
Types
Shared support hook and data-model types now live on the
Types page. Use it for PublicVisitor,
PublicWebsiteResponse, CossistantClient, TimelineItem, Conversation,
and the rest of the canonical support type reference.
On this page
OverviewuseSupportBasic ExampleReturn ValuesuseVisitorExample: Identify on AuthExample: Update Metadata on ActionReturn Valuesidentify() ParametersuseSupportConfigBasic ExampleReturn ValuesuseSupportNavigationBasic ExampleReturn ValuesuseSupportHandleBasic ExampleReturn ValuesuseHomePageBasic ExampleReturn ValuesuseConversationPageBasic ExampleReturn ValuesuseMessageComposerBasic ExampleReturn ValuesuseFileUploadBasic ExampleReturn ValuesuseSupportTextBasic ExampleReturned FormatteruseSupportEventsBasic ExampleReturn ValuesuseSupportEventEmitterReturn ValuesTypes