Table of Contents

Messages, Reactions, and Polls

This part of interactivity covers follow-up chat input, reaction-based confirmation, typing indicators, and lightweight polls.

Waiting for the next message

The quickest way to continue a conversation is waiting for the next message in the same channel. When you already have the user's original message, GetNextMessageAsync() is usually the most convenient entry point.

await ctx.RespondAsync("Reply with `confirm` to continue.");

var result = await ctx.Message.GetNextMessageAsync(
    m => string.Equals(m.Content, "confirm", StringComparison.OrdinalIgnoreCase),
    TimeSpan.FromSeconds(30));

if (result.TimedOut)
{
    await ctx.RespondAsync("You took too long.");
    return;
}

await ctx.RespondAsync("Confirmed.");

You can also wait from a channel directly:

var result = await ctx.Channel.GetNextMessageAsync(ctx.User, TimeSpan.FromSeconds(30));

Waiting for reactions

WaitForReactionAsync() is useful for small yes/no prompts or emoji-based confirmations.

var emoji = DiscordEmoji.FromUnicode("👌");
var message = await ctx.RespondAsync($"React with {emoji} to continue.");

var result = await message.WaitForReactionAsync(ctx.User, emoji, TimeSpan.FromSeconds(30));

if (!result.TimedOut)
    await ctx.RespondAsync("Thanks.");

Reaction waits require the appropriate reaction intents to be enabled.

Collecting reactions

If you want the final totals instead of the first valid input, use CollectReactionsAsync():

var message = await ctx.RespondAsync("Vote with reactions now.");
var reactions = await message.CollectReactionsAsync(TimeSpan.FromSeconds(20));

foreach (var reaction in reactions)
    await ctx.Channel.SendMessageAsync($"{reaction.Emoji}: {reaction.Total}");

Running a simple poll

DoPollAsync() adds the supplied emojis, waits until timeout, and returns the final counts.

var message = await ctx.RespondAsync("Which option do you want?");
var results = await message.DoPollAsync(
[
    DiscordEmoji.FromUnicode("1️⃣"),
    DiscordEmoji.FromUnicode("2️⃣"),
    DiscordEmoji.FromUnicode("3️⃣")
],
timeoutOverride: TimeSpan.FromSeconds(30));

foreach (var result in results)
    await ctx.Channel.SendMessageAsync($"{result.Emoji}: {result.Total}");

By default, poll reactions are deleted after the poll ends. Change InteractivityConfiguration.PollBehaviour to KeepEmojis if you want the reactions to stay visible.

Waiting for typing

Typing waits are useful when you want to know whether a user has started responding before the actual message arrives.

var typing = await ctx.Channel.WaitForUserTypingAsync(ctx.User, TimeSpan.FromSeconds(15));

if (!typing.TimedOut)
    await ctx.RespondAsync("I can see you typing...");

This feature requires typing intents.

Choosing the right entry point

Method Best for
GetNextMessageAsync() Chat-style follow-up prompts
WaitForReactionAsync() One reaction from one user
CollectReactionsAsync() Totals across a whole voting window
DoPollAsync() Quick reaction polls with automatic setup
WaitForUserTypingAsync() Detecting that a reply has started