I’m new to development with the Twitch SDK. I currently have a game on Steam and want to implement Twitch integration using the official Twitch API. My first goal is to create a voting system. While I can technically do this using Polls, the problem is that I can’t test it since I’m not a Twitch Partner or Affiliate. I’ve tried using a mock server, but it didn’t give any usable results.
So, I decided to implement the voting system using Twitch chat instead for those who is not Partner of Affiliate, which brings its own challenges. Reading chat seems really painful to implement. Based on what I’ve read here and on Discord, it’s apparently impossible to directly read chat. However, I came across WebSockets and EventSub, which might help.
From what I understand, I would need the user’s OAuth token to connect to chat. This means I can’t use the usual authentication flow (GameTask<AuthenticationInfo> and GameTask<AuthState>) because it doesn’t provide device_code, access_token, or refresh_token.
Instead, I have to manually POST to the appropriate endpoints to obtain that information and handle user authentication myself. However, this approach makes it harder to manage user state (e.g., whether the user is logged in, logged out, or waiting to authorize). One of my main concerns is: How can I reliably detect when the user clicks the “Authorize” button so I can use the device_code to retrieve the access_token?
Here are my main questions:
Is there a more appropriate or standard way to support both Poll-based and Chat-based voting, depending on the streamer’s selected settings?
Did I understand correctly that WebSockets + EventSub can read chat? I tried using NativeWebSocket to connect to wss://eventsub.wss.twitch.tv/ws, and while I get a “Connection established” debug message, I never receive the welcome message. Eventually, it disconnects with an “Undefined” error.
I’ve been trying to figure this out for a long time, and every solution seems to lead to a dead end. I also tried TwitchLib, but ran into issues with authorization. I haven’t yet tried using TwitchLib with the authorization endpoints. I believe that might allow me to retrieve user info and connect to chat as the streamer—meaning I wouldn’t need a separate bot to connect to multiple streams.
Any advice or suggestions on which direction to take would be greatly appreciated. Sorry for the wall of text—I just wanted to clearly explain my situation.
In a “game” scenario the only authentication you have access to is the streamers, otherwise you’d be leaking the credentials to the bot and/or have problems updating the bots credentials
There are two ways to connect to chat:
IRC
Eventsub (regardless of transport type)
You do bind a message reciever before connecting/during connecting?
You should get
session_welcome
and a number of session_keepalive’s before being disconnected
A disconnect should come with a close code which would ID the error, I suspect here it’s just the “connection unused” which is code 4003.
on click I generate the requried outbound URL and start a background poller
Present the link to the user/open the users web browsers
The background poller just ticks periodically using the interval returned when I call https://id.twitch.tv/oauth2/device to get the device_code/verification_uri thats needed to send the user to.
So I know to start polling becuase I did a call to get the devicde_code in the first place.
It seems you think you just call once when the user hits authorize, but you will never know when a user hits authorize, you have to start polling the moment you get the device_code and send the user to twitch.
Thanks for this advice — it worked! I can now safely detect when a user has authorized and retrieve the token. Although, I couldn’t find much info on what happens if the user cancels the authorization, but for now, that’s not a big issue.
I believe I do subscribe to OnMessage and added debug logs to capture any incoming messages, but still receiving nothing. I also tried sending a message to the same URL — the connection closed immediately, which I expected after reading the docs.
So I think the WebSocket is connecting to wss://eventsub.wss.twitch.tv/ws, but I still don’t receive any messages. In my previous post, I mistakenly said it throws an error, but actually it triggers OnClose with an “Undefined” message exactly 10 seconds after connecting — which lines up with Twitch expecting a session to be established within that time.
Here’s the code I’m using (with the NativeWebSocket package for Unity):
Btw, for learning purposes, I like to see how other developers implement certain things. I found some games that have Twitch integration using TwitchLib and a bot that connects to chat and reads messages. In their code, I can clearly see the bot’s access token.
Does that mean I could just revoke that token and break their integration? (I’m not going to do that! Just asking)
that leave the app polling until the 30 minute timeout occurs (or whatever the time limit is at the time of creating the device code flow entry)
That violates the developer agreement and best practices, let along tokens are not forever.
Yes.
Any given person can see the token in the code as you have, abuse said token or flat out revoke it.
Or use the token to get the bot account banned/etc.
It’s also likely these sort of things are using a “public”/“test” clientID like a token generator which isn’t really for production use cases.
They are doing it wrong. Very very wrong.
since i’m not a unity guy I don’t have anything to offer here
basically all your On functions have the incorrect variables. They all should be OnWhatever += (sender, message) where you have OnWhatever += (message)
Well, thank you VERY much — I finally started receiving messages from Twitch chat! Now the only thing left is to polish the code, handle all possible edge cases, and do a lot of testing.
I decided to set the poll timer to 30 seconds with a 2-second interval, and I’ll add a cancel button — so if the user cancels the authorization, they can cancel it in-game or just wait 30 seconds. I think that should do the trick.
I have read that On actions should have a sender property, but the package I’m using doesn’t include one. What helped me was calling DispatchMessageQueue() inside Update(). After that, I finally started receiving messages.