Relay protocol
The Connect relay accepts HTTPS POST requests and forwards them to WebSocket subscribers. It uses Cloudflare Workers and Durable Objects, with a separate buffer and set of connections for each token.
For recorder setup using an existing relay, see Connect relay.
Responsibilities
Section titled “Responsibilities”The relay forwards notification bodies without parsing or verifying them. The recorder verifies Twitch’s HMAC signatures. The relay holds no Twitch credentials or signing secret.
Normal notifications are buffered for up to five minutes to support reconnects. Verification challenges require a synchronous response from the recorder. The relay handles this POST-to-WebSocket exchange only; it doesn’t proxy the dashboard or recording files.
Tokens
Section titled “Tokens”Tokens must match [a-zA-Z0-9_-]{16,128}. Each token identifies one Durable Object. Multiple clients can subscribe with the same token.
Ingest
Section titled “Ingest”POST /u/{token}Content-Type: application/json
<body>Normal notifications return 202 Accepted immediately. For Twitch EventSub verification challenges, the relay waits for the subscribed client to replay the request locally and returns the local handler’s response to Twitch.
Subscribe
Section titled “Subscribe”GET /u/{token}/subscribe?cursor={last_cursor}Upgrade: websocketOn connection, the relay replays buffered notifications with a cursor greater than the supplied value, then sends new notifications. Cursors increase with each stored event.
Frames the relay sends
Section titled “Frames the relay sends”{ "id": "uuid", "cursor": 42, "ts": 1714291200000, "headers": { "twitch-eventsub-message-id": "...", "...": "..." }, "body": "<base64-encoded body>", "requires_response": false}The frame includes the request headers with lowercase names and the base64-encoded body. The receiving client reconstructs the request and verifies its signature. The relay reads the EventSub message-type header to identify verification challenges.
Frames the subscriber sends back
Section titled “Frames the subscriber sends back”After replaying a frame locally, the subscriber posts:
{ "type": "dispatch_result", "id": "uuid", "status": 200, "headers": { "content-type": "text/plain; charset=utf-8" }, "body": "<base64-encoded response body>"}For normal notifications, a non-2xx/3xx result closes the subscriber connection. The client can reconnect using its last acknowledged cursor to retry buffered notifications.
When requires_response is true, the relay returns the response to the original HTTP caller. This is required for Twitch EventSub verification challenges.
A Durable Object alarm removes expired notifications even when no new traffic arrives. Verification challenges are not buffered; they require a connected subscriber.
Token validation
Section titled “Token validation”A self-hosted relay can leave token validation unset and accept tokens matching the required pattern.
To check tokens through the hosted cloud service, configure both values:
TOKEN_VALIDATE_URL=https://api.replayvod.com/relay/tokens/validateRELAY_SHARED_SECRET=...The Worker checks ingest and subscribe requests before forwarding them to the Durable Object. Revoked tokens and inactive subscriptions are rejected.
Self-host
Section titled “Self-host”Run from relay/:
npm installnpm run devAfter configuring your Cloudflare account and Worker bindings in wrangler.jsonc, deploy with:
npm run deployUse the deployed Worker’s hostname for both relay URLs in ReplayVOD. Configure token validation if you want to restrict which tokens the Worker accepts.
Usage depends on notification volume, connected clients, and buffered events. Check your Cloudflare account’s usage and billing for the deployed Worker and Durable Objects.
License
Section titled “License”The relay is MIT-licensed. The recorder, dashboard, and supporting code are GPL-3.0.