How to restrict Discord bot slash commands to specific channels?

I’m having trouble limiting where my Discord bot’s slash commands can be used. I want them to only work in voice channel rooms but they’re showing up everywhere.

I made a new server to test this out. The bot is connected and it created its own role automatically. No other roles exist on the server.

In the bot’s integration settings I turned off all channels. But I can still use the commands in every channel. I even tried to block all actions for the bot’s role in one category. Still no luck. The commands keep working everywhere.

The bot has two slash commands:

@bot.tree.command()
async def roll_dice(interaction: discord.Interaction):
    result = random.randint(1, 6)
    await interaction.response.send_message(f'You rolled a {result}!')

@bot.tree.command()
async def show_card(interaction: discord.Interaction):
    card = random.choice(['Ace', 'King', 'Queen', 'Jack'])
    await interaction.response.send_message(f'Your card is: {card}')

Any ideas on how to actually restrict these commands to specific channels? I’m out of ideas here.

hey dude, try using discord.app_commands.checks decorator. it lets u set conditions for when commands can be used. here’s an example:

def in_voice_channel():
    def predicate(interaction):
        return isinstance(interaction.channel, discord.VoiceChannel)
    return app_commands.check(predicate)

@bot.tree.command()
@in_voice_channel()
async def roll_dice(interaction):
    # command code here

this should make it work only in voice channels

I’ve dealt with this exact problem before. The solution that worked for me was using a combination of app_commands.checks and a custom check function. Here’s what I did:

from discord import app_commands

def is_voice_channel():
    def predicate(interaction):
        return isinstance(interaction.channel, discord.VoiceChannel)
    return app_commands.check(predicate)

@bot.tree.command()
@is_voice_channel()
async def roll_dice(interaction: discord.Interaction):
    result = random.randint(1, 6)
    await interaction.response.send_message(f'You rolled a {result}!')

This approach ensures the commands only work in voice channels. If someone tries to use the command elsewhere, they’ll get an error message. It’s more reliable than relying on server settings alone. Just apply the @is_voice_channel() decorator to all commands you want to restrict.

I ran into a similar issue when working on my bot. In my case, I found that trying to control allowed channels through integration settings alone wasn’t enough. I ended up embedding a channel check directly into the command functions. I defined an array of allowed channel IDs and then verified that the interaction channel ID was in that list before executing the command. If it wasn’t, the bot would immediately return an appropriate message. For example, using a check with the roll_dice command ensured that non-allowed channels simply received an error response.

Here is a snippet that shows how I implemented this:

ALLOWED_CHANNELS = [123456789, 987654321]  # Add your voice channel IDs here

@bot.tree.command()
async def roll_dice(interaction: discord.Interaction):
    if interaction.channel_id not in ALLOWED_CHANNELS:
        await interaction.response.send_message('This command can only be used in specific channels.', ephemeral=True)
        return
    result = random.randint(1, 6)
    await interaction.response.send_message(f'You rolled a {result}!')

This method gave me the precise control I needed without relying solely on broader server settings.