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.

DisGo’s event system allows you to respond to events from Discord’s Gateway API. Events are dispatched through the EventManager and can be consumed through multiple listener types.

Event flow

1

Gateway receives event

Discord sends an event through the WebSocket connection
2

Gateway handler processes

The gateway event handler converts the raw payload to a typed event
3

EventManager dispatches

The event is dispatched to all registered listeners
4

Listeners execute

Your event handler functions are called with the event data

Event listener types

DisGo provides three ways to listen for events:

Function listeners

The simplest approach is using typed functions:
import "github.com/disgoorg/disgo/events"

func handleMessage(event *events.MessageCreate) {
    log.Printf("Message from %s: %s", 
        event.Message.Author.Username,
        event.Message.Content,
    )
}

client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListenerFunc(handleMessage),
)

Channel listeners

For concurrent event processing:
messageChan := make(chan *events.MessageCreate, 100)

go func() {
    for event := range messageChan {
        // Process event
        processMessage(event)
    }
}()

client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListenerChan(messageChan),
)

Adapter listeners

For handling multiple event types in one structure:
import "github.com/disgoorg/disgo/events"

listener := &events.ListenerAdapter{
    OnMessageCreate: func(e *events.MessageCreate) {
        log.Println("Message created")
    },
    OnMessageUpdate: func(e *events.MessageUpdate) {
        log.Println("Message updated")
    },
    OnMessageDelete: func(e *events.MessageDelete) {
        log.Println("Message deleted")
    },
}

client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListeners(listener),
)

Common event types

Message events

func handleMessageCreate(e *events.MessageCreate) {
    // Access message data
    content := e.Message.Content
    author := e.Message.Author
    channelID := e.ChannelID
    
    // Get cached guild (if available)
    if e.GuildID != nil {
        guild, ok := e.Client().Caches.Guild(*e.GuildID)
    }
}

Guild events

OnGuildJoin: func(e *events.GuildJoin) {
    log.Printf("Joined guild: %s (%s)", e.Guild.Name, e.Guild.ID)
},

OnGuildUpdate: func(e *events.GuildUpdate) {
    log.Printf("Guild %s updated", e.Guild.ID)
},

OnGuildLeave: func(e *events.GuildLeave) {
    log.Printf("Left guild: %s", e.GuildID)
},

OnGuildReady: func(e *events.GuildReady) {
    log.Printf("Guild %s ready", e.GuildID)
},

Member events

OnGuildMemberJoin: func(e *events.GuildMemberJoin) {
    log.Printf("%s joined %s",
        e.Member.User.Username,
        e.GuildID,
    )
},

OnGuildMemberUpdate: func(e *events.GuildMemberUpdate) {
    // Check role changes
    addedRoles := difference(e.Member.RoleIDs, e.OldMember.RoleIDs)
    removedRoles := difference(e.OldMember.RoleIDs, e.Member.RoleIDs)
},

OnGuildMemberLeave: func(e *events.GuildMemberLeave) {
    log.Printf("%s left %s", e.User.Username, e.GuildID)
},

Interaction events

OnInteraction: func(e *events.InteractionCreate) {
    switch data := e.Interaction.Data.(type) {
    case discord.SlashCommandInteractionData:
        // Handle slash command
    case discord.ComponentInteractionData:
        // Handle button/select menu
    case discord.ModalSubmitInteractionData:
        // Handle modal submission
    }
},

OnApplicationCommandInteraction: func(e *events.ApplicationCommandInteractionCreate) {
    // Specifically for slash commands
},

OnComponentInteraction: func(e *events.ComponentInteractionCreate) {
    // Specifically for buttons and select menus
},

Event interface

All events implement the Event interface:
type Event interface {
    Client() *Client
    SequenceNumber() int
}
This gives you access to:
func handler(e *events.MessageCreate) {
    // Get the client instance
    client := e.Client()
    
    // Make REST API calls
    client.Rest.CreateMessage(...)
    
    // Access caches
    guild, _ := client.Caches.Guild(e.GuildID)
    
    // Get sequence number (for debugging)
    seq := e.SequenceNumber()
}

Dynamic listener management

