chatkit-js
π―Skillfrom naimalarain13/hackathon-ii_the-evolution-of-todo
Simplifies real-time chat functionality by integrating Pusher Chatkit for seamless messaging and user interaction in web applications
Installation
npx skills add https://github.com/naimalarain13/hackathon-ii_the-evolution-of-todo --skill chatkit-jsSkill Details
Overview
---
name: chatkit-js
description: Integrate OpenAI ChatKit React components into Next.js applications. Covers custom API backend configuration, theming, widget embedding, conversation history, and authentication integration.
---
# ChatKit JS Frontend Skill
Integrate OpenAI ChatKit UI components into Next.js applications with custom backend support.
Architecture
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Next.js Frontend β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β ChatKit Widget β β
β β β’ useChatKit hook with custom API config β β
β β β’ Theming & customization β β
β β β’ Auth token injection β β
β β β’ Conversation history β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Custom fetch with JWT
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FastAPI Backend β
β /api/chat (SSE streaming) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
Quick Start
Installation
```bash
npm install @openai/chatkit-react
# Or with pnpm
pnpm add @openai/chatkit-react
```
Environment Variables
```env
# Domain key from OpenAI (for hosted mode)
NEXT_PUBLIC_OPENAI_DOMAIN_KEY=your-domain-key
# Custom API URL (for custom backend mode)
NEXT_PUBLIC_CHAT_API_URL=http://localhost:8000/api/chat
```
Reference
| Pattern | Guide |
|---------|-------|
| Basic Setup | [reference/basic-setup.md](reference/basic-setup.md) |
| Custom API | [reference/custom-api.md](reference/custom-api.md) |
| Theming | [reference/theming.md](reference/theming.md) |
Examples
| Example | Description |
|---------|-------------|
| [examples/todo-chatbot.md](examples/todo-chatbot.md) | Complete todo chatbot widget |
Templates
| Template | Purpose |
|----------|---------|
| [templates/ChatWidget.tsx](templates/ChatWidget.tsx) | ChatKit widget component |
| [templates/ChatPage.tsx](templates/ChatPage.tsx) | Full chat page layout |
Basic ChatKit Widget
```tsx
"use client";
import { ChatKit, useChatKit } from "@openai/chatkit-react";
export function ChatWidget() {
const { control } = useChatKit({
api: {
url: process.env.NEXT_PUBLIC_CHAT_API_URL || "/api/chat",
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY,
},
});
return (
control={control}
className="h-[600px] w-[400px] rounded-lg shadow-lg"
/>
);
}
```
Custom API with Authentication
```tsx
"use client";
import { ChatKit, useChatKit } from "@openai/chatkit-react";
import { useSession } from "@/lib/auth-client"; // Better Auth
export function AuthenticatedChat() {
const { data: session } = useSession();
const { control } = useChatKit({
api: {
url: process.env.NEXT_PUBLIC_CHAT_API_URL || "/api/chat",
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY,
// Custom fetch to inject auth token
fetch: async (input, init) => {
const token = session?.session?.token;
return fetch(input, {
...init,
headers: {
...init?.headers,
"Authorization": Bearer ${token},
"Content-Type": "application/json",
},
credentials: "include",
});
},
},
});
if (!session) {
return
}
return (
control={control}
className="h-full w-full"
/>
);
}
```
Theming
```tsx
const { control } = useChatKit({
api: { / ... / },
theme: {
colorScheme: "dark", // or "light"
color: {
accent: {
primary: "#3b82f6", // Blue accent
level: 2,
},
grayscale: {
hue: 220,
tint: 5,
shade: 0,
},
surface: {
background: "#1f2937",
foreground: "#f9fafb",
},
},
radius: "soft", // "none", "soft", "round"
density: "normal", // "compact", "normal", "spacious"
typography: {
fontFamily: "Inter, system-ui, sans-serif",
fontFamilyMono: "JetBrains Mono, monospace",
baseSize: 16,
},
},
});
```
Start Screen Customization
```tsx
const { control } = useChatKit({
api: { / ... / },
startScreen: {
greeting: "Hi! I'm your task assistant. How can I help?",
prompts: [
{
name: "View Tasks",
prompt: "Show me my pending tasks",
icon: "list",
},
{
name: "Add Task",
prompt: "Help me add a new task",
icon: "plus",
},
{
name: "Get Help",
prompt: "What can you help me with?",
icon: "question",
},
],
},
});
```
Header Customization
```tsx
const { control } = useChatKit({
api: { / ... / },
header: {
enabled: true,
title: {
enabled: true,
text: "Todo Assistant",
},
leftAction: {
icon: "sidebar-left",
onClick: () => toggleSidebar(),
},
rightAction: {
icon: "settings-cog",
onClick: () => openSettings(),
},
},
});
```
Composer Customization
```tsx
const { control } = useChatKit({
api: { / ... / },
composer: {
placeholder: "Ask me to manage your tasks...",
tools: [
{
id: "tasks",
label: "Tasks",
shortLabel: "Tasks",
icon: "list",
placeholderOverride: "What task would you like to add?",
pinned: true,
},
{
id: "search",
label: "Search",
shortLabel: "Search",
icon: "search",
placeholderOverride: "Search your tasks...",
pinned: true,
},
],
attachments: {
enabled: false, // Enable if backend supports
maxSize: 10 1024 1024, // 10MB
maxCount: 3,
accept: {
"image/*": [".png", ".jpg", ".jpeg"],
"application/pdf": [".pdf"],
},
},
},
});
```
Conversation History
```tsx
const { control } = useChatKit({
api: { / ... / },
history: {
enabled: true,
showDelete: true,
showRename: true,
},
});
```
Embedding as Widget
For embedding the chatbot as a floating widget:
```tsx
"use client";
import { useState } from "react";
import { ChatKit, useChatKit } from "@openai/chatkit-react";
export function FloatingChatWidget() {
const [isOpen, setIsOpen] = useState(false);
const { control } = useChatKit({
api: {
url: "/api/chat",
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY,
},
});
return (
<>
{/ Toggle Button /}
onClick={() => setIsOpen(!isOpen)}
className="fixed bottom-4 right-4 z-50 rounded-full bg-blue-600 p-4 text-white shadow-lg hover:bg-blue-700"
>
{isOpen ? "β" : "π¬"}
{/ Chat Widget /}
{isOpen && (
)}
>
);
}
```
Full Page Chat
```tsx
"use client";
import { ChatKit, useChatKit } from "@openai/chatkit-react";
export default function ChatPage() {
const { control } = useChatKit({
api: {
url: "/api/chat",
domainKey: process.env.NEXT_PUBLIC_OPENAI_DOMAIN_KEY,
},
theme: {
colorScheme: "light",
},
startScreen: {
greeting: "Welcome! How can I help you today?",
},
});
return (
Todo Chatbot
);
}
```
OpenAI Domain Allowlist Setup
For production deployment:
- Deploy frontend to get production URL
- Add domain to OpenAI allowlist:
- Go to: https://platform.openai.com/settings/organization/security/domain-allowlist
- Click "Add domain"
- Enter your frontend URL (without trailing slash)
- Get domain key and add to env variables
Note: localhost typically works without domain allowlist configuration.
Error Handling
```tsx
const { control, error, isLoading } = useChatKit({
api: { / ... / },
});
if (error) {
return
}
if (isLoading) {
return
}
```
Best Practices
- Use "use client" - ChatKit requires client-side rendering
- Configure CORS - Ensure backend allows frontend origin
- Inject auth tokens - Use custom fetch for authenticated requests
- Handle errors - Show user-friendly error states
- Customize theming - Match your app's design system
- Use start screen prompts - Guide users on what they can do
- Enable history - Allow users to continue conversations