Contents

Unity Engine

Initial Settings

Double click the supplied unitypackage (see Overview for download) and import all files into your project. Once the import is complete, click the Twitch Menu in the toolbar and then click on edit settings. The Inspector will then show a Twitch Client ID text box, you must enter a valid Client ID in that box for the plugins to function. Navigate to the Developer Console to create a new application or use an existing application’s Client ID.

Unity Plugin Settings image

Experimental Mac Support

Versions after 121523 have experimental support for Mac-based development environments. However, the plugins are not signed for Mac. You must run the following command to prevent the OS from blocking the dylib:

xattr -rd com.apple.quarantine TwitchSDK.unitypackage

Alternatively, you can build your own version of the plugin with your own signature via our GitHub source. See Overview regarding a request for the codebase.

Note that you must use Unity version 2022.3 or greater.

Authentication

Authentication requires you to maintain two GameTask objects of type AuthenticationInfo and AuthState, GameTask<AuthenticationInfo> and GameTask<AuthState>. GetAuthState() can be called at any time to ensure that your user’s auth state is up to date. Generally, we suggest you do this in the start function of your management code.

Prior to first login, you must call Twitch.API.GetAuthenticationInfo(Scopes) with one or more valid TwitchOAuthScope, this will return an object of type GameTask<AuthenticationInfo>.

Once GetAuthState() is called at least once, you can check the status of the authentication via the MaybeResult of the state. If the MaybeResult is not null, you can check its Status such as curAuthState.MaybeResults.Status. Possible status states are AuthStatus.LoggedIn, AuthStatus.LoggedOut, and AuthStatus.WaitingForCode. If the status is WaitingForCode, then your user needs to complete the login flow. To do so, create a UserAuthInfo object via the MaybeResult of Twitch.API.GetAuthenticationInfo(Scopes). If the MaybeResult is not null, then you should be able to launch a browser window with the URI from the UserAuthInfo object.

Application.OpenURL("{UserAuthInfo.uri}")

Note in the example class below, it is expected that you call GetAuthInformation() from some external source, such as a login menu.

List of Scopes

Scope Name Type of Access
TwitchOAuthScope.Bits.Read.Scope View Bits information for a channel.
TwitchOAuthScope.Channel.ManageBroadcast.Scope Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags.
TwitchOAuthScope.Channel.ManagePolls.Scope Manage a channel’s polls.
TwitchOAuthScope.Channel.ManagePredictions.Scope Manage of channel’s Channel Points Predictions
TwitchOAuthScope.Channel.ManageRedemptions.Scope Manage Channel Points custom rewards and their redemptions on a channel.
TwitchOAuthScope.Channel.ReadHypeTrain.Scope View Hype Train information for a channel.
TwitchOAuthScope.Clips.Edit.Scope Manage Clips for a channel.
TwitchOAuthScope.User.ReadSubscriptions.Scope View if an authorized user is subscribed to specific channels.

Note some of these scopes are required for functionality of a given type. Such as Polls requiring the ManagePolls scope. Please refer to Scopes to learn more about which scopes you should select.

Example of an Authentication Manager class

using TwitchSDK;
using TwitchSDK.interop;
public class AuthManager : MonoBehaviour
{
	GameTask<AuthenticationInfo> AuthInfoTask;
	GameTask<AuthState> curAuthState;
	
	void start()
	{
		updateAuthState();
	}
	
	public void UpdateAuthState()
	{
		curAuthState = Twitch.API.GetAuthState();
		if(curAuthState.MaybeResult.Status == AuthStatus.LoggedIn)
		{
			// user is logged in
		}
		if (curAuthState.MaybeResult.Status == AuthStatus.LoggedOut)
		{
			// user is logged out, do something
			// In this example you could also call GetAuthInformation() to retrigger login
		}
		if (curAuthState.MaybeResult.Status == AuthStatus.WaitingForCode)
		{
			// Waiting for code
			var UserAuthInfo = Twitch.API.GetAuthenticationInfo(RequiredScopes).MaybeResult;
			if(UserAuthInfo == null)
			{
				// User is still loading
			}
			// We have reached the state where we can ask the user to login
			Application.OpenURL("{UserAuthInfo.Uri}{UserAuthInfo.UserCode}");
		}
	}

