Back to Openclaw

Twitch

docs/channels/twitch.md

2026.7.111.2 KB
Original Source

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

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 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 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 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. </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.