You can add and remove listeners at runtime:
// Create a listener
listener := bot.NewListenerFunc(func(e *events.MessageCreate) {
    log.Println("Message:", e.Message.Content)
})

// Add it
client.AddEventListeners(listener)

// Remove it later
client.RemoveEventListeners(listener)

Custom event listener

Implement the EventListener interface for custom behavior:
type MyListener struct {
    messageCount int
}

func (l *MyListener) OnEvent(event bot.Event) {
    switch e := event.(type) {
    case *events.MessageCreate:
        l.messageCount++
        if l.messageCount%100 == 0 {
            log.Printf("Processed %d messages", l.messageCount)
        }
    case *events.Ready:
        log.Println("Bot is ready!")
    }
}

// Use it
client.AddEventListeners(&MyListener{})

Async event handling

By default, events are processed synchronously. Enable async processing:
import "github.com/disgoorg/disgo/bot"

client, err := disgo.New(token,
    bot.WithEventManagerConfigOpts(
        bot.WithAsyncEventsEnabled(true),
    ),
)
With async events enabled, your handlers run in goroutines. Ensure proper synchronization when accessing shared state.

Gateway lifecycle events

OnReady: func(e *events.Ready) {
    log.Printf("Logged in as %s", e.User.Username)
    log.Printf("Session ID: %s", e.SessionID)
},

OnResumed: func(e *events.Resumed) {
    log.Println("Session resumed")
},

OnGuildsReady: func(e *events.GuildsReady) {
    log.Printf("All guilds ready on shard %d", e.ShardID)
},

Raw events

Access raw gateway payloads:
import "github.com/disgoorg/disgo/gateway"

client, err := disgo.New(token,
    bot.WithGatewayConfigOpts(
        gateway.WithEnableRawEvents(true),
    ),
    bot.WithEventListenerFunc(func(e *events.Raw) {
        log.Printf("Raw event: %s", e.EventType)
    }),
)

Complete example

package main

import (
    "log"
    "strings"

    "github.com/disgoorg/disgo"
    "github.com/disgoorg/disgo/bot"
    "github.com/disgoorg/disgo/discord"
    "github.com/disgoorg/disgo/events"
    "github.com/disgoorg/disgo/gateway"
)

type Bot struct {
    client *bot.Client
}

func (b *Bot) onReady(e *events.Ready) {
    log.Printf("Bot ready: %s", e.User.Username)
}

func (b *Bot) onMessageCreate(e *events.MessageCreate) {
    // Ignore bots
    if e.Message.Author.Bot {
        return
    }

    // Handle commands
    if strings.HasPrefix(e.Message.Content, "!") {
        b.handleCommand(e)
    }
}

func (b *Bot) handleCommand(e *events.MessageCreate) {
    args := strings.Fields(e.Message.Content)
    if len(args) == 0 {
        return
    }

    switch args[0] {
    case "!ping":
        _, _ = e.Client().Rest.CreateMessage(
            e.ChannelID,
            discord.MessageCreate{Content: "Pong!"},
        )
    case "!info":
        if e.GuildID != nil {
            guild, ok := e.Client().Caches.Guild(*e.GuildID)
            if ok {
                _, _ = e.Client().Rest.CreateMessage(
                    e.ChannelID,
                    discord.MessageCreate{
                        Content: "Guild: " + guild.Name,
                    },
                )
            }
        }
    }
}

func main() {
    b := &Bot{}

    client, err := disgo.New("TOKEN",
        bot.WithDefaultGateway(),
        bot.WithGatewayConfigOpts(
            gateway.WithIntents(
                gateway.IntentGuilds,
                gateway.IntentGuildMessages,
                gateway.IntentMessageContent,
            ),
        ),
        bot.WithEventListeners(&events.ListenerAdapter{
            OnReady:         b.onReady,
            OnMessageCreate: b.onMessageCreate,
        }),
    )
    if err != nil {
        log.Fatal(err)
    }

    b.client = client

    // Connect and run
    // ...
}
Event handlers should be fast. For long-running operations, spawn a goroutine to avoid blocking the event loop.

Build docs developers (and LLMs) love