Twitch Chat Bot#

A simple twitch chat bot.

Chat bots can join channels, listen to chat and reply to messages, commands, subscriptions and many more.

Commands#

Chat commands are specific messages user can send in chat in order to trigger some action of your bot.

Example:

<User123>: !say Hello world
<MyBot>: User123 asked me to say "Hello world"

You can register listeners to chat commands using register_command().

The bot prefix can be set by using set_prefix(), the default is !

Your command listener function needs to be async and take in one parameter of type ChatCommand.

Example:

async def say_command_handler(cmd: ChatCommand):
    await cmd.reply(f'{cmd.user.name} asked me to say "{cmd.parameter}")

chat.register_command('say', say_command_handler)

Command Middleware#

Command Middleware is a way to control when a command should be executed.

See Chat Command Middleware and Chat - Introduction to Middleware for more information.

Events#

You can listen to different events happening in the chat rooms you joined.

Generally you register a event listener using register_event(). The first parameter has to be of type ChatEvent and the second one is your listener function.

Those Listeners always have to be async functions taking in one parameter (the payload). The Payload type is described below.

Example:

async def on_ready(cmd: EventData):
    await cmd.chat.join_room('teekeks42')

chat.register_event(ChatEvent.READY, on_ready)

Available Events#

Event Name

Event Data

Description

Bot Ready

ChatEvent: READY
Payload: EventData

This Event is triggered when the bot is started up and ready to join channels.

Message Send

ChatEvent: MESSAGE
Payload: ChatMessage

This Event is triggered when someone wrote a message in a channel we joined

Channel Subscription

ChatEvent: SUB
Payload: ChatSub

This Event is triggered when someone subscribed to a channel we joined.

Raid

ChatEvent: RAID
Payload: dict

Triggered when a channel gets raided

Channel Config Changed

ChatEvent: ROOM_STATE_CHANGE
Payload: RoomStateChangeEvent

Triggered when a channel is changed (e.g. sub only mode was enabled)

User Channel Join

ChatEvent: JOIN
Payload: JoinEvent

Triggered when someone other than the bot joins a channel.
This will not always trigger, depending on channel size

User Channel Leave

ChatEvent: USER_LEFT
Payload: LeftEvent

Triggered when someone other than the bot leaves a channel.
This will not always trigger, depending on channel size

Bot Channel Join

ChatEvent: JOINED
Payload: JoinedEvent

Triggered when the bot joins a channel

Bot Channel Leave

ChatEvent: LEFT
Payload: LeftEvent

Triggered when the bot left a channel

Message Delete

ChatEvent: MESSAGE_DELETE
Payload: MessageDeletedEvent

Triggered when a single message in a channel got deleted

User Messages Cleared

ChatEvent: CHAT_CLEARED
Payload: ClearChatEvent

Triggered when a user was banned, timed out and/or all messaged from a user where deleted

Bot Reveives Whisper Message

ChatEvent: WHISPER
Payload: WhisperEvent

Triggered when someone whispers to your bot.
You need the WHISPERS_READ Auth Scope to receive this Event.

Server Notice

ChatEvent: NOTICE
Payload: NoticeEvent

Triggered when server sends a notice message.

Code example#

from twitchAPI.twitch import Twitch
from twitchAPI.oauth import UserAuthenticator
from twitchAPI.type import AuthScope, ChatEvent
from twitchAPI.chat import Chat, EventData, ChatMessage, ChatSub, ChatCommand
import asyncio

APP_ID = 'my_app_id'
APP_SECRET = 'my_app_secret'
USER_SCOPE = [AuthScope.CHAT_READ, AuthScope.CHAT_EDIT]
TARGET_CHANNEL = 'teekeks42'


# this will be called when the event READY is triggered, which will be on bot start
async def on_ready(ready_event: EventData):
    print('Bot is ready for work, joining channels')
    # join our target channel, if you want to join multiple, either call join for each individually
    # or even better pass a list of channels as the argument
    await ready_event.chat.join_room(TARGET_CHANNEL)
    # you can do other bot initialization things in here


# this will be called whenever a message in a channel was send by either the bot OR another user
async def on_message(msg: ChatMessage):
    print(f'in {msg.room.name}, {msg.user.name} said: {msg.text}')


# this will be called whenever someone subscribes to a channel
async def on_sub(sub: ChatSub):
    print(f'New subscription in {sub.room.name}:\n'
          f'  Type: {sub.sub_plan}\n'
          f'  Message: {sub.sub_message}')


# this will be called whenever the !reply command is issued
async def test_command(cmd: ChatCommand):
    if len(cmd.parameter) == 0:
        await cmd.reply('you did not tell me what to reply with')
    else:
        await cmd.reply(f'{cmd.user.name}: {cmd.parameter}')


# this is where we set up the bot
async def run():
    # set up twitch api instance and add user authentication with some scopes
    twitch = await Twitch(APP_ID, APP_SECRET)
    auth = UserAuthenticator(twitch, USER_SCOPE)
    token, refresh_token = await auth.authenticate()
    await twitch.set_user_authentication(token, USER_SCOPE, refresh_token)

    # create chat instance
    chat = await Chat(twitch)

    # register the handlers for the events you want

    # listen to when the bot is done starting up and ready to join channels
    chat.register_event(ChatEvent.READY, on_ready)
    # listen to chat messages
    chat.register_event(ChatEvent.MESSAGE, on_message)
    # listen to channel subscriptions
    chat.register_event(ChatEvent.SUB, on_sub)
    # there are more events, you can view them all in this documentation

    # you can directly register commands and their handlers, this will register the !reply command
    chat.register_command('reply', test_command)


    # we are done with our setup, lets start this bot up!
    chat.start()

    # lets run till we press enter in the console
    try:
        input('press ENTER to stop\n')
    finally:
        # now we can close the chat bot and the twitch api client
        chat.stop()
        await twitch.close()


# lets run our setup
asyncio.run(run())

Class Documentation#

class twitchAPI.chat.Chat#

Bases: object

The chat bot instance

__init__(twitch, connection_url=None, is_verified_bot=False, initial_channel=None, callback_loop=None, no_message_reset_time=10)#
Parameters:
  • twitch (Twitch) – A Authenticated twitch instance

  • connection_url (Optional[str]) – alternative connection url

    Default:None

  • is_verified_bot (bool) – set to true if your bot is verified by twitch

    Default:False

  • initial_channel (Optional[List[str]]) – List of channel which should be automatically joined on startup

    Default: None

  • callback_loop (Optional[AbstractEventLoop]) –

    The asyncio eventloop to be used for callbacks.

    Set this if you or a library you use cares about which asyncio event loop is running the callbacks. Defaults to the one used by Chat.

  • no_message_reset_time (Optional[float]) – How many minutes of mo messages from Twitch before the connection is considered dead. Twitch sends a PING just under every 5 minutes and the bot must respond to them for Twitch to keep the connection active. At 10 minutes we’ve definitely missed at least one PING

    Default:10

logger: Logger#

The logger used for Chat related log messages

twitch: Twitch#

The twitch instance being used

connection_url: str#

Alternative connection url

Default:None

ping_frequency: int#

Frequency in seconds for sending ping messages. This should usually not be changed.

ping_jitter: int#

Jitter in seconds for ping messages. This should usually not be changed.

listen_confirm_timeout: int#

Time in second that any listen_ should wait for its subscription to be completed.

reconnect_delay_steps: List[int]#

Time in seconds between reconnect attempts

log_no_registered_command_handler: bool#

Controls if instances of commands being issued in chat where no handler exists should be logged.

Default:True

room_cache: Dict[str, ChatRoom]#

internal cache of all chat rooms the bot is currently in

join_timeout: int#

Time in seconds till a channel join attempt times out

default_command_execution_blocked_handler: Optional[Callable[[ChatCommand], Awaitable[None]]]#

The default handler to be called should a command execution be blocked by a middleware that has no specific handler set.

start()#
Return type:

None

Start the Chat Client

Raises:

RuntimeError – if already started

stop()#
Return type:

None

Stop the Chat Client

Raises:

RuntimeError – if the client is not running

set_prefix(prefix)#

Sets a command prefix.

The default prefix is !, the prefix can not start with / or .

Parameters:

prefix (str) – the new prefix to use for command parsing

Raises:

ValueError – when the given prefix is None or starts with / or .

set_channel_prefix(prefix, channel)#

Sets a command prefix for the given channel or channels

The default channel prefix is either ! or the one set by set_prefix(), the prefix can not start with / or .

Parameters:
Raises:

ValueError – when the given prefix is None or starts with / or .

reset_channel_prefix(channel)#

Resets the custom command prefix set by set_channel_prefix() back to the global one.

Parameters:

channel (Union[str, ChatRoom, List[Union[str, ChatRoom]]]) – The channel or channels you want to reset the channel command prefix for

register_command(name, handler, command_middleware=None)#

Register a command

Parameters:
Raises:

ValueError – if handler is not a coroutine

Return type:

bool

unregister_command(name)#

Unregister a already registered command.

Parameters:

name (str) – the name of the command to unregister

Return type:

bool

Returns:

True if the command was unregistered, otherwise false

register_event(event, handler)#

Register a event handler

Parameters:
Raises:

ValueError – if handler is not a coroutine

unregister_event(event, handler)#

Unregister a handler from a event

Parameters:
Return type:

bool

Returns:

Returns true when the handler was removed from the event, otherwise false

is_connected()#
Return type:

bool

Returns your current connection status.

is_ready()#
Return type:

bool

Returns True if the chat bot is ready to join channels and/or receive events

is_mod(room)#

Check if chat bot is a mod in a channel

Parameters:

room (Union[str, ChatRoom]) – The chat room you want to check if bot is a mod in. This can either be a instance of ChatRoom or a string with the room name (either with leading # or without)

Return type:

bool

Returns:

Returns True if chat bot is a mod

is_subscriber(room)#

Check if chat bot is a subscriber in a channel

Parameters:

room (Union[str, ChatRoom]) – The chat room you want to check if bot is a subscriber in. This can either be a instance of ChatRoom or a string with the room name (either with leading # or without)

Return type:

bool

Returns:

Returns True if chat bot is a subscriber

is_in_room(room)#

Check if the bot is currently in the given chat room

Parameters:

room (Union[str, ChatRoom]) – The chat room you want to check This can either be a instance of ChatRoom or a string with the room name (either with leading # or without)

Return type:

bool

async join_room(chat_rooms)#

join one or more chat rooms

Will only exit once all given chat rooms where successfully joined or twitchAPI.chat.Chat.join_timeout run out.

Parameters:

chat_rooms (Union[List[str], str]) – the Room or rooms you want to join

Returns:

list of channels that could not be joined

async send_raw_irc_message(message)#

Send a raw IRC message

Parameters:

message (str) – the message to send

Raises:

ValueError – if bot is not ready

async send_message(room, text)#

Send a message to the given channel

Please note that you first need to join a channel before you can send a message to it.

Parameters:
  • room (Union[str, ChatRoom]) – The chat room you want to send the message to. This can either be a instance of ChatRoom or a string with the room name (either with leading # or without)

  • text (str) – The text you want to send

Raises:
async leave_room(chat_rooms)#

leave one or more chat rooms

Will only exit once all given chat rooms where successfully left

Parameters:

chat_rooms (Union[List[str], str]) – The room or rooms you want to leave

register_command_middleware(mid)#

Adds the given command middleware as a general middleware

unregister_command_middleware(mid)#

Removes the given command middleware from the general list

class twitchAPI.chat.ChatUser#

Bases: object

Represents a user in a chat channel

__init__(chat, parsed, name_override=None)#
chat: Chat#

The twitchAPI.chat.Chat instance

name: str#

The name of the user

badge_info#

All infos related to the badges of the user

badges#

The badges of the user

color: str#

The color of the chat user if set

display_name: str#

The display name, should usually be the same as name

mod: bool#

if the user is a mod in chat channel

subscriber: bool#

if the user is a subscriber to the channel

turbo: bool#

Indicates whether the user has site-wide commercial free mode enabled

id: str#

The ID of the user

user_type: str#

The type of user

vip: bool#

if the chatter is a channel VIP

class twitchAPI.chat.EventData#

Bases: object

Represents a basic chat event

__init__(chat)#
chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.ChatMessage#

Bases: EventData

Represents a chat message

__init__(chat, parsed)#
text: str#

The message

is_me: bool#

Flag indicating if the message used the /me command

bits: int#

The amount of Bits the user cheered

sent_timestamp: int#

the unix timestamp of when the message was sent

reply_parent_msg_id: Optional[str]#

An ID that uniquely identifies the parent message that this message is replying to.

reply_parent_user_id: Optional[str]#

An ID that identifies the sender of the parent message.

reply_parent_user_login: Optional[str]#

The login name of the sender of the parent message.

reply_parent_display_name: Optional[str]#

The display name of the sender of the parent message.

reply_parent_msg_body: Optional[str]#

The text of the parent message

reply_thread_parent_msg_id: Optional[str]#

An ID that uniquely identifies the top-level parent message of the reply thread that this message is replying to. Is None if this message is not a reply.

reply_thread_parent_user_login: Optional[str]#

The login name of the sender of the top-level parent message. Is None if this message is not a reply.

emotes#

The emotes used in the message

id: str#

the ID of the message

hype_chat: Optional[HypeChat]#

Hype Chat related data, is None if the message was not a hype chat

property room: ChatRoom | None#

The channel the message was issued in

property user: ChatUser#

The user that issued the message

async reply(text)#

Reply to this message

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.ChatCommand#

Bases: ChatMessage

Represents a command

__init__(chat, parsed)#
name: str#

the name of the command

parameter: str#

the parameter given to the command

async send(message)#

Sends a message to the channel the command was issued in

Parameters:

message (str) – the message you want to send

async reply(text)#

Reply to this message

property room: ChatRoom | None#

The channel the message was issued in

property user: ChatUser#

The user that issued the message

chat: Chat#

The twitchAPI.chat.Chat instance

text: str#

The message

is_me: bool#

Flag indicating if the message used the /me command

bits: int#

The amount of Bits the user cheered

sent_timestamp: int#

the unix timestamp of when the message was sent

reply_parent_msg_id: Optional[str]#

An ID that uniquely identifies the parent message that this message is replying to.

reply_parent_user_id: Optional[str]#

An ID that identifies the sender of the parent message.

reply_parent_user_login: Optional[str]#

The login name of the sender of the parent message.

reply_parent_display_name: Optional[str]#

The display name of the sender of the parent message.

reply_parent_msg_body: Optional[str]#

The text of the parent message

reply_thread_parent_msg_id: Optional[str]#

An ID that uniquely identifies the top-level parent message of the reply thread that this message is replying to. Is None if this message is not a reply.

reply_thread_parent_user_login: Optional[str]#

The login name of the sender of the top-level parent message. Is None if this message is not a reply.

id: str#

the ID of the message

hype_chat: Optional[HypeChat]#

Hype Chat related data, is None if the message was not a hype chat

emotes#

The emotes used in the message

class twitchAPI.chat.ChatSub#

Bases: object

Represents a sub to a channel

__init__(chat, parsed)#
chat: Chat#

The twitchAPI.chat.Chat instance

sub_type: str#

The type of sub given

sub_message: str#

The message that was sent together with the sub

sub_plan: str#

the ID of the subscription plan that was used

sub_plan_name: str#

the name of the subscription plan that was used

system_message: str#

the system message that was generated for this sub

property room: ChatRoom | None#

The room this sub was issued in

class twitchAPI.chat.ChatRoom#

Bases: object

ChatRoom(name: str, is_emote_only: bool, is_subs_only: bool, is_followers_only: bool, is_unique_only: bool, follower_only_delay: int, room_id: str, slow: int)

name: str#
is_emote_only: bool#
is_subs_only: bool#
is_followers_only: bool#
is_unique_only: bool#
follower_only_delay: int#
room_id: str#
slow: int#
__init__(name, is_emote_only, is_subs_only, is_followers_only, is_unique_only, follower_only_delay, room_id, slow)#
enum twitchAPI.chat.ChatEvent(value)#

Bases: Enum

Represents the possible events to listen for using register_event()

Valid values are as follows:

READY = <ChatEvent.READY: 'ready'>#
MESSAGE = <ChatEvent.MESSAGE: 'message'>#
SUB = <ChatEvent.SUB: 'sub'>#
RAID = <ChatEvent.RAID: 'raid'>#
ROOM_STATE_CHANGE = <ChatEvent.ROOM_STATE_CHANGE: 'room_state_change'>#
JOIN = <ChatEvent.JOIN: 'join'>#
JOINED = <ChatEvent.JOINED: 'joined'>#
LEFT = <ChatEvent.LEFT: 'left'>#
USER_LEFT = <ChatEvent.USER_LEFT: 'user_left'>#
MESSAGE_DELETE = <ChatEvent.MESSAGE_DELETE: 'message_delete'>#
CHAT_CLEARED = <ChatEvent.CHAT_CLEARED: 'chat_cleared'>#
WHISPER = <ChatEvent.WHISPER: 'whisper'>#
NOTICE = <ChatEvent.NOTICE: 'notice'>#
class twitchAPI.chat.RoomStateChangeEvent#

Bases: EventData

Triggered when a room state changed

__init__(chat, prev, new)#
old: Optional[ChatRoom]#

The State of the room from before the change, might be Null if not in cache

new: ChatRoom#

The new room state

property room: ChatRoom | None#

Returns the Room from cache

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.JoinEvent#

Bases: EventData

__init__(chat, channel_name, user_name)#
user_name: str#

The name of the user that joined

property room: ChatRoom | None#

The room the user joined to

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.JoinedEvent#

Bases: EventData

__init__(chat, channel_name, user_name)#
room_name: str#

the name of the room the bot joined to

user_name: str#

the name of the bot

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.LeftEvent#

Bases: EventData

When the bot or a user left a room

__init__(chat, channel_name, room, user)#
room_name: str#

the name of the channel the bot left

user_name: str#

The name of the user that left the chat

cached_room: Optional[ChatRoom]#

the cached room state, might bo Null

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.ClearChatEvent#

Bases: EventData

__init__(chat, parsed)#
room_name: str#

The name of the chat room the event happend in

room_id: str#

The ID of the chat room the event happend in

user_name: str#

The name of the user whos messages got cleared

duration: Optional[int]#

duration of the timeout in seconds. None if user was not timed out

banned_user_id: Optional[str]#

The ID of the user who got banned or timed out. if duration is None, the user was banned. Will be None when the user was not banned nor timed out.

sent_timestamp: int#

The timestamp the event happend at

property room: ChatRoom | None#

The room this event was issued in. None on cache miss.

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.WhisperEvent#

Bases: EventData

__init__(chat, parsed)#
message: str#

The message that was send

property user: ChatUser#

The user that DMed your bot

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.MessageDeletedEvent#

Bases: EventData

__init__(chat, parsed)#
message: str#

The content of the message that got deleted

user_name: str#

Username of the message author

message_id: str#

ID of the message that got deleted

sent_timestamp: int#

The timestamp the deleted message was send

property room: ChatRoom | None#

The room the message was deleted in

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.NoticeEvent#

Bases: EventData

Represents a server notice

__init__(chat, parsed)#
msg_id: str#

Message ID of the notice, Msg-id reference

message: str#

Description for the msg_id

property room: ChatRoom | None#

The room this notice is from

chat: Chat#

The twitchAPI.chat.Chat instance

class twitchAPI.chat.HypeChat#

Bases: object

__init__(parsed)#
amount: int#

The value of the Hype Chat sent by the user.

currency: str#

The ISO 4217 alphabetic currency code the user has sent the Hype Chat in.

exponent: int#

Indicates how many decimal points this currency represents partial amounts in. Decimal points start from the right side of the value defined in amount

level: str#

The level of the Hype Chat, in English.

Possible Values are: ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN

is_system_message: bool#

A Boolean value that determines if the message sent with the Hype Chat was filled in by the system.

If True, the user entered no message and the body message was automatically filled in by the system.

If False, the user provided their own message to send with the Hype Chat.