	// Triggered by something external, like a login button on a options menu screen
	public void GetAuthInformation()
	{
	  // Check to see if the user is currently logged in or not.
		if (AuthInfoTask == null)
		{
			// This example uses all scopes, we suggest you only request the scopes you actively need.
			var scopes = TwitchOAuthScope.Bits.Read.Scope + " " + TwitchOAuthScope.Channel.ManageBroadcast.Scope + " " + TwitchOAuthScope.Channel.ManagePolls.Scope + " " + TwitchOAuthScope.Channel.ManagePredictions.Scope + " " + TwitchOAuthScope.Channel.ManageRedemptions.Scope + " " + TwitchOAuthScope.Channel.ReadHypeTrain.Scope + " " + TwitchOAuthScope.Clips.Edit.Scope + " " + TwitchOAuthScope.User.ReadSubscriptions.Scope;
			TwitchOAuthScope tscopes = new TwitchOAuthScope(scopes);
			AuthInfoTask = Twitch.API.GetAuthenticationInfo(tscopes);
		}
	}
}

Polls

When utilizing the poll functionality of the plugins, you must maintain a GameTask of type poll, GameTask<Poll>. You can use that task to determine if a poll has started, is active, or has returned results. To create a new poll, make a new object of type GameTask<Poll> then use the new poll function and pass in a PollDefinition for example:

OurPoll = Twitch.API.NewPoll(new PollDefinition { Title = "some title", Choices = {"a","b","c"}, Duration = someNumber})

Once created, you can use the MaybeResult to check the results.

var PollResult = OurPoll?.MaybeResult;

The resulting variable contains an Info object to check status and choice values, i.e., PollResult.Info.Status and PollResult.Info.Choices. More information can be found in the reference.

Example of a Poll Manager class

using TwitchSDK;
using TwitchSDK.Interop;
public class TwitchPollManager : MonoBehaviour
{
	GameTask<Poll> ActivePoll = null;
	private bool PollHasEnded = false;
	private void Start()
	{
	}
	
	//Called by some external class
	public void StartPoll(string pollTitle, string[] pollChoices)
	{
		// We already polled something, so we don't do anything.
		if (ActivePoll != null)
			return;
		var authStatus = Twitch.API?.GetAuthState().MaybeResult;
		// Not logged in
		if (authStatus?.Status != AuthStatus.LoggedIn)
			return;
		// If we don't have the "Manage Polls" permission, we also give up.
		if (!authStatus.Scopes.Any(a => a == Twitch.TwitchOAuthScope.Channel.ManagePolls.Scope))
			return;
		ActivePoll = Twitch.API.NewPoll(new PollDefinition
		{
			Title = pollTitle,
			Choices = pollChoices,
			Duration = 20, // in seconds
		});
	}
	private void Update()
	{
		if (PollHasEnded)
			return;
		var poll = ActivePoll?.MaybeResult;
		if (poll == null)
			return;
		// This means we have an active poll, and are waiting for it to finish.
		if (poll.Info.Status == PollStatus.Active)
			return;
		// Now we know the poll is finished in some way.
		PollHasEnded = true;
		// This poll was cancelled by someone, so we don't take the results.
		if (poll.Info.Status != PollStatus.Completed)
			return;
		// Now we can tally results and do something
		var votesForChoice1= poll.Info.Choices.Where(a => a.Title == "Yes").Single();
		var votesForChoice2 = poll.Info.Choices.Where(a => a.Title == "No").Single();

		if(votesForChoice1 > votesForChoice2)
			// Do something
		if(votesForChoice2 > votesForChoice1)
			// Do something else
		else // in case they somehow tie
			// Do something else again
	}
}

Predictions

Predictions function much in the same way as polls, only with a limit of two choices for outcomes. To interact with predictions, you must maintain a GameTask of type Prediction, GameTask<Prediction>. You can use that task to determine if a prediction has been started, is active, or has returned results. To create a new prediction, make a new object of type GameTask<Prediction> then use the new prediction function and pass in a PredictionDefinition. For example:

