Documentation Index
Fetch the complete documentation index at: https://mintlify.com/disgoorg/disgo/llms.txt
Use this file to discover all available pages before exploring further.
The Gateway is DisGo’s WebSocket connection to Discord. It receives real-time events and sends commands to Discord. Understanding the Gateway is essential for building responsive bots.
What is the Gateway?
The Gateway is a WebSocket connection that:
- Receives events from Discord (messages, member updates, etc.)
- Sends commands to Discord (update presence, request members, etc.)
- Maintains session state for reconnection
- Handles heartbeats to keep the connection alive
Gateway vs Shard Manager
Choose based on your bot’s size:
Single Gateway
Shard Manager
Use when: Your bot is in fewer than 2,500 guildsclient, err := disgo.New(token,
bot.WithDefaultGateway(),
)
Simpler setup, single WebSocket connection. Use when: Your bot is in 2,500+ guilds (or you need sharding)client, err := disgo.New(token,
bot.WithDefaultShardManager(),
)
Multiple WebSocket connections distribute load across shards.
Gateway intents
Intents control which events Discord sends to your bot. You must specify intents when connecting:
import "github.com/disgoorg/disgo/gateway"
client, err := disgo.New(token,
bot.WithGatewayConfigOpts(
gateway.WithIntents(
gateway.IntentGuilds,
gateway.IntentGuildMessages,
gateway.IntentMessageContent,
),
),
)
Available intents
Guild create/update/delete, role updates, channel updates
Member join/update/leave (privileged intent)
IntentGuildMessageReactions
Reaction add/remove events in guilds
Access to message content (privileged intent)
Presence updates (privileged intent)
Intent combinations
// All non-privileged intents
gateway.WithIntents(gateway.IntentsNonPrivileged)
// All intents (requires approval for privileged intents)
gateway.WithIntents(gateway.IntentsAll)
// Guild-specific intents
gateway.WithIntents(gateway.IntentsGuild)
// DM-specific intents
gateway.WithIntents(gateway.IntentsDirectMessage)
// Custom combination
gateway.WithIntents(
gateway.IntentGuilds.Add(
gateway.IntentGuildMessages,
gateway.IntentGuildMembers,
),
)
Privileged intents (IntentGuildMembers, IntentGuildPresences, IntentMessageContent) must be enabled in the Discord Developer Portal.
Gateway configuration
Compression
Reduce bandwidth usage with compression:
gateway.WithCompression(gateway.CompressionZstdStream)
Available compression types:
CompressionNone - No compression
CompressionZlib - Zlib compression
CompressionZstdStream - Zstandard stream compression (recommended)
Large threshold
Control when Discord sends member lists:
gateway.WithLargeThreshold(250)
Default is 50. Discord won’t send offline members for guilds larger than this threshold.
Auto reconnect
gateway.WithAutoReconnect(true) // Default
When enabled, DisGo automatically reconnects on connection loss.
Initial presence
Set your bot’s status on connection:
import "github.com/disgoorg/disgo/discord"
gateway.WithPresenceOpts(
gateway.WithPresenceActivities(
discord.Activity{
Name: "with the Discord API",
Type: discord.ActivityTypeGame,
},
),
gateway.WithPresenceStatus(discord.OnlineStatusOnline),
)
Gateway lifecycle
Connection states
type Status int
const (
StatusUnconnected // Initial state
StatusConnecting // Establishing WebSocket
StatusWaitingForHello // Waiting for HELLO opcode
StatusIdentifying // Sending IDENTIFY
StatusResuming // Resuming previous session
StatusWaitingForReady // Waiting for READY event
StatusReady // Connected and ready
StatusDisconnected // Disconnected
)
Opening the gateway
ctx := context.Background()
err := client.OpenGateway(ctx)
if err != nil {
log.Fatal("Failed to connect:", err)
}
Closing the gateway
// Graceful close
client.Close(context.Background())
// Close with custom code
client.Gateway.CloseWithCode(
context.Background(),
websocket.CloseGoingAway,
"Restarting",
)
Gateway operations
Presence updates
Update your bot’s status:
err := client.SetPresence(ctx,
gateway.WithPresenceActivities(
discord.Activity{
Name: "Users: 1,234",
Type: discord.ActivityTypeWatching,
},
),
gateway.WithPresenceStatus(discord.OnlineStatusDND),
)
Activity types:
ActivityTypeGame - “Playing…”
ActivityTypeStreaming - “Streaming…”
ActivityTypeListening - “Listening to…”
ActivityTypeWatching - “Watching…”
ActivityTypeCompeting - “Competing in…”
Member chunking
Request member data for large guilds:
// Request specific members
err := client.RequestMembers(ctx,
guildID,
true, // include presences
"unique-nonce", // nonce for tracking
memberID1, memberID2,
)
// Request all members matching a query
err := client.RequestMembersWithQuery(ctx,
guildID,
true, // include presences
"", // nonce
"john", // username starts with
100, // limit
)
Voice state updates
import "github.com/disgoorg/snowflake/v2"
// Join a voice channel
err := client.UpdateVoiceState(ctx,
guildID,
&channelID,
false, // self mute
false, // self deaf
)
// Leave voice
err := client.UpdateVoiceState(ctx,
guildID,
nil, // nil channel ID = disconnect
false,
false,
)
Session resumption
DisGo automatically handles session resumption:
// Get session info (useful for persistence)
sessionID := client.Gateway.SessionID()
sequence := client.Gateway.LastSequenceReceived()
resumeURL := client.Gateway.ResumeURL()
// Manually configure resume data
client, err := disgo.New(token,
bot.WithGatewayConfigOpts(
gateway.WithSessionID(*sessionID),
gateway.WithSequence(*sequence),
gateway.WithResumeURL(*resumeURL),
),
)
Rate limiting
The Gateway has automatic rate limiting:
// Commands are automatically rate limited
// You can send ~120 commands per minute
for i := 0; i < 200; i++ {
// This is safe - DisGo handles rate limiting
err := client.SetPresence(ctx, ...)
}
DisGo’s built-in rate limiter queues commands and sends them at a safe rate. You don’t need to implement your own rate limiting for Gateway commands.
Gateway metrics
// Get connection latency
latency := client.Gateway.Latency()
log.Printf("Gateway latency: %v", latency)
// Check connection status
status := client.Gateway.Status()
if status.IsConnected() {
log.Println("Connected to Discord")
}
Close codes
Understand why connections close:
import "github.com/disgoorg/disgo/gateway"
// Handle close events
bot.WithGatewayConfigOpts(
gateway.WithCloseHandler(func(gw gateway.Gateway, err error, reconnect bool) {
log.Printf("Gateway closed: %v (reconnect=%v)", err, reconnect)
if !reconnect {
// Fatal error - connection won't be retried
// Examples: invalid token, disallowed intents
log.Fatal("Cannot reconnect")
}
}),
)
Common close codes:
4000-4003 - Temporary errors (will reconnect)
4004 - Invalid token (will not reconnect)
4011 - Sharding required (will not reconnect)
4013 - Invalid intents (will not reconnect)
4014 - Disallowed intents (will not reconnect)
Complete example
package main
import (
"context"
"log"
"os"
"time"
"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/bot"
"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/disgo/events"
"github.com/disgoorg/disgo/gateway"
)
func main() {
client, err := disgo.New(os.Getenv("TOKEN"),
bot.WithGatewayConfigOpts(
// Configure intents
gateway.WithIntents(
gateway.IntentGuilds,
gateway.IntentGuildMessages,
gateway.IntentMessageContent,
),
// Configure compression
gateway.WithCompression(gateway.CompressionZstdStream),
// Set initial presence
gateway.WithPresenceOpts(
gateway.WithPresenceActivities(
discord.Activity{
Name: "for messages",
Type: discord.ActivityTypeWatching,
},
),
),
// Handle close events
gateway.WithCloseHandler(func(
gw gateway.Gateway,
err error,
reconnect bool,
) {
log.Printf("Connection closed: %v", err)
}),
),
bot.WithEventListeners(&events.ListenerAdapter{
OnReady: func(e *events.Ready) {
log.Printf("Connected as %s", e.User.Username)
// Update presence after connect
_ = e.Client().SetPresence(context.Background(),
gateway.WithPresenceActivities(
discord.Activity{
Name: "Ready!",
Type: discord.ActivityTypeGame,
},
),
)
},
OnMessageCreate: func(e *events.MessageCreate) {
// Handle messages
},
}),
)
if err != nil {
log.Fatal(err)
}
defer client.Close(context.Background())
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err = client.OpenGateway(ctx); err != nil {
log.Fatal("Failed to connect:", err)
}
log.Println("Bot is running")
select {} // Run forever
}