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.

Event handling is how your bot responds to things happening in Discord - messages being sent, users joining servers, reactions being added, and much more.

Adding event listeners

DisGo provides three ways to listen for events:

Function listeners

The simplest approach for single event types:
client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListenerFunc(func(event *events.MessageCreate) {
        // Handle message creation
    }),
)

Channel listeners

Useful for concurrent event processing:
func eventListenerChan() chan<- *events.MessageCreate {
    c := make(chan *events.MessageCreate)
    go func() {
        defer close(c)
        for event := range c {
            if event.Message.Content == "ping" {
                _, _ = event.Client().Rest.CreateMessage(
                    event.ChannelID,
                    discord.MessageCreate{Content: "pong"},
                )
            }
        }
    }()
    return c
}

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

Adapter listeners

Best for handling multiple event types in one place:
type BotEventListener struct{}

func (l *BotEventListener) OnMessageCreate(event *events.MessageCreate) {
    // Handle message creation
}

func (l *BotEventListener) OnReactionAdd(event *events.MessageReactionAdd) {
    // Handle reaction add
}

client, err := disgo.New(token,
    bot.WithDefaultGateway(),
    bot.WithEventListeners(&BotEventListener{}),
)

Common events

Here are the most commonly used events:

Message events

func(event *events.MessageCreate) {
    if event.Message.Author.Bot {
        return
    }
    // Handle new message
}

Interaction events

func(event *events.ApplicationCommandInteractionCreate) {
    data := event.SlashCommandInteractionData()
    // Handle slash command
}

Guild events

func(event *events.GuildMemberJoin) {
    // Welcome new member
}

Reaction events

func(event *events.MessageReactionAdd) {
    // Handle reaction added
}

Complete event handling example

package main

import (
    "context"
    "log/slog"
    "os"
    "os/signal"
    "syscall"

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

var token = os.Getenv("disgo_token")

func main() {
    client, err := disgo.New(token,
        bot.WithDefaultGateway(),
        bot.WithEventListenerFunc(onMessageCreate),
        bot.WithEventListeners(&events.ListenerAdapter{
            OnMessageCreate: onMessageCreate,
            OnReady:         onReady,
            OnGuildMemberJoin: onGuildMemberJoin,
        }),
    )
    if err != nil {
        slog.Error("error while building disgo instance", slog.Any("err", err))
        return
    }

    defer client.Close(context.TODO())

    if err = client.OpenGateway(context.TODO()); err != nil {
        slog.Error("error while connecting to gateway", slog.Any("err", err))
    }

    slog.Info("bot is now running. Press CTRL-C to exit.")
    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
    <-s
}

func onReady(event *events.Ready) {
    slog.Info("Bot is ready!", slog.String("user", event.User.Tag()))
}

func onMessageCreate(event *events.MessageCreate) {
    if event.Message.Author.Bot {
        return
    }
    
    if event.Message.Content == "ping" {
        _, _ = event.Client().Rest.CreateMessage(
            event.ChannelID,
            discord.MessageCreate{Content: "pong"},
        )
    }
}

func onGuildMemberJoin(event *events.GuildMemberJoin) {
    slog.Info("New member joined",
        slog.String("user", event.User.Tag()),
        slog.String("guild", event.GuildID.String()),
    )
}

Gateway intents

To receive events, you need to enable the appropriate gateway intents:
import "github.com/disgoorg/disgo/gateway"

client, err := disgo.New(token,
    bot.WithGatewayConfigOpts(
        gateway.WithIntents(
            gateway.IntentGuilds,           // Guild events
            gateway.IntentGuildMessages,    // Message events
            gateway.IntentMessageContent,   // Access to message content
            gateway.IntentGuildMembers,     // Member events
            gateway.IntentGuildMessageReactions, // Reaction events
        ),
    ),
)
Some intents like IntentGuildMembers and IntentMessageContent are privileged and require approval in the Discord Developer Portal for verified bots.

Event filtering

Filter events to only handle relevant ones:
func onMessageCreate(event *events.MessageCreate) {
    // Ignore bots
    if event.Message.Author.Bot {
        return
    }
    
    // Only handle DMs
    if event.GuildID == nil {
        return
    }
    
    // Only handle specific channels
    if event.ChannelID != myChannelID {
        return
    }
    
    // Handle the event
}

The Ready event

The Ready event fires when your bot successfully connects:
func onReady(event *events.Ready) {
    slog.Info("Logged in as", slog.String("tag", event.User.Tag()))
    slog.Info("Connected to", slog.Int("guilds", len(event.Guilds)))
    
    // Set bot activity
    client.SetPresence(context.TODO(),
        gateway.WithPlayingActivity("with DisGo"),
        gateway.WithOnlineStatus(discord.OnlineStatusOnline),
    )
}

Error handling in events

Always handle errors properly in event listeners:
func onMessageCreate(event *events.MessageCreate) {
    _, err := event.Client().Rest.CreateMessage(
        event.ChannelID,
        discord.MessageCreate{Content: "Hello!"},
    )
    if err != nil {
        event.Client().Logger.Error(
            "failed to send message",
            slog.Any("err", err),
            slog.String("channel", event.ChannelID.String()),
        )
    }
}

Accessing the client

You can access the bot client from any event:
func onMessageCreate(event *events.MessageCreate) {
    client := event.Client()
    
    // Access REST API
    client.Rest.CreateMessage(...)
    
    // Access cache
    guild, ok := client.Caches.Guild(event.GuildID)
    
    // Access logger
    client.Logger.Info("Processing message")
}

Using the handler package

The handler package provides organized routing for events:
import "github.com/disgoorg/disgo/handler"

r := handler.New()
r.SlashCommand("/ping", handlePing)
r.Component("/button/{id}", handleButton)
r.Modal("/modal", handleModal)

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

Event listener order

Event listeners are called in the order they’re registered:
client, err := disgo.New(token,
    bot.WithEventListenerFunc(firstListener),  // Called first
    bot.WithEventListenerFunc(secondListener), // Called second
    bot.WithEventListenerFunc(thirdListener),  // Called third
)

Available events

Here’s a comprehensive list of available events:
  • Ready - Bot connected to gateway
  • MessageCreate - New message created
  • MessageUpdate - Message edited
  • MessageDelete - Message deleted
  • ApplicationCommandInteractionCreate - Slash command used
  • ComponentInteractionCreate - Button/select menu clicked
  • ModalSubmitInteractionCreate - Modal submitted
  • GuildMemberJoin - Member joined guild
  • GuildMemberLeave - Member left guild
  • GuildMemberUpdate - Member updated (roles, nickname, etc.)
  • MessageReactionAdd - Reaction added to message
  • MessageReactionRemove - Reaction removed from message
  • VoiceStateUpdate - Voice state changed
  • ChannelCreate - Channel created
  • ChannelUpdate - Channel updated
  • ChannelDelete - Channel deleted
  • GuildCreate - Guild became available
  • GuildUpdate - Guild updated
  • GuildDelete - Guild became unavailable
See the events package documentation for the complete list of available events.

Best practices

  • Filter early: Return early from event handlers for irrelevant events
  • Handle errors: Always log errors from API calls
  • Don’t block: Keep event handlers fast; use goroutines for long-running tasks
  • Use appropriate intents: Only request the intents you need
  • Type assertions: Use type assertions carefully when handling generic events
  • Context timeouts: Use contexts with timeouts for API calls

Next steps

Build docs developers (and LLMs) love