General
What is Kappopher?
Kappopher is a comprehensive Go wrapper for the Twitch Helix API. It provides type-safe access to 147+ API endpoints, multiple OAuth flows, real-time event handling via EventSub and IRC, and advanced features like caching, batch operations, and middleware.
Why “Kappopher”?
A playful combination of “Kappa” (Twitch’s iconic emote) and “Gopher” (Go’s mascot).
Is this an official Twitch library?
No, Kappopher is a community-maintained library. It is not affiliated with or endorsed by Twitch.
Which Go version is required?
Kappopher requires Go 1.21 or later. We use generics and other modern Go features.
Authentication
Which OAuth flow should I use?
| Use Case | Recommended Flow |
|---|---|
| Server-side app | Authorization Code |
| CLI tool | Device Code |
| Server-to-server (no user) | Client Credentials |
| Client-side/SPA | Implicit (least secure) |
How do I get a Client ID and Secret?
- Go to the Twitch Developer Console
- Register a new application
- Copy your Client ID
- Generate a Client Secret
My token keeps expiring. What should I do?
Use the AutoRefresh feature to automatically refresh tokens before they expire:
cancel := authClient.AutoRefresh(ctx)
defer cancel()
Or manually refresh using RefreshToken() when you get a 401 error.
What scopes do I need?
It depends on the endpoints you’re using. Check the Twitch API Reference for required scopes per endpoint. Common scope groups are available via helix.CommonScopes.
EventSub
WebSocket or Webhooks?
| Feature | WebSocket | Webhooks |
|---|---|---|
| Public endpoint required | No | Yes |
| Best for | Bots, local dev | Production servers |
| Max subscriptions | 300 per connection | 10,000 total |
| Delivery | Real-time push | HTTP POST |
Why am I not receiving events?
- Check subscription status - Use
GetEventSubSubscriptions()to verify your subscriptions areenabled - Verify scopes - Some events require specific OAuth scopes
- Check user authorization - User token events require the user to have authorized your app
- WebSocket connected? - Ensure your WebSocket client is connected and listening
How do I handle EventSub reconnection?
The WebSocket client handles reconnection automatically. Use the reconnect handler to be notified:
helix.WithEventSubReconnectHandler(func(oldSessionID, newSessionID string) {
log.Printf("Reconnected: %s -> %s", oldSessionID, newSessionID)
})
IRC / Chat
Should I use IRC or EventSub for chat?
| Feature | IRC | EventSub |
|---|---|---|
| Latency | ~50ms | ~200ms |
| Send messages | Direct | Via API |
| Non-chat events | No | Yes |
| Best for | Chat bots | Dashboards |
Use IRC if you’re building a chat bot that needs to send messages quickly. Use EventSub if you need other events alongside chat.
Why can’t I send messages?
- Verify your token - Needs
chat:editscope - Join the channel first - Call
irc.Join(channel)before sending - Check rate limits - Twitch limits messages to 20 per 30 seconds (100 for verified bots)
- Bot account verified? - For higher limits, verify your bot at Twitch Developer Console
How do I parse emotes from chat messages?
Emote positions are in the emotes tag of IRC messages:
emotes := msg.Tags["emotes"]
// Format: "emote_id:start-end,start-end/emote_id:start-end"
API Usage
How do I handle pagination?
Use the cursor from the response:
cursor := ""
for {
resp, _ := client.GetStreams(ctx, &helix.GetStreamsParams{
First: 100,
After: cursor,
})
// Process resp.Data...
if resp.Pagination == nil || resp.Pagination.Cursor == "" {
break
}
cursor = resp.Pagination.Cursor
}
How do I handle rate limits?
Kappopher tracks rate limits automatically. Check before making requests:
remaining, reset := client.GetRateLimitInfo()
if remaining < 10 {
time.Sleep(time.Until(reset))
}
Can I make requests concurrently?
Yes! The client is thread-safe. For batch operations, use the batch helper:
batcher := helix.NewBatcher(client, helix.BatchConfig{
MaxConcurrent: 5,
})
results := batcher.GetUsers(ctx, userIDs)
Can I use different tokens for different requests?
Yes. Use WithToken to override the client-level token on a per-request basis:
ctx := helix.WithToken(ctx, &helix.Token{AccessToken: "other-user-token"})
followers, err := client.GetChannelFollowers(ctx, params)
This is useful when making concurrent requests that each require a different user token (e.g., fetching followers for multiple channels). See the Authentication Examples for a complete example.
Troubleshooting
I’m getting “invalid token” errors
- Validate your token:
authClient.ValidateToken(ctx, token) - Check if it’s expired
- Ensure you’re using the correct token type (app vs user)
- Verify the token has required scopes
API calls return empty data
- Check if the resource exists (user might have changed name, stream might be offline)
- Verify your parameters are correct
- Check the response’s
Paginationfield - you might need to paginate
WebSocket disconnects frequently
- Handle PING/PONG keepalives (Kappopher does this automatically)
- Check your network stability
- Use the reconnect handler to recover gracefully
Contributing
How can I contribute?
See CONTRIBUTING.md for guidelines. We welcome bug reports, feature requests, and pull requests!
Where do I report bugs?
Open an issue on GitHub.