Example status: Experimental
This example keeps the Realtime SFU credential on the server, but publisher and destructive operations are not authenticated. It is not a production reference.
Stream your camera through the Cloudflare Realtime SFU and view it as JPEG snapshots (~1 FPS) using the WebSocket media transport adapter.
After deployment, you can share a session with others entirely from your browser. It provides two interfaces: a Publisher page for camera control and a Viewer page for watching the JPEG stream.
Important: We recommend deploying to Cloudflare Workers first before trying local development. The Realtime SFU needs to connect back to your Worker via WebSocket, which doesn't work with
localhost.
-
Clone and install:
npm install
-
Configure
wrangler.jsoncvars and add secrets (see Configuration below). -
Build and deploy:
npm run build:web npx wrangler deploy
-
Open in your browser:
- Publisher:
https://<your-worker>.workers.dev/<session-name>/publisher - Viewer:
https://<your-worker>.workers.dev/<session-name>/viewer
- Publisher:
This demo uses the Realtime SFU's WebSocket adapter to convert WebRTC video into JPEG frames that can be processed in a Worker.
- Cloudflare Worker: Serves the UI and handles API requests. All secrets stay on the server.
- Cloudflare Realtime SFU: Receives your camera stream via WebRTC and converts video to JPEG frames (~1 FPS).
VideoAdapter(Durable Object): Manages each session. Receives JPEG frames from the SFU and broadcasts them to viewer WebSockets. See technical details.- Frontend UI: A TypeScript app bundled with
esbuildthat handles camera access, WebRTC connections, and displays JPEG snapshots.
- A Cloudflare account with Workers, Durable Objects, and Realtime SFU enabled.
- A configured Realtime SFU application.
- A Realtime SFU API bearer token.
- Node.js and npm.
- The Wrangler CLI.
-
Clone and Install:
git clone <repository-url> cd calls-examples/video-to-jpeg npm install
-
Set up
wrangler.jsonc: Open the file and add your SFU app ID to thevarsblock: -
Add Your Secret: Use Wrangler to store your Realtime SFU bearer token securely:
npx wrangler secret put REALTIME_SFU_BEARER_TOKEN
This token is used only from the Worker to the Realtime SFU API; it's never exposed to the browser.
-
Build the frontend:
npm run build:web
-
Deploy to Cloudflare Workers:
npx wrangler deploy
-
Open the Publisher page: Navigate to your deployed Worker's URL with any unique session name:
https://<your-worker>.workers.dev/<session-name>/publisher -
Start streaming:
- Click Connect Camera to allow camera access and establish WebRTC.
- Click Start JPEG Stream to begin streaming JPEG snapshots.
- You'll see your camera feed and the JPEG snapshots side-by-side.
-
Share the Viewer link: Send the viewer URL to anyone you want to share with:
https://<your-worker>.workers.dev/<session-name>/viewerThey'll see the JPEG stream without needing camera access.
-
Stop streaming:
- Click Stop JPEG Stream to stop the adapter.
- Click Reset Session to clear all state and start fresh.
URL patterns:
- Publisher:
/<session-name>/publisher- Viewer:
/<session-name>/viewer
⚠️ Localhost Limitation: The Realtime SFU cannot connect back tolocalhostWebSockets, so the JPEG adapter won't work locally. We strongly recommend deploying to Workers first to test the full functionality.
If you still want to develop locally (e.g., for UI changes):
-
Start the frontend watcher:
npm run watch:web
-
Start the Worker:
npm run dev
-
Open in browser:
http://localhost:8787/<session-name>/publisher
Note: WebRTC and the UI will work, but the JPEG streaming via the adapter will fail because the SFU can't reach your local machine.
For technical details about the architecture, API flows, and implementation, see ARCHITECTURE.md.
- Click the Reset Session button on the publisher page to clear the Durable Object state.
- Alternatively, send a DELETE request:
curl -X DELETE https://<your-worker>.workers.dev/<session-name>
- Check your browser's permissions for camera access.
- Try a different browser or device.
- Ensure you're using HTTPS (required for camera access, except on localhost).
- Make sure you clicked Start JPEG Stream after connecting the camera.
- Check the browser console for WebSocket errors.
- If testing locally, remember that the SFU can't connect to localhost—deploy to Workers instead.
- Run
npm run build:webto rebuild the frontend. - Check that
wrangler.jsonchas"assets": { "directory": "public" }. - Try a hard refresh in your browser.
- Ensure you ran
npm run build:webbeforenpx wrangler deploy. - Hard refresh your browser to clear cached assets.
- Video is streamed as JPEG at approximately 1 FPS (beta behavior).
- This is a reference demo and should not be used in production without:
- Authentication and authorization
- Error handling and monitoring
- Rate limiting and resource controls
For more details, see ARCHITECTURE.md.
{ // ... other wrangler config ... "vars": { "SFU_API_BASE": "https://rtc.live.cloudflare.com/v1", "REALTIME_SFU_APP_ID": "<your-realtime-sfu-app-id>" } }