Skip to content

Cloudflare Workers Adapter

The Cloudflare adapter creates a handler compatible with the Workers runtime.

Create a Worker at src/index.ts:

import { chatcopsCloudflareHandler } from '@chatcops/server';
export default {
async fetch(
request: Request,
env: Record<string, string>
): Promise<Response> {
const handler = chatcopsCloudflareHandler({
provider: {
type: 'claude',
apiKey: env.ANTHROPIC_API_KEY,
},
systemPrompt: 'You are a helpful assistant.',
cors: '*',
});
return handler(request);
},
};

Set secrets using Wrangler:

Terminal window
npx wrangler secret put ANTHROPIC_API_KEY

Or in wrangler.toml for non-secret values:

[vars]
SYSTEM_PROMPT = "You are a helpful assistant."
<script
src="https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js"
data-api-url="https://chatcops.your-domain.workers.dev"
></script>
import { chatcopsCloudflareHandler } from '@chatcops/server';
import { LeadCaptureTool } from '@chatcops/core/tools';
export default {
async fetch(request: Request, env: Record<string, string>): Promise<Response> {
const handler = chatcopsCloudflareHandler({
provider: {
type: 'gemini',
apiKey: env.GOOGLE_AI_API_KEY,
model: 'gemini-2.0-flash',
},
systemPrompt: env.SYSTEM_PROMPT || 'You are a helpful assistant.',
tools: [
new LeadCaptureTool({
onCapture: async (lead) => {
// Use Cloudflare KV, D1, or external webhook
await fetch(env.WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(lead),
});
},
}),
],
cors: '*',
rateLimit: { maxRequests: 20, windowMs: 60_000 },
});
return handler(request);
},
};
  • Cloudflare Workers have a 30-second CPU time limit (Bundled plan) or 15 minutes (Unbound)
  • SSE streaming works natively on Workers
  • Use Cloudflare KV or D1 for persistent storage (conversation history, analytics)
  • The env object provides access to secrets and bindings