Twitch
Twitch Moderation Toolkit — cross-channel moderation visibility for Twitch moderators.
This extension provides a model for interacting with the Twitch Helix API (chatters, bans, mod events, user lookups), a workflow that audits all your moderated channels in parallel, and a report that correlates findings cross-channel to surface suspicious users and ban overlap.
Quick Start
swamp extension pull @webframp/twitch
# Create one model instance per channel you moderate
swamp model create @webframp/twitch mod-drongo \
--global-arg channel=drongo \
--global-arg moderatorId=YOUR_TWITCH_USER_ID
# If the broadcaster has OAuth'd your app, enable ban/mod-event reads:
swamp model create @webframp/twitch mod-drongo \
--global-arg channel=drongo \
--global-arg moderatorId=YOUR_TWITCH_USER_ID \
--global-arg hasBroadcasterAuth=true
# Run the cross-channel audit
swamp workflow run @webframp/twitch-mod-auditAuthentication
Requires a Twitch application with OAuth2 user tokens. Store credentials in vault:
swamp vault set twitch-client-id YOUR_CLIENT_ID
swamp vault set twitch-client-secret YOUR_CLIENT_SECRET
swamp vault set twitch-access-token YOUR_ACCESS_TOKEN
swamp vault set twitch-refresh-token YOUR_REFRESH_TOKENTo obtain tokens, register an app at dev.twitch.tv/console/apps with redirect URL http://localhost:3000 and category "Chat Bot". Then authorize:
# 1. Open in browser (replace YOUR_CLIENT_ID):
# https://id.twitch.tv/oauth2/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:3000&response_type=code&scope=moderator:read:chatters+moderator:read:banned_users+moderator:manage:banned_users+user:write:chat+channel:read:editors+moderator:read:suspicious_users+moderator:read:warnings
# 2. Copy the code from the redirect URL, then exchange for tokens:
curl -X POST 'https://id.twitch.tv/oauth2/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&code=AUTH_CODE&grant_type=authorization_code&redirect_uri=http://localhost:3000'
# 3. Get your moderator user ID:
curl -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Client-Id: YOUR_CLIENT_ID' \
'https://api.twitch.tv/helix/users'The model refreshes expired access tokens automatically using the refresh token.
Methods by Auth Level
Moderator auth (works with any moderator token)
| Method | Scope | Purpose |
|---|---|---|
| get_channel | channel:read:editors | Channel metadata |
| get_chatters | moderator:read:chatters | List users in chat |
| get_user | (none) | User profile and account age |
| ban_user / unban_user | moderator:manage:banned_users | Issue/remove bans |
| send_message | user:write:chat | Send chat messages |
Broadcaster auth (broadcaster must have OAuth'd the app)
| Method | Scope | Purpose |
|---|---|---|
| get_banned_users | moderator:read:banned_users | Read full ban list |
| get_mod_events | moderator:read:banned_users | Mod add/remove events |
Set hasBroadcasterAuth=true on model instances where the broadcaster has
authorized your application. Methods that require broadcaster auth throw a
clear error when the flag is false.
Scopes
Request all scopes during app registration to avoid re-authorization later.
Note: the deprecated moderation:read scope has been replaced by the
granular moderator:read:banned_users scope.
| Scope | Used by | Purpose |
|---|---|---|
| moderator:read:chatters | get_chatters | List users in chat |
| moderator:read:banned_users | get_banned_users, get_mod_events | Read bans and mod activity |
| moderator:manage:banned_users | ban_user, unban_user | Issue bans/timeouts and unban |
| user:write:chat | send_message | Send chat messages as your user |
| channel:read:editors | get_channel | Read channel metadata |
| moderator:read:suspicious_users | (future) | Twitch-flagged suspicious users |
| moderator:read:warnings | (future) | Warnings issued to users |
2026.08.21.2
Changed:
ban_user,unban_user, andget_usernow reject emptyuserId/loginvalues before making any API call, instead of sending a blank ID to Twitch and surfacing whatever cryptic error Helix happens to return.ban_user'sduration(timeout length) is now validated against Twitch's actual limits — an integer between 1 second and 1,209,600 seconds (2 weeks). Out-of-range values are rejected immediately with a clear message rather than failing deep in the Helix API call.send_messagenow enforces the documented 500-character limit onmessage(and rejects empty messages) instead of letting the API reject an oversized message after the request is already sent.ban_user'sreasonfield is capped at 500 characters to match Twitch's API limit.- Errors raised by failed Helix API requests now name the HTTP method and
path that was attempted (e.g.
GET /moderation/banned?... returned 404) instead of just the status code and response body, making it clear which operation failed when multiple API calls happen in one method.
No behavioral changes for well-formed inputs — existing valid calls are unaffected.
Global Arguments
| Argument | Type | Description |
|---|---|---|
| channel | string | Twitch channel login name |
| moderatorId | string | Your Twitch user ID (the moderator performing actions) |
| clientId | string | Twitch application client ID |
| clientSecret | string | Twitch application client secret |
| accessToken | string | OAuth2 access token |
| refreshToken | string | OAuth2 refresh token |
| hasBroadcasterAuth | boolean | Set true if the broadcaster authorized this app (enables ban list and mod event reads) |
| Argument | Type | Description |
|---|---|---|
| login | string | Twitch login name to look up |
| Argument | Type | Description |
|---|---|---|
| userId | string | Twitch user ID to ban |
| reason? | string | Reason for the ban |
| duration? | number | Timeout duration in seconds, 1 to 1209600 (2 weeks); omit for a permanent ban |
| Argument | Type | Description |
|---|---|---|
| userId | string | Twitch user ID to unban |
| Argument | Type | Description |
|---|---|---|
| message | string | Message text to send (max 500 chars) |
| replyToMessageId? | string | Message ID to reply to (threads the response) |
Resources
Cross-channel Twitch moderation audit. Gathers chatters, bans, and channel info from all channel instances in parallel, then flags suspicious users (new accounts, cross-channel ban overlap, multi-channel presence). NOTE: Steps use modelIdOrName: "*" to target all @webframp/twitch model instances. Create one model instance per channel before running this workflow (e.g. swamp model create --type @webframp/twitch --name channel1).
Cross-channel moderation report highlighting suspicious users, ban overlap, and recent mod activity
2026.08.21.1
Changed: Tightened channel, moderatorId, clientId, clientSecret,
accessToken, and refreshToken on the global-args schema to require
non-empty strings. All six are required identifiers/tokens that the Twitch
API never accepts empty — this catches misconfigured vault references or
blank --global-arg values at model-create time instead of a confusing
Helix API failure on first method call.
2026.07.30.1
Added: hasBroadcasterAuth global arg (boolean, default false). When
false, get_banned_users and get_mod_events throw a clear error explaining
the broadcaster must have OAuth'd the app, instead of silently hitting a
Twitch 401.
Changed: Manifest description now separates methods into "Moderator auth"
and "Broadcaster auth" tables so users can see at a glance what works with
their token level. The OAuth scope URL replaces the deprecated moderation:read
with the granular moderator:read:banned_users.
Changed: Workflow step descriptions for get-banned-users and
get-mod-events note the broadcaster auth requirement. Both steps retain
allowFailure: true so the workflow completes even without broadcaster tokens.
Upgrade note: Existing model instances default to hasBroadcasterAuth=false
after upgrade. If you previously used get_banned_users or get_mod_events
successfully (because the broadcaster had authorized your app), update your
instances to restore that behavior:
swamp model update <name> --global-arg hasBroadcasterAuth=true
2026.07.30.1
Added: hasBroadcasterAuth global arg (boolean, default false). When
false, get_banned_users and get_mod_events throw a clear error explaining
the broadcaster must have OAuth'd the app, instead of silently hitting a
Twitch 401.
Changed: Manifest description now separates methods into "Moderator auth"
and "Broadcaster auth" tables so users can see at a glance what works with
their token level. The OAuth scope URL replaces the deprecated moderation:read
with the granular moderator:read:banned_users.
Changed: Workflow step descriptions for get-banned-users and
get-mod-events note the broadcaster auth requirement. Both steps retain
allowFailure: true so the workflow completes even without broadcaster tokens.
Upgrade note: Existing model instances default to hasBroadcasterAuth=false
after upgrade. If you previously used get_banned_users or get_mod_events
successfully (because the broadcaster had authorized your app), update your
instances to restore that behavior:
swamp model update <name> --global-arg hasBroadcasterAuth=true
2026.07.18.2
Added: An upgrades array entry (no-op) to mod.ts for proper typeVersion tracking on existing instances. No schema or behavior changes.
2026.07.18.1
Changed: Added @module-level JSDoc documentation to mod.ts. No
runtime behavior change.
2026.07.13.1
Changed: Upgraded the test-only dev dependency
@systeminit/swamp-testing to 0.20260504.10, matching the rest of the repo.
This is a test-harness change only — the published extension bundle is
unchanged and no runtime behavior is affected.
2026.07.18.1
Changed: Added @module-level JSDoc documentation to mod.ts. No
runtime behavior change.
2026.07.13.1
Changed: Upgraded the test-only dev dependency
@systeminit/swamp-testing to 0.20260504.10, matching the rest of the repo.
This is a test-harness change only — the published extension bundle is
unchanged and no runtime behavior is affected.
2026.07.13.1
Changed: Upgraded the test-only dev dependency
@systeminit/swamp-testing to 0.20260504.10, matching the rest of the repo.
This is a test-harness change only — the published extension bundle is
unchanged and no runtime behavior is affected.
2026.07.03.1
Changed: Added JSDoc documentation to HELIX_BASE, TOKEN_URL,
helixApiPaginated (API helpers), and report export for improved deno doc
coverage and quality rubric compliance.
2026.06.29.2
Added: README with quick start, authentication guide, method reference, and workflow/report documentation. Apache 2.0 LICENSE. JSDoc on model export.
Quality grade fix — addresses all missing scorer gates (README, code example, license, symbol documentation).
2026.06.29.2
Added: README with quick start, authentication guide, method reference, and workflow/report documentation. Apache 2.0 LICENSE. JSDoc on model export.
Quality grade fix — addresses all missing scorer gates (README, code example, license, symbol documentation).
2026.06.29.1
Fixed: Switched to inline npm:zod@4.4.3 specifier so deno doc --lint resolves the import without an import map (fixes scorer compatibility).
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License declared1/1earned
- Verified public repository2/2earned