Skip to main content

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:
Use when: Your bot is in fewer than 2,500 guilds
client, err := disgo.New(token,
    bot.WithDefaultGateway(),
)
Simpler setup, single WebSocket connection.

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

IntentGuilds
Intents
Guild create/update/delete, role updates, channel updates
IntentGuildMembers
Intents
Member join/update/leave (privileged intent)
IntentGuildMessages
Intents
Message events in guilds
IntentGuildMessageReactions
Intents
Reaction add/remove events in guilds
IntentDirectMessages
Intents
Message events in DMs
IntentMessageContent
Intents
Access to message content (privileged intent)
IntentGuildPresences
Intents
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
}