Files
openclaw/docs/channels/twitch.md
Peter Steinberger f7d7148cf0 docs: rewrite published docs grounded in current source (#100142)
Source-grounded rewrite of 529 published docs pages with per-unit information-loss verification: 1,713 factual corrections cited to src/**, generated surfaces regenerated, frontmatter titles preserved for i18n, release notes pages untouched. All docs gates green.

Closes #100141
2026-07-05 00:32:47 -04:00

370 lines
11 KiB
Markdown

---
summary: "Twitch chat bot: install, credentials, access control, token refresh"
read_when:
- Setting up Twitch chat integration for OpenClaw
title: "Twitch"
sidebarTitle: "Twitch"
---
Twitch chat support over Twitch's chat (IRC) interface via the Twurple client. OpenClaw signs in as a Twitch bot account, joins one channel per configured account, and replies in that channel.
## Install
Twitch ships as an official plugin; it is not part of the core install.
<Tabs>
<Tab title="npm registry">
```bash
openclaw plugins install @openclaw/twitch
```
</Tab>
<Tab title="Local checkout">
```bash
openclaw plugins install ./path/to/local/twitch-plugin
```
</Tab>
</Tabs>
`plugins install` registers and enables the plugin. Picking Twitch during `openclaw onboard` or `openclaw channels add` installs it on demand. Use the bare package name to follow the current release; pin an exact version only for reproducible installs. Requires OpenClaw 2026.4.10 or newer.
Details: [Plugins](/tools/plugin)
## Quick setup
<Steps>
<Step title="Install the plugin">
See [Install](#install) above.
</Step>
<Step title="Create a Twitch bot account">
Create a dedicated Twitch account for the bot (or use an existing account).
</Step>
<Step title="Generate credentials">
Use [Twitch Token Generator](https://twitchtokengenerator.com/):
- Select **Bot Token**
- Verify scopes `chat:read` and `chat:write` are selected
- Copy the **Client ID** and **Access Token**
</Step>
<Step title="Find your Twitch user ID">
Use [https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/](https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/) to convert a username to a Twitch user ID.
</Step>
<Step title="Configure the token">
- Env: `OPENCLAW_TWITCH_ACCESS_TOKEN=...` (default account only)
- Or config: `channels.twitch.accessToken`
If both are set, config takes precedence (the env var is only a fallback for the default account).
</Step>
<Step title="Start the gateway">
```bash
openclaw gateway run
```
</Step>
</Steps>
<Warning>
Add access control (`allowFrom` or `allowedRoles`) to prevent unauthorized users from triggering the bot. `requireMention` defaults to `true`.
</Warning>
Minimal config:
```json5
{
channels: {
twitch: {
enabled: true,
username: "openclaw", // Bot's Twitch account (authenticates)
accessToken: "oauth:abc123...", // OAuth access token (or use OPENCLAW_TWITCH_ACCESS_TOKEN env var)
clientId: "xyz789...", // Client ID from Token Generator
channel: "yourchannel", // Which Twitch channel's chat to join (required)
allowFrom: ["123456789"], // (recommended) Your Twitch user ID only
},
},
}
```
## What it is
- A Twitch channel owned by the Gateway.
- Deterministic routing: replies always go back to the Twitch channel the message came from.
- Each joined channel maps to an isolated group session key `agent:<agentId>:twitch:group:<channel>`.
- `username` is the bot's account (who authenticates), `channel` is which chat room to join. One account entry joins exactly one channel.
- Tokens work with or without the `oauth:` prefix; OpenClaw normalizes both ways (the setup wizard expects the `oauth:` form).
## Token refresh (optional)
Tokens from [Twitch Token Generator](https://twitchtokengenerator.com/) cannot be refreshed by OpenClaw - regenerate when expired (they last a few hours; no app registration needed).
For automatic refresh, create your own app at the [Twitch Developer Console](https://dev.twitch.tv/console) and add:
```json5
{
channels: {
twitch: {
clientSecret: "your_client_secret",
refreshToken: "your_refresh_token",
},
},
}
```
With both set, the plugin uses a refreshing auth provider that renews tokens before expiration and logs each refresh. Without `refreshToken` it logs `token refresh disabled (no refresh token)`; without `clientSecret` it falls back to a static (non-refreshing) token.
## Multi-account support
Use `channels.twitch.accounts` with per-account credentials. See [Configuration](/gateway/configuration) for the shared pattern.
Example (one bot account in two channels):
```json5
{
channels: {
twitch: {
accounts: {
channel1: {
username: "openclaw",
accessToken: "oauth:abc123...",
clientId: "xyz789...",
channel: "yourchannel",
},
channel2: {
username: "openclaw",
accessToken: "oauth:def456...",
clientId: "uvw012...",
channel: "secondchannel",
},
},
},
},
}
```
<Note>
Every account entry needs its own `accessToken` (the env var covers only the default account). An account joins exactly one channel, so joining two channels means two accounts. `channels.twitch.defaultAccount` picks which account is the default.
</Note>
## Access control
`allowFrom` is a hard allowlist of Twitch user IDs. When it is set, `allowedRoles` is ignored; leave `allowFrom` unset to use role-based access instead.
**Available roles:** `"moderator"`, `"owner"`, `"vip"`, `"subscriber"`, `"all"`.
<Tabs>
<Tab title="User ID allowlist (most secure)">
```json5
{
channels: {
twitch: {
accounts: {
default: {
allowFrom: ["123456789", "987654321"],
},
},
},
},
}
```
</Tab>
<Tab title="Role-based">
```json5
{
channels: {
twitch: {
accounts: {
default: {
allowedRoles: ["moderator", "vip"],
},
},
},
},
}
```
</Tab>
<Tab title="Disable @mention requirement">
By default, `requireMention` is `true`. To respond to all allowed messages:
```json5
{
channels: {
twitch: {
accounts: {
default: {
requireMention: false,
},
},
},
},
}
```
</Tab>
</Tabs>
<Note>
**Why user IDs?** Usernames can change, allowing impersonation. User IDs are permanent.
Find yours with the [username to ID converter](https://www.streamweasels.com/tools/convert-twitch-username-to-user-id/).
</Note>
## Troubleshooting
First, run diagnostic commands:
```bash
openclaw doctor
openclaw channels status --probe
```
<AccordionGroup>
<Accordion title="Bot does not respond to messages">
- **Check access control:** Ensure your user ID is in `allowFrom`, or temporarily remove `allowFrom` and set `allowedRoles: ["all"]` to test.
- **Check the mention gate:** With `requireMention: true` (default), messages must @mention the bot username.
- **Check the bot is in the channel:** The bot only joins the channel named in `channel`.
</Accordion>
<Accordion title="Token issues">
"Failed to connect" or authentication errors:
- Verify `accessToken` is the OAuth access token value (the `oauth:` prefix is optional)
- Check the token has `chat:read` and `chat:write` scopes
- If using token refresh, verify `clientSecret` and `refreshToken` are set
</Accordion>
<Accordion title="Token refresh not working">
Check logs for refresh events:
```text
Using env token source for mybot
Access token refreshed for user 123456 (expires in 14400s)
```
If you see `token refresh disabled (no refresh token)`:
- Ensure `clientSecret` is provided
- Ensure `refreshToken` is provided
</Accordion>
</AccordionGroup>
## Config
### Account config
<ParamField path="username" type="string" required>
Bot username (the authenticating account).
</ParamField>
<ParamField path="accessToken" type="string" required>
OAuth access token with `chat:read` and `chat:write` (config or env for the default account).
</ParamField>
<ParamField path="clientId" type="string" required>
Twitch Client ID (from Token Generator or your app). Optional in the schema but required to connect.
</ParamField>
<ParamField path="channel" type="string" required>
Channel to join.
</ParamField>
<ParamField path="enabled" type="boolean" default="true">
Enable this account.
</ParamField>
<ParamField path="clientSecret" type="string">
Optional: for automatic token refresh.
</ParamField>
<ParamField path="refreshToken" type="string">
Optional: for automatic token refresh.
</ParamField>
<ParamField path="expiresIn" type="number">
Token expiry in seconds (refresh tracking).
</ParamField>
<ParamField path="obtainmentTimestamp" type="number">
Timestamp when the token was obtained (refresh tracking).
</ParamField>
<ParamField path="allowFrom" type="string[]">
User ID allowlist. When set, roles are ignored.
</ParamField>
<ParamField path="allowedRoles" type='Array<"moderator" | "owner" | "vip" | "subscriber" | "all">'>
Role-based access control.
</ParamField>
<ParamField path="requireMention" type="boolean" default="true">
Require @mention to trigger the bot.
</ParamField>
<ParamField path="responsePrefix" type="string">
Outbound response prefix override for this account.
</ParamField>
### Provider options
- `channels.twitch.enabled` - Enable/disable channel startup
- `channels.twitch.username` / `accessToken` / `clientId` / `channel` - Simplified single-account config (implicit `default` account; takes precedence over `accounts.default`)
- `channels.twitch.accounts.<accountName>` - Multi-account config (all account fields above)
- `channels.twitch.defaultAccount` - Which account name is the default
- `channels.twitch.markdown.tables` - Markdown table rendering mode (`off` | `bullets` | `code` | `block`)
Full example:
```json5
{
channels: {
twitch: {
enabled: true,
username: "openclaw",
accessToken: "oauth:abc123...",
clientId: "xyz789...",
channel: "yourchannel",
clientSecret: "secret123...",
refreshToken: "refresh456...",
allowFrom: ["123456789"],
accounts: {
second: {
username: "mybot",
accessToken: "oauth:def456...",
clientId: "uvw012...",
channel: "your_channel",
enabled: true,
expiresIn: 14400,
obtainmentTimestamp: 1706092800000,
allowedRoles: ["moderator"],
},
},
},
},
}
```
## Tool actions
The agent can send Twitch messages through the message tool `send` action:
```json5
{
channel: "twitch",
action: "send",
to: "#mychannel",
message: "Hello Twitch!",
}
```
`to` is optional and defaults to the account's configured `channel`.
## Safety and ops
- **Treat tokens like passwords** - never commit tokens to git.
- **Use automatic token refresh** for long-running bots.
- **Use user ID allowlists** instead of usernames for access control.
- **Monitor logs** for token refresh events and connection status.
- **Scope tokens minimally** - only request `chat:read` and `chat:write`.
- **If stuck**: restart the gateway after confirming no other process owns the session.
## Limits
- **500 characters** per message; longer replies are chunked at word boundaries.
- Markdown is stripped before sending (Twitch chat is plain text; newlines become spaces).
- OpenClaw adds no rate limiting of its own; the Twurple chat client handles Twitch rate limits.
## Related
- [Channel Routing](/channels/channel-routing) — session routing for messages
- [Channels Overview](/channels) — all supported channels
- [Groups](/channels/groups) — group chat behavior and mention gating
- [Pairing](/channels/pairing) — DM authentication and pairing flow
- [Security](/gateway/security) — access model and hardening