braket.gg
EN

Twitch integration

Braket integrates with Twitch so that players and casters can link their channel, viewers can be alerted when followed players go live, and live matches surface a "watch now" link. The integration is deliberately read-only: Braket verifies channel identity and polls live status; it never re-streams or takes broadcast control. This chapter covers the single network-wide Twitch app, the one OAuth redirect URL you register, the environment configuration, the scope, Helix live-status polling, follows and alerts, and the caster directory. It is accurate to src/twitch/index.ts and src/web/routes/twitch.ts.

One network-wide Twitch app

There is a single Twitch application for the entire Braket network, not one per arena. Every arena's linking and live-status checks go through the same app credentials. This is why there is only one redirect URL to register and one pair of credentials to configure at the platform level.

The single OAuth redirect URL

Register exactly one OAuth redirect URL in the Braket Twitch app:

https://braket.gg/twitch/callback

This is derived from the platform domain (https://<platform-domain>/twitch/callback, where the platform domain defaults to braket.gg). Because linking must work for every arena but Twitch only allows a fixed set of redirect URIs, Braket routes all link flows through this one centralized callback: when a player starts linking, the server stashes a random state mapped to (tenant, user), redirects the player to Twitch, and when Twitch calls back to https://braket.gg/twitch/callback, Braket looks up the state to reattach the verified channel to the right player in the right arena.

Environment configuration

Real-mode Twitch needs Helix app credentials:

Variable Meaning
TWITCH_CLIENT_ID The Braket Twitch app's client id
TWITCH_CLIENT_SECRET The Braket Twitch app's client secret

When both are set, the real Twitch service runs. When either is missing, Braket runs the mock twin: linking asserts a login directly with no external call, and live status is an in-memory set (tests and dev flip it directly). This mirrors the mock-first approach used for Steam, so you can develop the whole feature with no Twitch account.

Read-only scope

The OAuth authorize request uses an empty scope: identity only, no permissions. Braket only needs to learn the channel login name, so it requests no re-streaming, chat, or channel-management scopes. The authorize URL is:

https://id.twitch.tv/oauth2/authorize?client_id=…&redirect_uri=https://braket.gg/twitch/callback&response_type=code&scope=&state=…

The code is exchanged at https://id.twitch.tv/oauth2/token (authorization-code grant), and the resulting token is used once against https://api.twitch.tv/helix/users to read the login, which is lowercased and stored on the player's users.twitchLogin. Nothing else about the channel is read or retained.

Linking flow

Helix live-status polling

Live status comes from Helix GET /helix/streams, using an app access token obtained via the client-credentials grant (cached until shortly before expiry). Braket batches lookups (Helix allows up to 100 logins per query) and returns the subset of the requested logins that are currently live.

To avoid hammering Helix on page renders, results are cached per tenant for 60 seconds (cachedLiveLogins). A failed Helix call degrades gracefully to "no one live" rather than erroring the page. So live badges across an arena reflect Twitch state with at most a 60-second lag.

Streamer follows and alerts

Players can follow a tournament or a player to be alerted around matches and when a followed player goes live. Follows are stored in the follows table (kind is tournament or player, plus a targetId), one row per user/kind/target.

Alerts are driven from these follows: upcoming-match notifications (stamped on the match as upcomingAlertAt so the sweep never double-fires), live alerts, and "a player you follow is streaming" alerts fed by the Helix live-status poll.

Match POV streams and the caster directory

There are two distinct streaming concepts:

Together, linked channels, live status, follows, and match streams populate a caster directory: which channels are casting which matches, who is live, and where to watch, all within an arena. Because the integration is identity-plus-live-status only, nothing here gives Braket control over anyone's broadcast.