---
title: "Member count voice channel on Discord: how to build it with a bot | StreetHosting"
description: "Build a voice channel showing Members: 1,234 in discord.js v14: the GuildMembers intent, the 2 renames per 10 minutes limit and no join permission."
url: "https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel"
type: "page"
language: "en-US"
---

Discord Bots · 8 min · Intermediate

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

# Member counter in a voice channel: a bot that updates the name by itself

A stats channel shows the member total in the name of a voice channel nobody can join. The trick is Discord's rename limit, which only allows 2 changes per 10 minutes per channel.

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)

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-member-count-voice-channel.%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-member-count-voice-channel.%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-member-count-voice-channel.%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-member-count-voice-channel.%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-member-count-voice-channel.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Perplexity")

Share:

[](https://x.com/intent/tweet?text=Member%20count%20voice%20channel%20on%20Discord%3A%20how%20to%20build%20it%20with%20a%20bot&url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-member-count-voice-channel "Share on X") [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-member-count-voice-channel "Share on Facebook") [](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-member-count-voice-channel "Share on LinkedIn") [](https://wa.me/?text=Member%20count%20voice%20channel%20on%20Discord%3A%20how%20to%20build%20it%20with%20a%20bot%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fdiscord-bots%2Fdiscord-member-count-voice-channel "Share on WhatsApp")

For agents: Copy as Markdown [.md](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel.md)

In this guide 6 sections

* [How the counter works](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#como-funciona)
* [The GuildMembers intent](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#intent-guildmembers)
* [Create the channel nobody can join](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#criar-canal)
* [The limit of 2 renames per 10 minutes](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#limite-renomeacao)
* [A scheduled update that respects the limit](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#atualizacao-agendada)
* [Where to run this on StreetHosting](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#onde-rodar)

Quick answer

Create a voice channel with the Connect permission denied for @everyone, store its ID and run a routine every 6 minutes that compares the current name with "Membros: {n}" and only calls `channel.setName()` if the number changed. Discord accepts only 2 renames per 10 minutes per channel, so do not rename on every member join. The plain total comes from `guild.memberCount`.

## How the counter works[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#como-funciona)

The stats channel is an ordinary voice channel whose name the bot changes. It shows up in the list, near the top, with text like "Membros: 1.234". Because it is a voice channel, the name is always visible in the sidebar, and because nobody can join it, it works only as a display.

There are three pieces:

* The channel, created once, with permissions that block joining.
* The count, which comes from `guild.memberCount` or from the member cache.
* The scheduled routine that updates the name without passing Discord's limit.

The third piece is where almost every tutorial goes wrong: updating the name on every join and leave event sounds logical and breaks on a large server or during a raid, as you will see below.

## The GuildMembers intent[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#intent-guildmembers)

In discord.js v14 you declare the intents on the client. `GuildMembers` is privileged and has to be turned on in the developer portal, under Bot, Privileged Gateway Intents, Server Members Intent. Without it, the bot fails to connect and returns the disallowed intents error, covered in the guide on [privileged intents errors](https://streethosting.com.br/en/guides/discord-bots/discord-bot-disallowed-intents-error).

`const { Client, GatewayIntentBits } = require('discord.js'); const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers], });`

It is worth knowing when it is really needed. The member total, bots included, is in `guild.memberCount`, but the intent is what keeps that number current: without it, the bot receives no joins or leaves, and the value stays frozen at the moment it connected. If you do not want the intent, call `guild.fetch()` before each update and use `approximateMemberCount`, which is approximate. The intent becomes mandatory when you want to count only people (no bots), count who has a role, or listen to `guildMemberAdd` and `guildMemberRemove`. Once the bot reaches 100 servers, it has to go through Discord's verification, and from then on privileged intents depend on approval.

With the intent on, discord.js keeps the member cache updated with joins and leaves. To count only humans, fetch the members once at startup and then count from the cache:

`// contagem.js async function prepararCache(guild) { await guild.members.fetch(); // once, at startup } function contarMembros(guild, semBots) { if (!semBots) return guild.memberCount; return guild.members.cache.filter((m) => !m.user.bot).size; } // formats as Membros: 1.234 function formatarNome(modelo, numero) { return modelo.replace('{n}', numero.toLocaleString('pt-BR')); } module.exports = { prepararCache, contarMembros, formatarNome };`

`toLocaleString('pt-BR')` adds the thousands separator by itself. On very large servers, a full `members.fetch()` is slow and uses memory. If that is your case and you only need the total, stick with `memberCount` and skip the fetch.

## Create the channel nobody can join[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#criar-canal)

The setting that turns a voice channel into a display is a permission denial. The @everyone role keeps **View Channel** and loses **Connect**. The result is a visible channel, with the lock icon, that nobody can join:

`const { ChannelType, PermissionFlagsBits } = require('discord.js'); const { contarMembros, formatarNome } = require('./contagem'); async function criarCanalContador(guild, modelo, semBots) { const canal = await guild.channels.create({ name: formatarNome(modelo, contarMembros(guild, semBots)), type: ChannelType.GuildVoice, permissionOverwrites: [ { id: guild.roles.everyone.id, allow: [PermissionFlagsBits.ViewChannel], deny: [PermissionFlagsBits.Connect], }, ], reason: 'Canal de contador de membros', }); // puts it at the top of the list await canal.setPosition(0).catch(() => {}); return canal; }`

The bot needs the **Manage Channels** permission on the server to create and rename. It does not need to join the channel. If you want to be extra safe, also deny `Speak` and `Stream`, but denying `Connect` alone is enough. Moderation roles with administrator permission can still join, which is expected.

Store the channel ID. Losing it means recreating the channel and leaving the old one behind. A simple SQLite table solves it, and the `/contador criar` command just calls the function above and saves the result:

`` const Database = require('better-sqlite3'); const db = new Database('dados.db'); db.exec(` CREATE TABLE IF NOT EXISTS contadores ( guild_id TEXT PRIMARY KEY, channel_id TEXT NOT NULL, modelo TEXT NOT NULL, sem_bots INTEGER NOT NULL DEFAULT 0 ) `); const salvar = db.prepare( 'INSERT OR REPLACE INTO contadores (guild_id, channel_id, modelo, sem_bots) VALUES (?, ?, ?, ?)' ); const todos = db.prepare('SELECT * FROM contadores'); const remover = db.prepare('DELETE FROM contadores WHERE guild_id = ?'); // in the /contador criar handler (command with setDefaultMemberPermissions(ManageChannels)) const canal = await criarCanalContador(interaction.guild, 'Membros: {n}', false); salvar.run(interaction.guildId, canal.id, 'Membros: {n}', 0); await interaction.reply({ content: 'Canal criado.', flags: MessageFlags.Ephemeral }); ``

## The limit of 2 renames per 10 minutes[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#limite-renomeacao)

Discord limits a channel name change to **2 times every 10 minutes per channel**. It is a tighter limit than the other routes, and it is per channel: renaming another channel does not use up this one's balance.

The classic mistake is wiring the rename straight to the events:

`` // DO NOT do this client.on('guildMemberAdd', (m) => canal.setName(`Membros: ${m.guild.memberCount}`)); client.on('guildMemberRemove', (m) => canal.setName(`Membros: ${m.guild.memberCount}`)); ``

On a busy server dozens of people join and leave every minute, and in a raid hundreds join. Each event triggers a rename, the first two go through and all the others hit the limit. By default discord.js holds the request until the window frees up, so the calls stay stacked for minutes, and the channel name only shows a number from ten minutes ago. Worse: the backlog uses memory and the bot can end up with a queue full of requests that no longer make sense.

Do not try to get around the limit with several channels or by retrying in a loop. Pushing on limited routes raises the risk of the bot being temporarily blocked for too many requests. See how the 429 works in [fixing the Discord 429 rate limit](https://streethosting.com.br/en/guides/discord-bots/fix-discord-429-rate-limit).

## A scheduled update that respects the limit[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#atualizacao-agendada)

The solution is to decouple: the events rename nothing, and a routine with a fixed interval checks the number and renames only if it changed. A 6 minute interval guarantees at most 2 renames in any 10 minute window, and the comparison avoids spending a call when the number did not change:

`` // atualizador.js const { contarMembros, formatarNome, prepararCache } = require('./contagem'); const INTERVALO = 6 * 60 * 1000; // 6 minutes let rodando = false; async function atualizarTodos(client, db) { if (rodando) return; rodando = true; try { for (const linha of db.todos.all()) { const guild = client.guilds.cache.get(linha.guild_id); if (!guild) continue; try { const canal = await guild.channels.fetch(linha.channel_id).catch((err) => { if (err.code === 10003) return null; // 10003 = channel deleted throw err; // temporary error: try again next round }); if (!canal) { db.remover.run(linha.guild_id); // channel deleted: stop trying continue; } const nome = formatarNome(linha.modelo, contarMembros(guild, !!linha.sem_bots)); if (canal.name !== nome) { await canal.setName(nome, 'Atualização do contador de membros'); } } catch (err) { console.error(`Falha ao atualizar o contador de ${guild.name}:`, err); } } } finally { rodando = false; } } async function iniciarContador(client, db) { for (const guild of client.guilds.cache.values()) { await prepararCache(guild).catch((err) => console.error('Cache de membros:', err)); } await atualizarTodos(client, db); setInterval(() => atualizarTodos(client, db), INTERVALO); } module.exports = { iniciarContador }; ``

Call `iniciarContador(client, { todos, remover })` in `Events.ClientReady`. The limit is per channel, and each server has its own, so the routine serves several servers with no problem. If the bot restarts many times in a row, the first update of each start also counts toward the limit, and Discord simply delays the request until it frees up.

Want a number that moves faster? You can't. The limit belongs to Discord, and no bot gets past it. If the server grows so much that a 6 minute delay bothers you, accept the delay or show the number in a pinned message, which has a much looser limit. The join events are still useful for other things, such as [welcome messages](https://streethosting.com.br/en/guides/discord-bots/discord-welcome-message-bot), and the same scheduling idea applies to [managing temporary voice channels](https://streethosting.com.br/en/guides/discord-bots/discord-temporary-voice-channels-bot).

Other stats follow the same mold: number of bots, channels or members with a role. Each one is a separate channel, with its own rename quota, and the same routine serves all of them. For who is online, use the `approximatePresenceCount` that comes from `guild.fetch()`: it is an estimate, but it skips the presence intent, which is much heavier and privileged.

## Where to run this on StreetHosting[](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#onde-rodar)

The counter only updates while the bot is on, and since the members intent keeps a cache in memory, it is worth choosing a plan with spare RAM. On [StreetHosting bot hosting](https://streethosting.com.br/en/bots) your Node.js code runs in a container with a panel. The Discord Essential plan, at R$ 9.99 per month, brings 1 GB of RAM and 2 GB of NVMe, enough for the counter on small and medium servers. If the bot looks after several large servers, Discord Advanced, at R$ 19.99, doubles the RAM to 2 GB.

In this guide

* [How the counter works](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#como-funciona)
* [The GuildMembers intent](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#intent-guildmembers)
* [Create the channel nobody can join](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#criar-canal)
* [The limit of 2 renames per 10 minutes](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#limite-renomeacao)
* [A scheduled update that respects the limit](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#atualizacao-agendada)
* [Where to run this on StreetHosting](https://streethosting.com.br/en/guides/discord-bots/discord-member-count-voice-channel#onde-rodar)

## Frequently asked questions

Why doesn't the counter update right away when someone joins?

Because Discord limits renaming a channel to 2 times every 10 minutes. If the bot renamed on every join, the requests would pile up in a queue and the channel number would be late anyway. Updating every 6 minutes is more predictable and never hits the limit.

Do I need the GuildMembers intent just to show the total?

Not for the plain total, but without it guild.memberCount stays frozen at the value from when the bot connected, because joins and leaves never arrive. In that case, call guild.fetch() before each update and use approximateMemberCount. The Server Members intent is needed when you want to exclude bots from the count, count by role or react to joins and leaves.

How do I stop people from joining the voice channel?

Deny the Connect permission to the @everyone role on the channel. The channel stays visible, but the join button is blocked. The bot does not need to join the channel, only Manage Channels on the server.

What happens if I go over the rename limit?

Discord answers with a 429 error and the library holds the request until the window frees up, which can leave that call hanging for several minutes. That is why a routine with a fixed interval is better than one rename per event.

Can I show how many members are online?

An approximate number, yes, with no privileged intent: guild.fetch() returns approximatePresenceCount, the estimate of members online. The exact count requires the GuildPresences intent, which is privileged and heavy, and for most servers it is not worth it.

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 Beginner Used disallowed intents error in a Discord bot: how to fix it The bot crashes on connect with Used disallowed intents, or it connects and cannot see the text of messages. Both have the same root: privileged intents must be switched on in the portal and declared in the code. 8 min Read guide](https://streethosting.com.br/en/guides/discord-bots/discord-bot-disallowed-intents-error) [Discord bots Intermediate How to fix the Discord 429 rate limit error The 429 error shows up when your bot sends too many calls in a short time. A simple queue and a wait time will cut the problem down. 2 min Read guide](https://streethosting.com.br/en/guides/discord-bots/fix-discord-429-rate-limit) [Discord bots Intermediate Temporary voice channels on Discord: the join to create system Instead of keeping dozens of empty voice rooms, leave a single trigger channel. When someone joins, the bot creates a room named after the person, moves them in and deletes the channel when everyone leaves. 8 min Read guide](https://streethosting.com.br/en/guides/discord-bots/discord-temporary-voice-channels-bot)

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