# Configuration & Deployment ## Dashboard Setup 1. Navigate to https://dash.cloudflare.com/?to=/:account/calls 2. Click "Create Application" (or use existing app) 3. Copy `CALLS_APP_ID` from dashboard 4. Generate and copy `CALLS_APP_SECRET` (treat as sensitive credential) 5. Use credentials in Wrangler config or environment variables below ## Dependencies **Backend (Workers):** Built-in fetch API, no additional packages required **Client (PartyTracks):** ```bash npm install partytracks @cloudflare/calls ``` **Client (React + PartyTracks):** ```bash npm install partytracks @cloudflare/calls observable-hooks # Observable hooks: useObservableAsValue, useValueAsObservable ``` **Client (Raw API):** Native browser WebRTC API only ## Wrangler Setup ```jsonc { "name": "my-calls-app", "main": "src/index.ts", "compatibility_date": "2025-01-01", // Use current date for new projects "vars": { "CALLS_APP_ID": "your-app-id", "MAX_WEBCAM_BITRATE": "1200000", "MAX_WEBCAM_FRAMERATE": "24", "MAX_WEBCAM_QUALITY_LEVEL": "1080" }, // Set secret: wrangler secret put CALLS_APP_SECRET "durable_objects": { "bindings": [ { "name": "ROOM", "class_name": "Room" } ] } } ``` ## Deploy ```bash wrangler login wrangler secret put CALLS_APP_SECRET wrangler deploy ``` ## Environment Variables **Required:** - `CALLS_APP_ID`: From dashboard - `CALLS_APP_SECRET`: From dashboard (secret) **Optional:** - `MAX_WEBCAM_BITRATE` (default: 1200000) - `MAX_WEBCAM_FRAMERATE` (default: 24) - `MAX_WEBCAM_QUALITY_LEVEL` (default: 1080) - `TURN_SERVICE_ID`: TURN service - `TURN_SERVICE_TOKEN`: TURN auth (secret) ## TURN Configuration ```javascript const pc = new RTCPeerConnection({ iceServers: [ { urls: 'stun:stun.cloudflare.com:3478' }, { urls: [ 'turn:turn.cloudflare.com:3478?transport=udp', 'turn:turn.cloudflare.com:3478?transport=tcp', 'turns:turn.cloudflare.com:5349?transport=tcp' ], username: turnUsername, credential: turnCredential } ], bundlePolicy: 'max-bundle', // Recommended: reduces overhead iceTransportPolicy: 'all' // Use 'relay' to force TURN (testing only) }); ``` **Ports:** 3478 (UDP/TCP), 53 (UDP), 80 (TCP), 443 (TLS), 5349 (TLS) **When to use TURN:** Required for restrictive corporate firewalls/networks that block UDP. ~5-10% of connections fallback to TURN. STUN works for most users. **ICE candidate filtering:** Cloudflare handles candidate filtering automatically. No need to manually filter candidates. ## Durable Object Boilerplate Minimal presence system: ```typescript export class Room { private sessions = new Map(); async fetch(req: Request) { const {pathname} = new URL(req.url); const body = await req.json(); if (pathname === '/join') { this.sessions.set(body.sessionId, {userId: body.userId, tracks: []}); return Response.json({participants: this.sessions.size}); } if (pathname === '/publish') { this.sessions.get(body.sessionId)?.tracks.push(...body.tracks); // Broadcast to others via WebSocket (not shown) return new Response('OK'); } return new Response('Not found', {status: 404}); } } ``` ## Environment Validation Check credentials before first API call: ```typescript if (!env.CALLS_APP_ID || !env.CALLS_APP_SECRET) { throw new Error('CALLS_APP_ID and CALLS_APP_SECRET required'); } ```