Skip to main content
This example demonstrates how to listen for message events and log them to the console. It also shows how to handle message reactions.

Overview

The Message Logger bot will:
  • Log all messages from both guilds (servers) and direct messages
  • Display formatted output with server name, channel, author, and content
  • Handle message reactions (specifically the heart emoji)
  • Demonstrate channel type specialization

Setup

1

Configure Gateway Intents

To receive message events, you need to enable specific intents:
EnumSet<GatewayIntent> intents = EnumSet.of(
    // Enables MessageReceivedEvent for guild (also known as servers)
    GatewayIntent.GUILD_MESSAGES,
    // Enables the event for private channels (also known as direct messages)
    GatewayIntent.DIRECT_MESSAGES,
    // Enables access to message.getContentRaw()
    GatewayIntent.MESSAGE_CONTENT,
    // Enables MessageReactionAddEvent for guild
    GatewayIntent.GUILD_MESSAGE_REACTIONS,
    // Enables MessageReactionAddEvent for private channels
    GatewayIntent.DIRECT_MESSAGE_REACTIONS
);
The MESSAGE_CONTENT intent is a privileged intent. You need to enable it in the Discord Developer Portal under your bot’s settings.
2

Create the Event Listener

Extend ListenerAdapter to handle events:
public class MessageLoggerExample extends ListenerAdapter {
    public static final Emoji HEART = Emoji.fromUnicode("U+2764");

    @Override
    public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
        // Handle message events
    }

    @Override
    public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) {
        // Handle reaction events
    }
}
3

Register the Listener

Add your listener when building the JDA instance:
JDA jda = JDABuilder.createLight(token, intents)
    .addEventListeners(new MessageLoggerExample())
    .setActivity(Activity.watching("your messages"))
    .build();

Handling Message Events

The onMessageReceived method is called whenever a message is sent in a channel your bot can see:
@Override
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
    // The user who sent the message
    User author = event.getAuthor();
    // The channel where the message was sent
    MessageChannelUnion channel = event.getChannel();
    // The actual message
    Message message = event.getMessage();

    // Check whether the message was sent in a guild / server
    if (event.isFromGuild()) {
        String guildName = event.getGuild().getName();
        String printableContent = message.getContentDisplay();

        System.out.printf(
            "[%s] [%#s] %#s: %s\n",
            guildName,
            channel,    // The %#s makes use of the channel name
            author,     // The %#s makes use of User#getAsTag
            printableContent
        );
    } else {
        // This is a message from a private channel
        System.out.printf("[direct] %#s: %s\n", author, message.getContentDisplay());
    }
}
Use message.getContentDisplay() instead of getContentRaw() to convert mentions into readable text (e.g., @user instead of <@123456789>).

Channel Type Specialization

Channels use a “union” type system that allows you to specialize to more concrete types:
// Check if the channel is a text channel
if (channel.getType() == ChannelType.TEXT) {
    System.out.println("The channel topic is " + channel.asTextChannel().getTopic());
}

// Check if the channel is a thread
if (channel.getType().isThread()) {
    String channelName = channel.asThreadChannel()
        .getParentChannel()  // Get the parent channel
        .getName();

    System.out.println("This thread is part of channel #" + channelName);
}

Handling Reactions

You can listen for reaction events to detect when users react to messages:
public static final Emoji HEART = Emoji.fromUnicode("U+2764");

@Override
public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) {
    if (event.getEmoji().equals(HEART)) {
        System.out.println("A user loved a message!");
    }
}
Find Unicode codepoints for emojis at Emojipedia. For example, the red heart is U+2764.

Complete Example

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.requests.GatewayIntent;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.EnumSet;

import javax.annotation.Nonnull;

public class MessageLoggerExample extends ListenerAdapter {
    public static final Emoji HEART = Emoji.fromUnicode("U+2764");

    public static void main(String[] args) throws IOException {
        String token = new String(Files.readAllBytes(Paths.get(args[0])), StandardCharsets.UTF_8).trim();

        EnumSet<GatewayIntent> intents = EnumSet.of(
            GatewayIntent.GUILD_MESSAGES,
            GatewayIntent.DIRECT_MESSAGES,
            GatewayIntent.MESSAGE_CONTENT,
            GatewayIntent.GUILD_MESSAGE_REACTIONS,
            GatewayIntent.DIRECT_MESSAGE_REACTIONS
        );

        try {
            JDA jda = JDABuilder.createLight(token, intents)
                .addEventListeners(new MessageLoggerExample())
                .setActivity(Activity.watching("your messages"))
                .build();

            jda.getRestPing().queue(ping ->
                System.out.println("Logged in with ping: " + ping)
            );

            jda.awaitReady();
            System.out.println("Guilds: " + jda.getGuildCache().size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
        User author = event.getAuthor();
        MessageChannelUnion channel = event.getChannel();
        Message message = event.getMessage();

        if (event.isFromGuild()) {
            String guildName = event.getGuild().getName();
            String printableContent = message.getContentDisplay();

            System.out.printf(
                "[%s] [%#s] %#s: %s\n",
                guildName,
                channel,
                author,
                printableContent
            );
        } else {
            System.out.printf("[direct] %#s: %s\n", author, message.getContentDisplay());
        }

        if (channel.getType() == ChannelType.TEXT) {
            System.out.println("The channel topic is " + channel.asTextChannel().getTopic());
        }

        if (channel.getType().isThread()) {
            String channelName = channel.asThreadChannel()
                .getParentChannel()
                .getName();
            System.out.println("This thread is part of channel #" + channelName);
        }
    }

    @Override
    public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) {
        if (event.getEmoji().equals(HEART)) {
            System.out.println("A user loved a message!");
        }
    }
}

Sample Output

When running, you’ll see output like:
Logged in with ping: 42
Guilds: 3
[My Server] [#general] User#1234: Hello world!
[My Server] [#general] Bot#5678: Hi there!
[direct] Friend#9012: Hey!
A user loved a message!

Build docs developers (and LLMs) love