Twitchat offers a websocket API through OBS-Websocket to control some features and receive some events.
This API needs OBS-Websocket V5 to be installed and running!
After installing OBS-Websocket, start OBS, you may want set a password on Tools -> obs-websocket Settings.
Once done, go on Twitchat, open the parameters and on the OBS panel specify the credentials to connect with OBS.
OBS will act as a bridge to transmit Twitchat messages to any connected client.
To connect with OBS-Websocket you can use the obs-websocket-js package that already handles everything.
Bellow is a typescript example to use the API via OBS-Websocket-js.
The example refers to TwitchatActionType and TwitchatEventType.
You can find their signatures here.
import OBSWebSocket from 'obs-websocket-js';
const port:number = 4455;//Configure this
const pass:string "";//Configure this
const obs = new OBSWebSocket();
/**
* Connect to OBS-websocket
*/
async function connect(port:string, pass:string):Promise<boolean> {
try {
await obs.connect("ws://127.0.0.1:"+port, pass, {rpcVersion:1});
}catch(error) {
setTimeout(()=> {
//try again later
connect(port, pass);
}, 5000);
return false;
}
obs.addListener("ConnectionClosed", ()=> {
//Reconnect
connect(port, pass);
});
//@ts-ignore ("CustomEvent" not yet declared in obs-websocket-js types. Need ts-ignore to avoid compilation error)
obs.on("CustomEvent", (e:{origin:"twitchat", type:TwitchatEventType, data:unknown}) => onTwitchatEvent(e))
return true;
}
/**
* Send a message to Twitchat
*/
function sendMessage(type:TwitchatActionType, data:unknown):Promise<void> {
const eventData = { origin:"twitchat", type, data };
obs.call("BroadcastCustomEvent", {eventData});
}
/**
* Called when receiving a message from Twitchat
*/
function onTwitchatEvent(e:{origin:"twitchat", type:TwitchatEventType, data:unknown}):void {
if(e.type == undefined) return;
//Ignore any message not coming from twitchat
if(e.origin != "twitchat") return;
console.log(`Twitchat event ${e.type} received !`);
console.log(e.data);//JSON data of the event
//Example
if(e.type == "MESSAGE_NON_FOLLOWER") {
console.log(`The user ${e.data.tags.username} is not following the channel and sent this message : ${e.data.message}`)
}
}
connect().then(()=> {
//Marks 1 message as read in the "Greet them section"
sendMessage("GREET_FEED_READ", {count:1});
});Here are the types signatures used on the above examples
//Events fired by Twitchat
export type TwitchatEventType =
"MESSAGE_READ"
| "MESSAGE_NON_FOLLOWER"
| "MESSAGE_FILTERED"
| "MESSAGE_DELETED"
| "MESSAGE_FIRST"
| "MESSAGE_FIRST_ALL_TIME"
| "MESSAGE_WHISPER"
| "FOLLOW"
| "POLL_END"
| "PREDICTION_END"
| "MENTION"
| "CURRENT_TRACK"
| "TRACK_ADDED_TO_QUEUE"
| "RAFFLE_COMPLETE"
| "COUNTDOWN_COMPLETE"
| "COUNTDOWN_START"
| "TIMER_START"
| "TIMER_STOP"
| "TIMER_OVERLAY_PRESENCE"
| "WHEEL_OVERLAY_PRESENCE"
| "EMERGENCY_MODE"
| "CHAT_HIGHLIGHT_OVERLAY_PRESENCE"
//Actions you can request to Twitchat
export type TwitchatActionType =
"GREET_FEED_READ"
| "GREET_FEED_READ_ALL"
| "CHAT_FEED_READ"
| "CHAT_FEED_READ_ALL"
| "CHAT_FEED_PAUSE"
| "CHAT_FEED_UNPAUSE"
| "CHAT_FEED_SCROLL_UP"
| "CHAT_FEED_SCROLL_DOWN"
| "POLL_TOGGLE"
| "PREDICTION_TOGGLE"
| "BINGO_TOGGLE"
| "RAFFLE_TOGGLE"
| "ACTIVITY_FEED_TOGGLE"
| "VIEWERS_COUNT_TOGGLE"
| "MOD_TOOLS_TOGGLE"
| "CENSOR_DELETED_MESSAGES_TOGGLE"
| "GET_CURRENT_TRACK"
| "WHEEL_OVERLAY_START"
| "GET_WHEEL_OVERLAY_PRESENCE"
| "GET_CURRENT_TIMERS"
| "GET_TIMER_OVERLAY_PRESENCE"
| "SET_EMERGENCY_MODE"
| "GET_CHAT_HIGHLIGHT_OVERLAY_PRESENCE"
| "SET_CHAT_HIGHLIGHT_OVERLAY_MESSAGE"
| "SHOW_CLIP"
| "START_EMERGENCY"
| "STOP_EMERGENCY"
| "SHOUTOUT"List of the events fired by Twitchat you can listen to and the JSON data sent in parameters.
Sent when clicking a message on the chat to mark it as read
{
channel:string,
message:string,
tags:any,//IRC tags data
}Sent when a non-follower sends a message
{
channel:string,
message:string,
tags:any,//IRC tags data
}Sent when a message is filtered out. If you don't want commands to be displayed on the chat, anytime a command is sent this event will be fired.
{
channel:string,
message:string,
tags:any,//IRC tags data
}Sent when a message is deleted.
{
channel:string,
message:string,
tags:any,//IRC tags data
}Sent when a user sends her/his first message of the stream ("Greet them" section).
{
channel:string,
message:string,
tags:any,//IRC tags data
}Sent when a user sends her/his first message on the channel.
{
channel:string,
message:string,
tags:any,//IRC tags data
}The actual message received isn't sent for privacy reasons.
{
unreadCount:number,//Number of unread whispers
user:{
id: string,
login: string,
color: string,
badges: any,//IRC parsed badges infos
'display-name': string,
'message-id': string,
},
}Sent when a user follows the channel
{
display_name: string,
username: string,
user_id: string,
}Sent when a poll starts, updates (when someone votes) and ends.
{
id: string,
broadcaster_id: string,
broadcaster_name: string,
broadcaster_login: string,
title: string,
choices: {
id: string,
title: string,
votes: number,
channel_points_votes: number,
bits_votes: number,
},
bits_voting_enabled: boolean,
bits_per_vote: number,
channel_points_voting_enabled: boolean,
channel_points_per_vote: number,
status: "ACTIVE" | "COMPLETED" | "TERMINATED" | "ARCHIVED" | "MODERATED" | "INVALID",
duration: number,
started_at: string,
ended_at: string | undefined,
};Sent when a prediction starts, updates (when someone votes) and ends.
{
id: string,
broadcaster_id: string,
broadcaster_name: string,
broadcaster_login: string,
title: string,
outcomes: {
id: string,
title: string,
users: number,
channel_points: number,
color:string,
top_predictors:{
id:string,
name:string,
login:string,
channel_points_used:number,
channel_points_won:number | undefined,
},
},
prediction_window: number,
status: "ACTIVE" | "RESOLVED" | "CANCELED" | "LOCKED",
created_at: string,
ended_at: string | undefined,
locked_at: string | undefined,
}Called when a message contains a mention of your nickname
{
display_name: string,
username: string,
user_id: string,
}Sent when a new track is playing on spotify or when playback is stopped
{
trackName:string,
artistName:string,
trackDuration:number,
trackPlaybackPos:number,
cover:string,
}Sent when a new track is added to the queue\
{
title:string,
artist:string,
album:string,
cover:string,
duration:number,
}Sent when a raffle completes
{
winner:{
id:string;
label:string;
//Data when doing a chat raffle
data:{
user:Object;//IRC user data
score:number;//Ponderation score if any
};
//Data when doing a raffle amongst our subs
data:{
broadcaster_id: string;
broadcaster_login: string;
broadcaster_name: string;
gifter_id: string;
gifter_login: string;
gifter_name: string;
is_gift: boolean;
tier: string;
plan_name: string;
user_id: string;
user_name: string;
user_login: string;
};
},
}Sent when a countdown start
{
startAt:number,//Timestamp in ms
duration:number,//Duration in ms
}Sent when a countdown completes
{
startAt:number,//Timestamp in ms
duration:number,//Duration in ms
}Sent when a timer is started
{
startAt:number,//Timestamp in ms
}Sent when stoping a timer
{
startAt:number,//Timestamp in ms
stopAt:number,//Timestamp in ms
}Sent when a timer overlay advertises its presence
-none-Sent when a wheel overlay advertises its presence
-none-Sent when the emergency mode is started or stopped
{
enabled:boolean
}Sent when a chat highlight overlay advertises its presence
{
enabled:boolean
}List of actions you can request Twitchat to perform.\
Marks "count" messages as read in the "Greet them" section.
Default value = 1
{
"count": number,
}Marks all the messages as read in the "Greet them" section
-none-
Marks "count" messages as read in the chat feed.
count value can be negative to move the read mark back.
Default value = 1
{
"count": number,
}Marks all the messages as read in the chat feed.
-none-
Pauses the chat
-none-
Resumes the chat by scrolling back to bottom
-none-
Scroll the chat feed up by the number of pixels specified in the scrollBy value.
Default value = 100
{
"scrollBy":number
}Scroll the chat feed down by the number of pixels specified in the scrollBy value.
Default value = 100
{
"scrollBy":number
}Toggle current poll's visibility
-none-Toggle current prediction's visibility
-none-Toggle current bingo's visibility
-none-Toggle current raffle's visibility
-none-Toggle activity feed's visibility
-none-Toggle viewer count's visibility
-none-Toggle moderation tools' visibility
-none-Toggle the censorship of the deleted messages
If censorship is enabled, deleted messages content is replaced by <deleted message>.
-none-Request the currently playing spotify track\
-none-Start a wheel animation.
items contains the list of wheel items to display on the wheel. There must be between 1 and an infinity of items.
winner param is the entry of the list the wheel should stop to.
{
items:[
{
id:string;
label:string;
data:winner;
},
//...
],
winner: {
id:string;
label:string;
data:winner;
},
}Ask of a wheel overlay exists.
If it does you'll receive the WHEEL_OVERLAY_PRESENCE event.
-none-Request current timer / countdown values
If it does you'll receive the TIMER_START nor COUNTDOWN_START event.
-none-Ask if a timer overlay exists.
If it does you'll receive the TIMER_OVERLAY_PRESENCE event.
-none-Starts or stops the emergency mode. If not JSON is given it will simply toggle the current state
{
enabled:boolean
}Ask if a chat highlight overlay exists.
If it does you'll receive the CHAT_HIGHLIGHT_OVERLAY_PRESENCE event.
-none-Send a chat message on the "chat highlight" overlay Send no data to hide the current message
{
message: string;//Message with emotes parsed as HTML tags
user:{
id: string;
login: string;
display_name: string;
type: string;
broadcaster_type: string;
description: string;
profile_image_url: string;
offline_image_url: string;
created_at: string;
},
params:{
position:"tl"|"t"|"tr"|"l"|"m"|"r"|"bl"|"b"|"br";
}
}Send a clip to be displayed on the chat highlight overlay
{
//This is the same JSON as the one sent by the Twitch API
clip:{
broadcaster_id: string;
broadcaster_name: string;
created_at: string;
creator_id: string;
creator_name: string;
duration: number;
embed_url: string;
game_id: string;
id: string;
language: string;
thumbnail_url: string;
title: string;
url: string;
video_id: string;
view_count: number;
},
params:{
position:"tl"|"t"|"tr"|"l"|"m"|"r"|"bl"|"b"|"br";
}
}Starts the emergency mode as the user clicked the emergency button
-none-Stop the emergency mode
-none-Sends a shoutout to the latest raider
-none-