showcase/shell-docs/src/content/docs/premium/observability.mdx
Monitor your CopilotKit application with first-class observability hooks that emit structured signals for chat events, user interactions, and runtime errors. Send them straight to your existing stack — Sentry, Datadog, New Relic, OpenTelemetry — or route them to your analytics pipeline. The hooks expose stable schemas and IDs so you can join agent events with app telemetry, trace sessions end to end, and alert on failures in real time.
Works with Copilot Cloud via publicApiKey, or self-hosted via publicLicenseKey.
Track user interactions and chat events:
import { CopilotKitProvider, CopilotChat } from "@copilotkit/react-core/v2";
export default function App() {
return (
<CopilotKitProvider
publicApiKey="ck_pub_your_key" // [!code highlight] — Copilot Cloud
// OR
publicLicenseKey="ck_pub_your_key" // [!code highlight] — self-hosted
>
<CopilotChat
observabilityHooks={{
onMessageSent: (message) => {
console.log("Message sent:", message);
analytics.track("chat_message_sent", { message });
},
onChatExpanded: () => analytics.track("chat_expanded"),
onChatMinimized: () => analytics.track("chat_minimized"),
onFeedbackGiven: (messageId, type) => {
analytics.track("chat_feedback", { messageId, type });
},
}}
/>
</CopilotKitProvider>
);
}
Monitor runtime errors:
import { CopilotKitProvider } from "@copilotkit/react-core/v2";
<CopilotKitProvider
publicApiKey="ck_pub_your_key" // [!code highlight]
// OR
publicLicenseKey="ck_pub_your_key" // [!code highlight]
onError={(errorEvent) => {
console.error("CopilotKit Error:", errorEvent);
analytics.track("copilotkit_error", {
type: errorEvent.type,
source: errorEvent.context.source,
timestamp: errorEvent.timestamp,
});
}}
showDevConsole={false} // hide dev console in production
>
</CopilotKitProvider>;
Pass any subset of these in observabilityHooks on CopilotChat / CopilotPopup / CopilotSidebar:
| Hook | Fires when |
|---|---|
onMessageSent(message) | User sends a message |
onChatExpanded() | Chat opens/expands |
onChatMinimized() | Chat closes/minimizes |
onMessageRegenerated(messageId) | Message is regenerated |
onMessageCopied(content) | Message content is copied |
onFeedbackGiven(messageId, type) | Thumbs up/down feedback given |
onChatStarted() | Chat generation starts |
onChatStopped() | Chat generation stops |
onError(errorEvent) | An error event fires |
The onError handler receives a detailed event with rich context:
interface CopilotErrorEvent {
type:
| "error"
| "request"
| "response"
| "agent_state"
| "action"
| "message"
| "performance";
timestamp: number;
context: {
source: "ui" | "runtime" | "agent";
request?: {
operation: string;
method?: string;
url?: string;
startTime: number;
};
response?: { endTime: number; latency: number };
agent?: { name: string; nodeName?: string };
messages?: { input: any[]; messageCount: number };
technical?: { environment: string; stackTrace?: string };
};
error?: any; // present for error events
}
Forward error events to Sentry using its captureException API:
import * as Sentry from "@sentry/react";
<CopilotKitProvider
publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
onError={(errorEvent) => {
if (errorEvent.type === "error") {
Sentry.captureException(errorEvent.error, {
tags: {
source: errorEvent.context.source,
operation: errorEvent.context.request?.operation,
},
extra: {
context: errorEvent.context,
timestamp: errorEvent.timestamp,
},
});
}
}}
>
</CopilotKitProvider>;
Route all CopilotKit events to your analytics pipeline via the onError callback:
<CopilotKitProvider
publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
onError={(errorEvent) => {
analytics.track("copilotkit_event", {
event_type: errorEvent.type,
source: errorEvent.context.source,
agent_name: errorEvent.context.agent?.name,
latency: errorEvent.context.response?.latency,
error_message: errorEvent.error?.message,
timestamp: errorEvent.timestamp,
});
}}
>
</CopilotKitProvider>
Enable the dev console and attach lightweight logging hooks for local iteration:
<CopilotKitProvider
runtimeUrl="http://localhost:3000/api/copilotkit"
publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
showDevConsole={true}
onError={(errorEvent) => console.log("CopilotKit Event:", errorEvent)}
>
<CopilotChat
observabilityHooks={{
onMessageSent: (message) => console.log("Message sent:", message),
onChatExpanded: () => console.log("Chat expanded"),
}}
/>
</CopilotKitProvider>
Disable the dev console and route errors to your logging and monitoring services:
<CopilotKitProvider
runtimeUrl="https://your-app.com/api/copilotkit"
publicLicenseKey={process.env.NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY}
showDevConsole={false} // hide from end users
onError={(errorEvent) => {
if (errorEvent.type === "error") {
logger.error("CopilotKit Error", {
error: errorEvent.error,
context: errorEvent.context,
timestamp: errorEvent.timestamp,
});
monitoring.captureError(errorEvent.error, { extra: errorEvent.context });
}
}}
>
<CopilotChat
observabilityHooks={{
onMessageSent: (message) =>
analytics.track("chat_message_sent", {
messageLength: message.length,
userId: getCurrentUserId(),
}),
onChatExpanded: () => analytics.track("chat_expanded"),
onFeedbackGiven: (messageId, type) =>
analytics.track("chat_feedback", { messageId, type }),
}}
/>
</CopilotKitProvider>
Sign up free at https://cloud.copilotkit.ai
Grab your public license key (self-hosting) or public API key (Copilot Cloud) from the dashboard
Add it to your env vars:
NEXT_PUBLIC_COPILOTKIT_LICENSE_KEY=ck_pub_your_key_here
# OR
NEXT_PUBLIC_COPILOTKIT_API_KEY=ck_pub_your_key_here
Pass it to CopilotKitProvider and start wiring up observability hooks.