Twitch Integration
Connect your Twitch accounts to enable chat bots, channel management, and real-time event tracking.
Setup
Prerequisites
- A Twitch application registered at dev.twitch.tv
- Configure your OAuth redirect URI in Twitch:
{server.public_url}/v1/integrations/callback/twitch - Note your Client ID and Client Secret
Configuration
[server]
# The redirect URI is automatically built from this: {public_url}/v1/integrations/callback/twitch
public_url = "https://your-domain.com"
[integrations.twitch]
client_id = "your_twitch_client_id"
client_secret = "your_twitch_client_secret"
Or via environment variables:
SERVER_PUBLIC_URL=https://your-domain.com
TWITCH_INTEGRATION_CLIENT_ID=your_client_id
TWITCH_INTEGRATION_CLIENT_SECRET=your_client_secret
The OAuth redirect URI is automatically constructed from server.public_url:
{server.public_url}/v1/integrations/callback/twitch
Make sure to add this exact URL to your Twitch application's OAuth Redirect URLs.
OAuth Scopes
Channel Scopes
Scopes requested for channel (broadcaster) accounts:
| Scope | Description | Required |
|---|---|---|
channel:manage:broadcast | Update stream title, game, tags | Yes |
channel:read:stream_key | Read stream key | No |
channel:manage:schedule | Manage streaming schedule | Yes |
channel:read:subscriptions | Read subscriber list | Yes |
channel:manage:redemptions | Manage channel points rewards | Yes |
channel:read:redemptions | View channel points redemptions | Yes |
bits:read | View bits leaderboard | Yes |
channel:manage:moderators | Add/remove moderators | Yes |
channel:read:vips | View VIP list | Yes |
channel:manage:vips | Manage VIPs | Yes |
channel:moderate | Perform moderation actions | Yes |
moderator:read:followers | Read follower list | Yes |
channel:read:polls | View polls | Yes |
channel:manage:polls | Create/end polls | Yes |
channel:read:predictions | View predictions | Yes |
channel:manage:predictions | Create/resolve predictions | Yes |
channel:read:hype_train | View hype train events | Yes |
channel:manage:raids | Start/cancel raids | Yes |
channel:read:ads | Read ad schedule | Yes |
channel:manage:ads | Run ads | Yes |
channel:read:charity | Read charity campaign | Yes |
channel:read:goals | Read channel goals | Yes |
channel:read:guest_star | Read Guest Star sessions | Yes |
channel:manage:guest_star | Manage Guest Star sessions | Yes |
For bots to display the verified bot badge when chatting in your channel, the channel account must separately authorize the channel:bot scope. This can be done by adding it to the custom scopes when connecting or reconnecting the channel integration.
Bot Scopes
Scopes requested for bot accounts:
| Scope | Description | Required |
|---|---|---|
user:bot | Bot identity | Yes |
user:read:chat | Read chat messages via EventSub | Yes |
user:write:chat | Send chat messages via Helix API | Yes |
moderator:read:chat_messages | Read moderated chat messages | No |
moderator:manage:chat_messages | Delete chat messages | No |
moderator:manage:banned_users | Ban/unban users | No |
moderator:read:blocked_terms | View blocked terms | No |
moderator:manage:blocked_terms | Manage blocked terms | No |
moderator:read:chat_settings | View chat settings | No |
moderator:manage:chat_settings | Manage chat settings | No |
Bot Badge Requirements
For your bot to display the verified bot badge in Twitch chat when using the Send Chat Message API, specific requirements must be met:
Required Authorizations
Bot Account must authorize:
user:bot- Bot identity scopeuser:write:chat- Send messages via APIuser:read:chat- Read chat via EventSub
Channel Account must authorize:
channel:bot- Allows bots to display badge in this channel
Sending Messages with Badge
To send messages that display the bot badge:
- Use
POST /helix/chat/messages(NOT IRC) - Use an App Access Token (generated via client credentials flow)
- The App Access Token works because users authorized the scopes to your client ID
- The bot account cannot be the channel broadcaster
Important: User Access Token = messages sent but NO badge. App Access Token = badge displayed.
Verified Bot Status
Bots with Verified Bot status from Twitch receive:
- Higher chat rate limits (7,500 messages/30s vs 20)
- Higher join rate (2,000/10s vs 20)
- Verified badge displayed in chat
Apply for Verified Bot status through Twitch's developer portal when your bot reaches sufficient scale.
Chat Rate Limits
| Account Type | Messages/30s | Join Rate/10s |
|---|---|---|
| Regular User | 20 | 20 |
| Broadcaster/Mod/VIP | 100 | 20 |
| Verified Bot | 7,500 | 2,000 |
Connecting Accounts
Connect Channel Account
- Go to Admin > Integrations
- Click "Connect" under Twitch
- Select "Channel" as the account type
- Authorize on Twitch
- You'll be redirected back to Heimdall
Connect Bot Account
- Log out of Twitch (if logged into broadcaster account)
- Log into your bot's Twitch account
- Go to Admin > Integrations
- Click "Connect" under Twitch
- Select "Bot" as the account type
- Enter a unique bot identifier (e.g., "nightbot", "mybot")
- Authorize on Twitch
- You'll be redirected back to Heimdall
Token Management
Token Lifetime
- Access Token: 4 hours (automatically refreshed)
- Refresh Token: Does not expire (valid until revoked)
Automatic Refresh
Heimdall automatically refreshes tokens before they expire. The scheduler runs periodically and refreshes tokens that will expire within the configured buffer time (default: 30 minutes).
Manual Refresh
If you encounter issues:
- Go to Admin > Integrations
- Find the Twitch integration
- Click "Refresh Token"
Token Errors
Common token errors:
| Error | Cause | Solution |
|---|---|---|
invalid_grant | Token revoked on Twitch | Disconnect and reconnect |
invalid_client | Client credentials changed | Update config, reconnect |
token_expired | Refresh failed | Try manual refresh, or reconnect |
EventSub Integration
With Twitch integrations connected, you can subscribe to EventSub events for real-time notifications. EventSub subscriptions are managed separately from OAuth integrations.
Chat Events
| Type | Description | Required Scope |
|---|---|---|
channel.chat.message | User sends a message to chat | user:read:chat |
channel.chat.clear | Moderator clears all chat messages | user:read:chat |
channel.chat.clear_user_messages | All messages from a user removed | user:read:chat |
channel.chat.message_delete | Moderator deletes a specific message | user:read:chat |
channel.chat.notification | Chat events (subs, raids, etc.) | user:read:chat |
channel.chat_settings.update | Chat settings are modified | user:read:chat |
channel.chat.user_message_hold | User's message caught by automod | user:read:chat |
channel.chat.user_message_update | Message automod status updated | user:read:chat |
AutoMod & Moderation
| Type | Description | Required Scope |
|---|---|---|
automod.message.hold | Message caught by automod for review | moderator:manage:automod |
automod.message.update | Automod queue message status changes | moderator:manage:automod |
automod.settings.update | Automod settings modified | moderator:read:automod_settings |
automod.terms.update | Automod terms updated | moderator:manage:automod |
channel.moderate | Moderator performs action | channel:moderate |
channel.ban | User banned or timed out | channel:moderate |
channel.unban | User unbanned | channel:moderate |
channel.unban_request.create | User creates unban request | moderator:read:unban_requests |
channel.unban_request.resolve | Unban request resolved | moderator:manage:unban_requests |
channel.moderator.add | User given moderator privileges | None |
channel.moderator.remove | Moderator privileges removed | None |
channel.vip.add | User added as VIP | None |
channel.vip.remove | User removed as VIP | None |
channel.warning.send | User receives warning | None |
channel.warning.acknowledge | User acknowledges warning | None |
channel.suspicious_user.message | Suspicious user sends message | None |
channel.suspicious_user.update | Suspicious user status updated | None |
Channel Management
| Type | Description | Required Scope |
|---|---|---|
channel.update | Title, category, language changed | None |
channel.follow | Channel receives a follow | moderator:read:followers |
channel.ad_break.begin | Midroll commercial break starts | channel:read:ads |
channel.raid | Broadcaster raids another channel | None |
channel.shoutout.create | Broadcaster sends a shoutout | None |
channel.shoutout.receive | Broadcaster receives a shoutout | None |
channel.shield_mode.begin | Shield Mode activated | None |
channel.shield_mode.end | Shield Mode deactivated | None |
Subscriptions & Monetization
| Type | Description | Required Scope |
|---|---|---|
channel.subscribe | New subscription | channel:read:subscriptions |
channel.subscription.end | Subscription expires | channel:read:subscriptions |
channel.subscription.gift | Gift subscriptions granted | channel:read:subscriptions |
channel.subscription.message | Resub message sent | channel:read:subscriptions |
channel.cheer | User cheers with bits | bits:read |
channel.bits.use | Bits used on channel | bits:read |
Channel Points & Rewards
| Type | Description | Required Scope |
|---|---|---|
channel.channel_points_custom_reward.add | Custom reward created | None |
channel.channel_points_custom_reward.update | Custom reward modified | None |
channel.channel_points_custom_reward.remove | Custom reward deleted | None |
channel.channel_points_custom_reward_redemption.add | Viewer redeems custom reward | None |
channel.channel_points_custom_reward_redemption.update | Redemption status changed | None |
channel.channel_points_automatic_reward_redemption.add | Automatic reward redeemed | None |
Polls & Predictions
| Type | Description | Required Scope |
|---|---|---|
channel.poll.begin | Poll started | None |
channel.poll.progress | Users respond to poll | None |
channel.poll.end | Poll ended | None |
channel.prediction.begin | Prediction started | None |
channel.prediction.progress | Users participate in prediction | None |
channel.prediction.lock | Prediction locked | None |
channel.prediction.end | Prediction ended | None |
Goals & Charity
| Type | Description | Required Scope |
|---|---|---|
channel.goal.begin | Broadcaster starts a goal | None |
channel.goal.progress | Progress made towards goal | None |
channel.goal.end | Broadcaster ends goal | None |
channel.charity_campaign.start | Charity campaign started | None |
channel.charity_campaign.progress | Charity fundraising progress | None |
channel.charity_campaign.donate | User donates to charity | None |
channel.charity_campaign.stop | Charity campaign ended | None |
Hype Train
| Type | Description | Required Scope |
|---|---|---|
channel.hype_train.begin | Hype Train starts | None |
channel.hype_train.progress | Hype Train gains momentum | None |
channel.hype_train.end | Hype Train ends | None |
Stream Events
| Type | Description | Required Scope |
|---|---|---|
stream.online | Broadcaster starts streaming | None |
stream.offline | Broadcaster stops streaming | None |
Shared Chat (Multi-Stream)
| Type | Description | Required Scope |
|---|---|---|
channel.shared_chat.begin | Channel joins shared chat session | None |
channel.shared_chat.update | Shared chat session changes | None |
channel.shared_chat.end | Channel leaves shared chat | None |
Guest Star (Beta)
| Type | Description | Required Scope |
|---|---|---|
channel.guest_star_session.begin | Guest Star session starts | None |
channel.guest_star_session.end | Guest Star session ends | None |
channel.guest_star_guest.update | Guest or slot updated | None |
channel.guest_star_settings.update | Host preferences modified | None |
User & Authorization Events
| Type | Description | Required Scope |
|---|---|---|
user.update | User updates their account | None |
user.whisper.message | User receives a whisper | None |
user.authorization.grant | User grants app authorization | None |
user.authorization.revoke | User revokes app authorization | None |
Drops & Extensions
| Type | Description | Required Scope |
|---|---|---|
drop.entitlement.grant | Drop entitlement granted | None |
extension.bits_transaction.create | Bits transaction in extension | None |
Infrastructure
| Type | Description | Required Scope |
|---|---|---|
conduit.shard.disabled | EventSub transport shard disabled | None |
Subscribing to Events
To subscribe to EventSub events, use the Twitch API:
curl -X POST 'https://api.twitch.tv/helix/eventsub/subscriptions' \
-H 'Authorization: Bearer {app_access_token}' \
-H 'Client-Id: {client_id}' \
-H 'Content-Type: application/json' \
-d '{
"type": "channel.follow",
"version": "2",
"condition": {
"broadcaster_user_id": "12345",
"moderator_user_id": "12345"
},
"transport": {
"method": "webhook",
"callback": "https://your-domain.com/webhooks/twitch",
"secret": "your_webhook_secret"
}
}'
For WebSocket transport (recommended for bots):
curl -X POST 'https://api.twitch.tv/helix/eventsub/subscriptions' \
-H 'Authorization: Bearer {user_access_token}' \
-H 'Client-Id: {client_id}' \
-H 'Content-Type: application/json' \
-d '{
"type": "channel.chat.message",
"version": "1",
"condition": {
"broadcaster_user_id": "12345",
"user_id": "67890"
},
"transport": {
"method": "websocket",
"session_id": "your_websocket_session_id"
}
}'
Troubleshooting
"Missing required scope" error
The user didn't authorize all required scopes. Ask them to:
- Go to Twitch Settings > Connections
- Revoke Heimdall's access
- Reconnect through Admin > Integrations
Bot messages not showing badge
Ensure:
- Channel account has authorized
channel:botscope - Bot account has authorized
user:botscope - You're using App Access Token, not User Access Token
- Bot account is not the channel broadcaster
Rate limit exceeded
Your bot is sending too many messages. Implement:
- Message queuing
- Rate limiting per channel
- Consider applying for Verified Bot status