---
title: "Discord bot polls: native poll, reactions or buttons | StreetHosting"
description: "Create Discord polls with discord.js v14: use the native poll field, compare it with reactions and buttons, enforce a single vote and read the result."
url: "https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting"
type: "page"
language: "en-US"
---

Discord Bots · 7 min · Intermediate

Published on Nov 13, 2026 · Updated on Nov 13, 2026

# Polls and voting on Discord with a bot: which format to choose

Discord has a native poll and the bot can send it with one field on the message. Learn when it is enough, when reactions or buttons make more sense, how to limit to one vote and how to read the result.

By [Equipe StreetHosting](https://streethosting.com.br/en/autores#equipe-streethosting) · StreetHosting infrastructure and support team

[Automation and webhooks](https://streethosting.com.br/en/guides/topics/automation) [Costs, plans and billing](https://streethosting.com.br/en/guides/topics/costs)

Summarize with:

[](https://chat.openai.com/?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "ChatGPT") [](https://claude.ai/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Claude") [](https://www.google.com/search?udm=50&aep=11&q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Google AI Mode") [](https://x.com/i/grok?text=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Grok") [](https://www.perplexity.ai/search/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Perplexity")

Share:

[](https://x.com/intent/tweet?text=Discord%20bot%20polls%3A%20native%20poll%2C%20reactions%20or%20buttons&url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting "Share on X") [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting "Share on Facebook") [](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting "Share on LinkedIn") [](https://wa.me/?text=Discord%20bot%20polls%3A%20native%20poll%2C%20reactions%20or%20buttons%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-bot-polls-voting "Share on WhatsApp")

For agents: Copy as Markdown [.md](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting.md)

In this guide 7 sections

* [Native poll, reactions or buttons](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#tres-formatos)
* [Send the native poll from the bot](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#enquete-nativa)
* [Read the result and end early](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#ler-resultado)
* [Poll with reactions](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#reacoes)
* [Poll with buttons](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#botoes)
* [Details that make a vote work](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#cuidados)
* [Where to run this on StreetHosting](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#onde-rodar)

Quick answer

For a simple vote, send the native poll: in discord.js v14 you just pass `poll` to `channel.send()`, with a question, answers and a `duration` in hours. Discord counts the votes and guarantees a single vote with `allowMultiselect: false`. Use reactions or buttons only when you need your own rules, such as voting by role.

## Native poll, reactions or buttons[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#tres-formatos)

Before the native poll existed, every bot ran votes with reactions. Today there are three paths, and each one solves a different problem.

|                         | Native poll                        | Reactions                                       | Buttons                  |
| ----------------------- | ---------------------------------- | ----------------------------------------------- | ------------------------ |
| Who counts the votes    | Discord                            | You, by reading the reactions                   | You, in your database    |
| Single vote             | Yes, through the poll's own option | Only with code that removes the other reactions | Yes, with a key per user |
| Duration                | Set at creation and ends by itself | You have to schedule it                         | You have to schedule it  |
| Rules by role or weight | No                                 | Hard                                            | Yes                      |
| Maximum options         | 10                                 | Limited by the reactions on a message           | 25 buttons               |
| Coding effort           | Low                                | Medium                                          | Higher                   |

When in doubt, start with the native poll. It already has a progress bar, a live count, automatic ending and works on mobile with nothing extra. Reactions are for the improvised quick question, and buttons come in when the vote has to follow a rule of your server.

## Send the native poll from the bot[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#enquete-nativa)

The `poll` field exists in current discord.js v14 versions. If your project is old, run `npm install discord.js@latest` first. The bot also needs the **Send Polls** permission in the channel, on top of viewing the channel and sending messages.

The example below is an `/enquete` command with the question, the options separated by semicolons, the duration and the multiple choice option:

`` const { SlashCommandBuilder, MessageFlags } = require('discord.js'); const enquete = new SlashCommandBuilder() .setName('enquete') .setDescription('Cria uma enquete neste canal') .addStringOption((o) => o.setName('pergunta').setDescription('A pergunta').setMaxLength(300).setRequired(true) ) .addStringOption((o) => o.setName('opcoes').setDescription('Opções separadas por ponto e vírgula').setRequired(true) ) .addIntegerOption((o) => o.setName('horas').setDescription('Duração em horas').setMinValue(1).setMaxValue(168) ) .addBooleanOption((o) => o.setName('multipla').setDescription('Permitir mais de uma resposta') ); // in the interactionCreate handler if (interaction.commandName === 'enquete') { const pergunta = interaction.options.getString('pergunta', true); const opcoes = interaction.options .getString('opcoes', true) .split(';') .map((t) => t.trim()) .filter(Boolean); if (opcoes.length < 2 || opcoes.length > 10 || opcoes.some((t) => t.length > 55)) { return interaction.reply({ content: 'Use de 2 a 10 opções, com até 55 caracteres cada.', flags: MessageFlags.Ephemeral, }); } const mensagem = await interaction.channel.send({ poll: { question: { text: pergunta }, answers: opcoes.map((text) => ({ text })), duration: interaction.options.getInteger('horas') ?? 24, // in hours allowMultiselect: interaction.options.getBoolean('multipla') ?? false, }, }); await interaction.reply({ content: `Enquete criada. ID da mensagem: ${mensagem.id}`, flags: MessageFlags.Ephemeral, }); } ``

The limits Discord imposes: a question of up to 300 characters, at most 10 answers of up to 55 characters each, and a duration in hours, from 1 up to 768 (32 days). Each answer also accepts an emoji, in the `emoji` field next to the text. Once sent, the poll cannot be edited.

To register the command and understand the handler, see [creating a Discord bot with slash commands](https://streethosting.com.br/en/guides/discord-bots/create-discord-bot-slash-commands).

## Read the result and end early[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#ler-resultado)

When the time is up, Discord closes the poll and posts the result in the channel. If your bot needs the numbers (to give a reward, open a discussion or record them in a database), fetch the message and read the `poll` object:

`async function lerResultado(canal, idDaMensagem) { const mensagem = await canal.messages.fetch(idDaMensagem); const poll = mensagem.poll; if (!poll) return null; const respostas = poll.answers.map((r) => ({ texto: r.text, votos: r.voteCount })); const total = respostas.reduce((soma, r) => soma + r.votos, 0); return { pergunta: poll.question.text, final: poll.resultsFinalized, // true once the count is closed total, respostas: respostas.sort((a, b) => b.votos - a.votos), }; } // end before the deadline (only works on polls sent by the bot itself) await mensagem.poll.end(); // who voted for an answer const resposta = mensagem.poll.answers.first(); const votantes = await resposta.fetchVoters({ limit: 100 });`

While the poll is open, Discord's count is approximate. The `resultsFinalized` field tells you when the number is final, so only save the result to the database after it is `true`.

To react to each vote in real time, turn on the `GuildMessagePolls` intent on the client and listen to `Events.MessagePollVoteAdd` and `Events.MessagePollVoteRemove`. It is not a privileged intent, so it needs no approval in the portal. If your bot only sends the poll and reads the result at the end, it does not need this intent.

Store the poll message ID in your database along with the reason for the poll. That ID is how you come back later, even if the bot restarted, to read the final result.

## Poll with reactions[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#reacoes)

The classic format: the bot sends a message and adds one reaction per option. Each person votes by clicking a reaction. It is the quickest way to ask a question with no structure at all:

`` const NUMEROS = ['1\uFE0F\u20E3', '2\uFE0F\u20E3', '3\uFE0F\u20E3', '4\uFE0F\u20E3', '5\uFE0F\u20E3']; async function enqueteReacoes(canal, pergunta, opcoes) { const linhas = opcoes.map((texto, i) => `${NUMEROS[i]} ${texto}`); const mensagem = await canal.send(`**${pergunta}**\n\n${linhas.join('\n')}`); for (let i = 0; i < opcoes.length; i++) { await mensagem.react(NUMEROS[i]); } return mensagem; } ``

The cost shows up when you want a single vote. Discord does not stop a person from adding two reactions, so the bot has to listen to `messageReactionAdd`, find the same user's other reactions on the message and remove each one. That requires the `GuildMessageReactions` intent, partials for old messages and several API calls for every vote. There is also no deadline: you have to schedule the ending yourself.

Reactions as a vote are easy to manipulate. Anyone allowed to add reactions can vote for several options if the bot goes down, and the bot does not see what happened while it was offline. For anything that really counts, prefer the native poll or buttons with a record in the database.

## Poll with buttons[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#botoes)

Buttons give you full control. You decide who can vote, store each vote in your own database and choose how to show the result. The design is simple: each button carries the option in its `customId` and a table with a primary key per message and user guarantees a single vote.

`` const Database = require('better-sqlite3'); const { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, MessageFlags } = require('discord.js'); const db = new Database('dados.db'); db.exec(`CREATE TABLE IF NOT EXISTS votos ( mensagem_id TEXT NOT NULL, user_id TEXT NOT NULL, opcao INTEGER NOT NULL, PRIMARY KEY (mensagem_id, user_id) )`); const votar = db.prepare(`INSERT INTO votos (mensagem_id, user_id, opcao) VALUES (?, ?, ?) ON CONFLICT (mensagem_id, user_id) DO UPDATE SET opcao = excluded.opcao`); const contar = db.prepare('SELECT opcao, COUNT(*) AS n FROM votos WHERE mensagem_id = ? GROUP BY opcao'); function montarEmbed(pergunta, opcoes, mensagemId) { const contagem = Object.fromEntries(contar.all(mensagemId).map((l) => [l.opcao, l.n])); const linhas = opcoes.map((texto, i) => `**${texto}**: ${contagem[i] ?? 0} voto(s)`); return new EmbedBuilder().setTitle(pergunta).setDescription(linhas.join('\n')); } // buttons: customId = voto:<opcao> function montarBotoes(opcoes) { const linha = new ActionRowBuilder().addComponents( opcoes.slice(0, 5).map((texto, i) => new ButtonBuilder().setCustomId(`voto:${i}`).setLabel(texto).setStyle(ButtonStyle.Primary) ) ); return [linha]; } // in the interactionCreate handler if (interaction.isButton() && interaction.customId.startsWith('voto:')) { const opcao = Number(interaction.customId.split(':')[1]); votar.run(interaction.message.id, interaction.user.id, opcao); // the options and the question come from the original embed or from a table of yours await interaction.update({ embeds: [montarEmbed(PERGUNTA, OPCOES, interaction.message.id)] }); } ``

A repeated vote swaps the choice instead of adding up, and the count comes straight from the database, so a restart wipes nothing. To limit by role, check `interaction.member.roles.cache.has(ID)` before saving. Each row of buttons holds 5 buttons and a message has up to 5 rows, 25 in total. To end the poll, swap the buttons for a disabled version and store the result. The guide on [interactive buttons and menus](https://streethosting.com.br/en/guides/discord-bots/discord-bot-buttons-select-menus) covers that life cycle in detail.

* Use the native poll for an open question, like the next event.
* Use buttons for votes that count for something, like electing a moderator with a minimum role.
* Use reactions only for the everyday improvised vote.

If you collect ideas from members over time, you can combine this with the [suggestions system](https://streethosting.com.br/en/guides/discord-bots/discord-suggestion-system-bot), letting the most voted ones become a poll.

## Details that make a vote work[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#cuidados)

A few details separate a poll that works from one that causes complaints in the server.

* **Limit who can create polls.** Use `setDefaultMemberPermissions` on the command or check a role before sending. Without that, anyone can flood the channel with polls.
* **Pick the right channel.** The bot creates the poll in the channel where the command was used. If you want a fixed voting channel, fetch the channel by ID and send there, checking first that the bot has Send Polls in it. Channel permissions can deny what the server allows.
* **Think about the duration.** For everyday decisions, 24 hours is enough. For something that involves the whole community, give it about 3 to 7 days, so people who rarely open Discord can vote.
* **Announce the result.** Discord already posts the result when the time is up, but a bot that reads the result and replies with the winner, mentioning an announcements role, gives the closure people expect.
* **Handle errors.** If the command fails for lack of permission, say so clearly instead of leaving the interaction unanswered. Discord gives only 3 seconds for the first reply; use `deferReply()` if processing takes longer.

That covers the most common cases. If a vote has to be auditable, like electing a moderator, store the votes in your database with buttons, because the native poll shows who voted but does not let you impose eligibility rules.

## Where to run this on StreetHosting[](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#onde-rodar)

The native poll needs nothing special: the bot only has to be on when someone uses the command. For buttons and vote events, it has to stay online all the time. On [StreetHosting bot hosting](https://streethosting.com.br/en/bots) you upload the Node.js code to a container with a panel, and the Discord Essential plan costs R$ 9.99 per month, with 1 GB of RAM, 2 GB of NVMe and a MariaDB database to store the votes. A polls bot is light and fits that plan with room to spare.

In this guide

* [Native poll, reactions or buttons](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#tres-formatos)
* [Send the native poll from the bot](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#enquete-nativa)
* [Read the result and end early](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#ler-resultado)
* [Poll with reactions](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#reacoes)
* [Poll with buttons](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#botoes)
* [Details that make a vote work](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#cuidados)
* [Where to run this on StreetHosting](https://streethosting.com.br/en/guides/discord-bots/discord-bot-polls-voting#onde-rodar)

## Frequently asked questions

Can the bot create Discord's native poll?

Yes. In the current discord.js v14, a message accepts the poll field, with a question, answers, a duration in hours and the multiple choice option. The bot needs the Send Polls permission in the channel. Older versions of the library do not know this field, so update the package.

Can I edit a poll after it is sent?

No. The question, answers and duration are fixed. What you can do is end it early with poll.end(), if the bot sent the poll, or create another one.

How do I guarantee one vote per person?

On the native poll, leave allowMultiselect as false and Discord itself blocks more than one answer. With reactions, the bot has to remove the user's other reactions. With buttons, a primary key per message and user in the database does it.

What is the maximum duration of the native poll?

The duration is given in hours and Discord accepts from 1 hour up to 768 hours, which is 32 days. If you leave it out, the default is 24 hours.

When should I prefer buttons over the native poll?

When you need rules the native poll does not offer: votes only from people with a certain role, votes with different weights, a result hidden until the end or a record of the votes in your own database.

Next step

See bot plans

24/7 Discord bots with fast activation and support in Portuguese.

[See bot plans](https://streethosting.com.br/en/bots)

## Related guides

[Discord bots Intermediate Buttons and select menus in a Discord bot with discord.js v14 Learn to build ButtonBuilder and StringSelectMenuBuilder, read the customId in interactionCreate, meet the 3 second deadline, choose between a collector and a global handler and disable used buttons. 7 min Read guide](https://streethosting.com.br/en/guides/discord-bots/discord-bot-buttons-select-menus) [Discord bots Intermediate Discord suggestion system with voting, approval and a thread An organized suggestions channel: the person uses /suggest, the bot posts an embed with vote buttons, opens a thread for the conversation and staff approve or reject with a reason, changing the embed color. 7 min Read guide](https://streethosting.com.br/en/guides/discord-bots/discord-suggestion-system-bot) [Discord bots Beginner How to run giveaways on Discord with a giveaway bot Giveaways drive engagement and grow a community when they are fair. Here is how to set up a giveaway bot with a prize, deadline and requirements, and how to cut down on alt-account fraud. 3 min Read guide](https://streethosting.com.br/en/guides/discord-bots/discord-giveaway-bot)

[← Back to the Guide Center](https://streethosting.com.br/en/guides)
