GDTwitch Integration Toolkit
Godot 4.7 Library for Twitch Integration
![]() |
|---|
Lots of features in this project to make twitch integration easy. Check out the provided examples/ to get started quickly.
Twitch Integration
- Device Code Grant Flow for security-standard OAuth logins with the
GDTwitchDeviceCodeFlowWidget. - Supports sending chat messages, replies, and pinned messages.
- Supports EventSub reconnect requests, and automatic reconnecting on dropped connections (using backoff).
- Use signals for EventSub events with
GDTwitchEventSub - Supports all versioned EventSub events.
- Use coroutines to load animated emotes from the web and cache with
GDTwitchImages. - Build your own Twitch Chat overlays OR release games to the public with Twitch Integration.
Twitch Images Support:
- Emotes Support:
- User badges
- User avatars
Render chat messages
![]() |
|---|
- Use
GDTwitchEmoteChatLabelto render a chat message with embedded animated zero-width emotes. - Use
GDTwitchChatRowto render an entire chat row with avatar, badges, colorized usernames, and the chat message with embedded animated zero-width emotes.
Examples
Check out the examples/ directory for the most reliable source of documentation.
They should provide ideas on how to get started.
![]() |
|---|
examples/main_minimal_example.gd- This example demonstrates how to create a
GDTwitchEventSubconnection with just a few lines of code. - This example listens to chat messages, and sends a message to chat.
- Run with
$ godot --headless -s res://examples/main_minimal_example.gd
- This example demonstrates how to create a
examples/main_device_code_example.gd- This example demonstrates the use of the
GDTwitchDeviceCodeFlowWidget, which allows your app to complete the Device Code Grant Flow. - It also demonstrates the refresh-token ability of the Widget.
- Run with
$ godot -s res://examples/main_device_code_example.gd
- This example demonstrates the use of the
examples/games_example- This example includes a couple programs to choose from:
chat: Demonstrates use of theGDTwitchChatRowwhich renders avatars, badges, and chat messages.plinko: Demonstrates reading from chat to control a game.
- This example features a UI for inputting the channels you want to interact with.
- This example also demonstrates saving the
AppTokento disk for quick restarts. - Run with
$ godot .as it is the primary binary.
- This example includes a couple programs to choose from:
Usage
GDTwitchEventSub
GDTwitchEventSub is your primary class for engaging with the Twitch EventSub API. Every possible message has a type-safe concrete type defined under GDTwitchTypes.
Using GDTwitchEventSub requires the following:
- Create a cancel token (
GDTwitchAsync.Context) - Events to subscribe to (
GDTwitchEventSub.EventSelection) - Your connection parameters (
GDTwitchEventSub.StartArgs)var context := GDTwitchAsync.Context.ongoing() var event_selection := GDTwitchEventSub.EventSelection.all() var channel := GDTwitchEventSub.CHANNEL_SELF # Special channel name for connecting to the user whose app_token you are using. var start_args := GDTwitchEventSub.StartArgs.new(app_token, channel, event_selection)
Then start the GDTwitchEventSub!
var events : GDTwitchEventSub
func _ready() -> void:
events.on_any_event.connect(_on_any_event) # Use a more specific signal!
events.start(context, start_args)
and you're off and running.
To close events:
context.cancel()
and to cleanup any resources at app shutdown, or when a child context is no longer needed:
context.join() # or context.cancel_and_join() if this hasn't been cancelled.
#### GDTwitchImages
GDTwitchImages is your one-stop shop for image downloads, caching, and decoding. All images and animations are retrieved as Texture so you are free to use them how you see fit.
To use GDTwitchImages, you only have to create an instance:
var images := GDTwitchImages.new()
These instance are cheap. However, the image download deduplication only happens per-instance, so if you have many overlays you may want to share an instance instead of creating multiple new ones to prevent downloading the same emotes, badges, or avatars concurrently.
# Resolve all emotes (all emote_spans.resolved_emotes will be updated)
await images.resolve_emotes(context, event.message.emote_spans)
# Resolve any _avatar_url field:
var avatar_image := await images.resolve_avatar_url(context, message.chatter_avatar_url)
# Resolve all badges (all badges.resolved_badges will be updated)
await images.resolve_badges(context, message.badges)
NOTE: When an EmoteSpan or ChatMessageBadge has already been resolved, it holds a reference to resolved image. However, resolving the same emote later on a new instance will just use the Texture in memory (if its weak reference is alive) or check the cache on disk.
Often you want to download multiple images concurrently:
# Resolve all images and/or add them to the cache and resolved fields.
await GDTwitchAsync.await_all(
images.resolve_emotes.bind(context, event.message.emote_spans),
images.resolve_badges.bind(context, event.badges),
images.resolve_avatar_url.bind(context, event.chatter_avatar_url),
)
# For ChannelChatMessageV1Event, simply use the shorthand function, which
# returns the avatar texture and adds images to the cache and resolved fields.
await images.resolve_chat_message(event)
context is a cancel token with some interesting properties. See the section on GDTwitchAsync.Context for tips and tricks.
GDTwitchAsync.Context
GDTwitchAsync.Context is a versitile utility used extensively in the GDTwitch internals. However, it provides some great benefits as a public-facing API as well, such as timeouts and cancellation.
It can be constructed in at least these following ways:
# Context that continues until it is cancelled.
var context := GDTwitchAsync.Context.ongoing()
# Context that continues until it cancelled or the time expires.
# Useful for image downloads that you may want to limit their time.
var image_context := GDTwitchAsync.Context.new_timeout(15.0)
# Create a context where if the parent is cancelled, the child is cancelled, too.
var child_context := context.child()
var download_context := context.child_with_timeout(15.0)
GDTwitchEventSub expects the context passed into start to be cancelled at some point so that the server can shutdown and begin cleanup.
You application should call context.cancel() when the GDTwitchEventSub is no longer needed, such as when the managing Node is removed from the tree (_exit_tree()).
Additionally, when the application shuts down, or a child context is no longer needed, you should also call context.cancel_and_join() or context.join() to free any remaining resources (threads and workers) for a clean exit.
NOTE: context.cancel() will cancel any children GDTwitchAsync.Context.
NOTE: context.join() will join any children GDTwitchAsync.Context.
NOTE: context.is_done() is the way to check if a context has been cancelled and work should be stopped.
GDTwitchDeviceCodeFlowWidget
![]() |
|---|
GDTwitchDeviceCodeFlowWidget is a widget that initiates the Device Code Grant Flow for your users. If offers provides signal on_app_token(app_token: GDTwitchEventSub.AppToken, error: String) which can be used to get the GDTwitchEventSub.AppToken required for events.start(...)
See this widget in action with main_device_code_example.gd.
This widget makes use of the underlying GDTwitchDeviceCodeFlow utility, which can be used to create your own custom widget. The GDTwitchDeviceCodeFlow is heavily commented, so check it out for more details.
This widget also provides the ability to refresh a token while displaying the token status to the user. The example main_device_code_example.gd demonstrates how to do this in 3 easy steps:
- Connect to
signal on_app_token_refresh. - Apply the app_token you already have:
device_code_flow_widget.set_app_token(_load_app_token_from_disk()) - Use the app token when its refreshed
GDTwitchAnimatedTexture
This class is a self-animating Texture2D. It is created when TwitchImages decodes GIF and WEBP files.
If you prefer, you may use anim.get_sprite_frames() to run animations another way.
GDTwitchTypes
This namespace-class holds all of the concrete types for all of the event you can subscribe to.
There are some artificial fields in some of the various types. Namely, _avatar_url fields are not part of the Twitch EventSub API, but are made available so that those images can be downloaded.
Other stuff
There is plenty more, but these are the basics and then some. When exploring the codebase, the general guideline is that the more underscores you see, the more internal the API. Have fun.
Project Notes
GDTwitch library
The architecture of the project allows you to integrate the gd-twitch library without the use of specialized nodes. This encourages a flexibility in implementation in your own projects. To make this possible, the codebase makes use of many components that perform tasks, such as network IO, threading, and image request deduplication using threads in thread-safe patterns that are ultimately exposed to your project as coroutines or signals.
Testing
- The test directory includes a GDScript code coverage report tool based on godot-code-coverage, updated for Godot 4.7. See
test/coverage.gdfor details. - Injected fakes for Websocket, Http, and GDTwitchClock to override network I/O and time.
- A utility for saving event samples to disk makes it easy to replicate real-world behavior while tests are offline.
Semantic Versioning Post at version 1.0+
This project uses Semantic Versioning. See https://semver.org/ for details.
In summary, given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you make incompatible API changes
- MINOR version when you add functionality in a backward compatible manner
- PATCH version when you make backward compatible bug fixes
AI Notice
- All code is reviewed by humans but some parts of this project were implemented by AI and were reviewed and verified by a human.
- Many hours of human attention and care have gone into ensuring the code is high quality and reliable.
- Notable generated content:
- Example peg images are AI generated.
- GDTwitchTypes were AI generated from documentation.
- Many tests were AI generated after the foundation for testing was created.
Changelog for version 21.1.0
2026-10-09 03:58:24
No changelog provided for this version.


