Overview
The Express adapter provides a ready-to-use router for integrating CopilotKit with Express.js applications. It handles all CopilotKit endpoints including agent execution, connection, transcription, and runtime info.
Installation
npm install @copilotkit/runtime express
Basic Usage
import express from 'express';
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { BuiltInAgent } from '@copilotkit/agent';
const app = express();
const runtime = new CopilotRuntime({
agents: {
'default': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY
})
}
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
API Reference
createCopilotEndpointExpress()
Creates an Express router with all CopilotKit endpoints.
function createCopilotEndpointExpress(
params: CopilotExpressEndpointParams
): Router
The CopilotRuntime instance to use for handling requests.
Base path for all CopilotKit endpoints. Must start with /.basePath: '/api/copilotkit'
Returns: An Express Router instance.
Endpoints
The adapter automatically creates the following endpoints:
POST /agent/:agentId/run
Execute an agent with new input.
Parameters:
agentId (path): Agent identifier
Request body:
{
"runId": "run_123",
"threadId": "thread_456",
"messages": [...],
"tools": [...],
"context": [...],
"state": {...}
}
Response: Server-Sent Events (SSE) stream of AG-UI events
POST /agent/:agentId/connect
Connect to an existing thread to receive events.
Parameters:
agentId (path): Agent identifier
Request body:
{
"threadId": "thread_456"
}
Response: Server-Sent Events (SSE) stream of thread events
POST /agent/:agentId/stop/:threadId
Stop a running agent execution.
Parameters:
agentId (path): Agent identifier
threadId (path): Thread identifier
Response:
GET /info
Get runtime information including available agents.
Response:
{
"version": "1.0.0",
"agents": {
"default": {
"id": "default",
"name": "Default Agent"
}
}
}
POST /transcribe
Transcribe audio input (requires transcription service).
Request: Multipart form data with audio file
Response:
{
"text": "Transcribed text..."
}
CORS Configuration
The adapter automatically configures CORS with permissive settings:
cors({
origin: "*",
methods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH", "OPTIONS"],
allowedHeaders: ["*"]
})
For production, you may want to add your own CORS middleware before the CopilotKit router:
import cors from 'cors';
app.use('/api/copilotkit', cors({
origin: 'https://your-frontend.com',
credentials: true
}));
app.use(copilotRouter);
Examples
Basic Setup
import express from 'express';
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { BuiltInAgent } from '@copilotkit/agent';
const app = express();
const runtime = new CopilotRuntime({
agents: {
'assistant': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY,
prompt: 'You are a helpful assistant.'
})
}
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
app.listen(3000);
Multiple Agents
const runtime = new CopilotRuntime({
agents: {
'customer-support': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY,
prompt: 'You are a customer support agent.'
}),
'sales': new BuiltInAgent({
model: 'anthropic/claude-sonnet-4.5',
apiKey: process.env.ANTHROPIC_API_KEY,
prompt: 'You are a sales assistant.'
})
}
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
With Authentication Middleware
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
const runtime = new CopilotRuntime({
agents: { ... },
beforeRequestMiddleware: async (request) => {
const token = request.headers.get('Authorization');
if (!token) {
return new Response('Unauthorized', { status: 401 });
}
const user = await verifyToken(token);
if (!user) {
return new Response('Invalid token', { status: 401 });
}
// Add user ID to headers
return new Request(request.url, {
...request,
headers: {
...Object.fromEntries(request.headers.entries()),
'X-User-Id': user.id
}
});
}
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
With Transcription
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { OpenAITranscriptionService } from '@copilotkit/runtime/transcription';
const runtime = new CopilotRuntime({
agents: { ... },
transcriptionService: new OpenAITranscriptionService({
apiKey: process.env.OPENAI_API_KEY,
model: 'whisper-1'
})
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
Custom Base Path
// Mount at /copilot instead of /api/copilotkit
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/copilot'
});
app.use(copilotRouter);
// Frontend would connect to:
// http://localhost:3000/copilot
With Body Parser
import express from 'express';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
const app = express();
// Parse JSON bodies for other routes
app.use(express.json());
// CopilotKit router handles its own body parsing
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
// Other routes
app.post('/api/other', (req, res) => {
res.json({ message: 'Hello' });
});
Error Handling
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
// Global error handler
app.use((err, req, res, next) => {
console.error('Error:', err);
res.status(500).json({
error: 'Internal server error',
message: err.message
});
});
Development Server
import express from 'express';
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { BuiltInAgent } from '@copilotkit/agent';
const app = express();
const port = process.env.PORT || 3000;
const runtime = new CopilotRuntime({
agents: {
'default': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY
})
}
});
const copilotRouter = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(copilotRouter);
// Health check endpoint
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
console.log(`CopilotKit endpoint: http://localhost:${port}/api/copilotkit`);
});
Deployment
Vercel
// api/copilotkit.ts
import express from 'express';
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { BuiltInAgent } from '@copilotkit/agent';
const app = express();
const runtime = new CopilotRuntime({
agents: {
'default': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY
})
}
});
const router = createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
});
app.use(router);
export default app;
Docker
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
// server.js
import express from 'express';
import { CopilotRuntime } from '@copilotkit/runtime';
import { createCopilotEndpointExpress } from '@copilotkit/runtime/express';
import { BuiltInAgent } from '@copilotkit/agent';
const app = express();
const port = process.env.PORT || 3000;
const runtime = new CopilotRuntime({
agents: {
'default': new BuiltInAgent({
model: 'openai/gpt-4o',
apiKey: process.env.OPENAI_API_KEY
})
}
});
app.use(createCopilotEndpointExpress({
runtime,
basePath: '/api/copilotkit'
}));
app.listen(port, '0.0.0.0', () => {
console.log(`Server running on port ${port}`);
});
Troubleshooting
CORS Issues
If you encounter CORS errors, ensure your frontend URL is properly configured:
import cors from 'cors';
app.use('/api/copilotkit', cors({
origin: process.env.FRONTEND_URL || 'http://localhost:5173',
credentials: true
}));
app.use(createCopilotEndpointExpress({ ... }));
Base Path Not Working
Ensure the basePath starts with /:
// ✅ Correct
basePath: '/api/copilotkit'
// ❌ Wrong
basePath: 'api/copilotkit'
SSE Streaming Issues
Some proxies and load balancers buffer responses. Configure them to allow SSE:
nginx:
location /api/copilotkit {
proxy_pass http://backend;
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
See Also