Skip to main content

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
runtime
CopilotRuntime
required
The CopilotRuntime instance to use for handling requests.
basePath
string
required
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:
{
  "success": true
}

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