OurPrediction = Twitch.API.NewPoll(new PollDefinition { Title = "some prediction", Outcomes = {"a","b"}, Duration = someNumber)

Once created, you can use the MaybeResult to check the results.

var PredictionResult = OurPrediction?.MaybeResult;

The resulting variable contains a Info object, You can use this to check status, outcomes, and the winning outcome, i.e., PredictionResult.Info.Status, PredictionResult.Info.WinningOutcomeId, PredictionResult.Info.Outcomes.

PredictionResult.Info.Outcomes is a vector containing information about a given outcome, such as number of users and Channel Points used. More information can be found in our reference.

Example of a Predictions Manager class

using TwitchSDK;
using TwitchSDK.Interop;
public class TwitchPredictionManager : MonoBehaviour
{
	GameTask<Prediction> ActivePrediction = null;
	private bool PredictionHasEnded = false;
	private Prediction LocalPrediction = null;

	public void createPrediction(string predictionTitle, string[] predictionChoices)
	{
		// We already polled something, so we don't do anything.
		if (ActivePrediction != null)
			return;
		var authStatus = Twitch.API?.GetAuthState().MaybeResult;
		// Not Logged in
		if (authStatus?.Status != AuthStatus.LoggedIn)
			return;
		// If we don't have the "Manage Predictions" permission, we also give up.
		if (!authStatus.Scopes.Any(a => a == TwitchOAuthScope.Channel.ManagePredictions.Scope))
			return;
		ActivePrediction = Twitch.API.NewPrediction(new PredictionDefinition
		{
			Title = predictionTitle,
			Outcomes = predictionChoices,
			Duration = 20, // in seconds
		});
		// Sets it back to false incase a previous prediction has already ended
		PredictionHasEnded = false;
	}
	
	// Allows you to end a prediction if run is currently running
	public void EndPrediction()
	{
		if (LocalPrediction == null)
		{
			return;
		}
		
		// The resolve command forces one of the outcomes to be selected
		LocalPrediction.Resolve(LocalPrediction.Info.Outcomes[0]);
		Debug.Log("Prediction ended");
	}

	private void Update()
	{
		if (PredictionHasEnded)
			return;
		var prediction = ActivePrediction?.MaybeResult;
		if (prediction == null)
			return;
		// This means we have an active poll, and are waiting for it to finish.
		LocalPrediction = prediction;
		if (prediction.Info.Status == PollStatus.Active)
			return;
		// Now we know the prediction is finished.
		PredictionHasEnded = true;
		// This prediction was cancelled by someone, so we don't take the results.
		if (prediction.Info.Status != PredictionStatus.Completed)
			return;
		// Now we get the winning outcome
		var winningOutcome = prediction.Info.Outcomes.Where(a => a.Id == prediction.Info.WinningOutcomeId);
		// Do something with that			
	}
}

Channel Point Rewards

Channel Point rewards allow you to create dynamic in-game events based on redemptions made by users on a given stream. This is the most open-ended of all supported functions and, as such, any functionality implemented will be highly dependent on your game’s design.

This requires the user to be logged in and have the appropriate manage:redemptions scope.

The example below uses Channel Points to provide a list of colors which could be used in various ways in-game.

Example of a Channel Points Manager class

using TwitchSDK;
using TwitchSDK.Interop;
public class TwitchChannelPointManager : MonoBehaviour
{
	public void SetSampleRewards()
	{
		CustomRewardDefinition ColorRed = new CustomRewardDefinition();
		ColorRed.Title = "Red!";
		ColorRed.Cost = 10;
		CustomRewardDefinition ColorBlue = new CustomRewardDefinition();
		ColorBlue.Title = "Blue!";
		ColorBlue.Cost = 25;
		CustomRewardDefinition ColorOctarine = new CustomRewardDefinition();
		ColorOctarine.Title = "Octarine!";
		ColorOctarine.Cost = 750;

		List<CustomRewardDefinition> cDefinitionList = new List<CustomRewardDefinition>();
		cDefinitionList.Add(ColorRed);
		cDefinitionList.Add(ColorBlue);
		cDefinitionList.Add(ColorOctarine);

		Twitch.API.ReplaceCustomRewards(cDefinitionList.ToArray());
	}

	public void ClearRewards()
	{
		CustomRewardDefinition Cleared = new CustomRewardDefinition();
		Cleared.Title = "";
		Cleared.Cost = 0;
		Cleared.IsEnabled = false;
		Twitch.API.ReplaceCustomRewards(Cleared);
	}
}

Once you have created custom Channel Point rewards, you must subscribe to the associated event as described under Subscribe to Events.

User Info

To retrieve user information, such as Displayname, Viewcount, or UserType, you must maintain a GameTask of type UserInfo, GameTask<UserInfo>. If you wish to retrieve email information, you must request the appropriate scope at authentication.

Example

GameTask<UserInfo> UserInfoTask;
string LoginName;
string BroacasterType;
string DisplayName;
string UserType;
string ViewCount;
	
public void GetUserInformation()
{
    if(UserInfoTask == null)
    {
        UserInfoTask = Twitch.API.GetMyUserInfo();
        if(UserInfoTask?.IsCompleted == true)
        {
            if(UserInfoTask.MaybeResult != null)
            {
                LoginName = "Login Name: " + UserInfoTask.MaybeResult.DisplayName;
                BroacasterType = "Broadcaster Type: " + UserInfoTask.MaybeResult.BroadcasterType;
                DisplayName = "Display Name: " + UserInfoTask.MaybeResult.DisplayName;
                UserType = "User Type: " + UserInfoTask.MaybeResult.UserType;
                ViewCount = "View Count: " + UserInfoTask.MaybeResult.ViewCount;
            }
        }
    }
}

Stream Info

To retrieve stream information, such as ViewerCount, Language, GameName, etc. You must maintain a GameTask of type StreamInfo, GameTask<StreamInfo>.

Example

GameTask<StreamInfo> StreamInfoTask;
string GameName;
bool isMature;
string Language;
string Title;
long ViewerCount;
	
public void GetStreamInformation()
{
    if(StreamInfoTask == null)
    {
        StreamInfoTask = Twitch.API.GetMyStreamInfo();
        if(StreamInfoTask?.IsCompleted == true)
        {
            if(StreamInfoTask.MaybeResult != null)
            {
                GameName = "Game Name: " + StreamInfoTask.MaybeResult.GameName;
                isMature = StreamInfoTask.MaybeResult.IsMature;
                DisplayName = "Language: " + StreamInfoTask.MaybeResult.Language;
                Title = "Title: " + StreamInfoTask.MaybeResult.Title;
                ViewerCount = StreamInfoTask.MaybeResult.ViewerCount;
            }
        }
    }
}

Subscribe to Events

Events such as new followers, subscribers, raids, Hype Trains, etc use a special type of GameTask<EventStream<>>. EventStreams are special in that they also have multiple types.

When working with Events, you have a choice to either use WaitForEvent or TryGetNextEvent. We recommend that you only use one at a time. If you plan on requesting this at regular intervals, such as in Update, we suggest using TryGetNextEvent. If the event has been completed, TryGetNextEvent will return the task via the out parameter.

Channel Point Rewards

GameTask<EventStream<CustomRewardEvent>> CustomRewardEvents;

private void start()
{
  CustomRewardEvents = Twitch.API.SubscribeToCustomRewardEvents();
}

private void update()
{
  CustomRewardEvent CurRewardEvent; 
  CustomRewardEvents.MaybeResult.TryGetNextEvent(out CurRewardEvent);
  if(CurRewardEvent != null)
  {
    // Do something
    Debug.Log("{CurRewardEvent.RedeemerName} has brought {CurRewardEvent.CustomRewardTitle} for {CurRewardEvent.CustomRewardCost}!");
  }
}

Follows

GameTask<EventStream<ChannelFollowEvent>> FollowEvents;

private void start()
{
  FollowEvents = Twitch.API.SubscribeToChannelFollowEvents();
}

private void update()
{
  ChannelFollowEvent CurFollowEvent; 
  FollowEvents.MaybeResult.TryGetNextEvent(out CurFollowEvent);
  if(CurFollowEvent != null)
  {
    // Do something
    Debug.Log("{CurFollowEvent.UserDisplayName} is now following!");
  }
}

Subscribers

GameTask<EventStream<ChannelSubscribeEvent>> ChannelSubscribeEvents;

private void start()
{
  ChannelSubscribeEvents = Twitch.API.SubscribeToChannelSubscribeEvents();
}

private void update()
{
  ChannelSubscribeEvent CurSubscriberEvent; 
  ChannelSubscribeEvents.MaybeResult.TryGetNextEvent(out CurSubscriberEvent);
  if(CurSubscriberEvent != null)
  {
    // Do something
    Debug.Log("{CurSubscriberEvent.UserDisplayName} has Subscribed!");
  }
}

Hype Train

GameTask<EventStream<HypeTrainEvent>> HypeTrainEvents;

private void start()
{
  HypeTrainEvents = Twitch.API.SubscribeToHypeTrainsEvents();
}

private void update()
{
  HypeTrainEvent CurHypeTrainEvent; 
  HypeTrainEvents.MaybeResult.TryGetNextEvent(out CurHypeTrainEvent);
  if(CurHypeTrainEvent != null)
  {
    // Do something
    Debug.Log("The Hypetrain level is {CurHypeTrainEvent.Level}!");
  }
}

Raids

GameTask<EventStream<ChannelRaidEvent>> RaidEvents;

private void start()
{
  RaidEvents = Twitch.API.SubscribeToChannelRaidEvent();
}

private void update()
{
  ChannelRaidEvent CurRaidEvent; 
  RaidEvents.MaybeResult.TryGetNextEvent(out CurRaidEvent);
  if(CurRaidEvent != null)
  {
    // Do something
    Debug.Log("{CurRaidEvent.FromBroadcasterName} has raided with {CurRaidEvent.Viewers} people!");
  }
}