Skip to content

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.

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 must match [a-zA-Z0-9_-]{16,128}. Each token identifies one Durable Object. Multiple clients can subscribe with the same token.

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.

GET /u/{token}/subscribe?cursor={last_cursor}
Upgrade: websocket

On connection, the relay replays buffered notifications with a cursor greater than the supplied value, then sends new notifications. Cursors increase with each stored event.

{
"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.

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.

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/validate
RELAY_SHARED_SECRET=...

The Worker checks ingest and subscribe requests before forwarding them to the Durable Object. Revoked tokens and inactive subscriptions are rejected.

Run from relay/:

Terminal window
npm install
npm run dev

After configuring your Cloudflare account and Worker bindings in wrangler.jsonc, deploy with:

Terminal window
npm run deploy

Use 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.

The relay is MIT-licensed. The recorder, dashboard, and supporting code are GPL-3.0.