Every Minecraft community wants to know: is the server online? How many players are on right now? In this tutorial, I'll show you how to build a Discord bot that posts live Minecraft server status updates using the Minecraft ServerHub API.
Why a Discord Bot?
Discord is where most Minecraft communities live. Instead of making players visit a website or use third-party tools, you can bring server status directly into your Discord channels. The bot will:
- Show online/offline status with player counts
- Update automatically every 5 minutes
- Display the server MOTD and version info
- Support both Java and Bedrock servers
We'll use the free Minecraft ServerHub REST API which requires no API key and returns JSON data for any server.
Prerequisites
- Node.js 18+ installed
- A Discord bot token (Discord Developer Portal)
- A Minecraft server address to monitor
Project Setup
Create a new project and install dependencies:
mkdir mc-discord-bot && cd mc-discord-bot
npm init -y
npm install discord.js node-cron
Step 1: Create the API Helper
First, let's create a module that queries the server status API. The endpoint returns everything we need: player count, MOTD, version, latency, and the server icon.
// api.js
const BASE = "https://minecraft-serverhub.com/api/server";
async function getServerStatus(address) {
const res = await fetch(BASE + "/" + address);
if (!res.ok) throw new Error("API returned " + res.status);
return res.json();
}
module.exports = { getServerStatus };
The API response includes fields like online, players.online, players.max, motd.clean, version, and latency. Check the full API documentation for all available fields.
Step 2: Build the Discord Embed
Discord embeds are the best way to display rich server information. We'll create a function that turns API data into a beautiful embed:
// embed.js
const { EmbedBuilder } = require("discord.js");
function createStatusEmbed(server, address) {
if (!server.online) {
return new EmbedBuilder()
.setTitle("Server Status: " + address)
.setColor(0xff0000)
.setDescription("Server is **OFFLINE**")
.setTimestamp();
}
const embed = new EmbedBuilder()
.setTitle("Server Status: " + address)
.setColor(0x00ff00)
.addFields(
{ name: "Status", value: "Online", inline: true },
{ name: "Players", value: server.players.online + "/" + server.players.max, inline: true },
{ name: "Version", value: server.version || "Unknown", inline: true },
{ name: "Latency", value: server.latency + "ms", inline: true }
)
.setTimestamp()
.setFooter({ text: "Powered by Minecraft ServerHub" });
if (server.motd && server.motd.clean) {
embed.setDescription(server.motd.clean);
}
if (server.icon) {
embed.setThumbnail("data:image/png;base64," + server.icon);
}
return embed;
}
module.exports = { createStatusEmbed };
Step 3: Wire Up the Bot
Now let's create the main bot file that connects to Discord, registers a slash command, and sets up auto-updating:
// bot.js
const { Client, GatewayIntentBits, SlashCommandBuilder, REST, Routes } = require("discord.js");
const cron = require("node-cron");
const { getServerStatus } = require("./api");
const { createStatusEmbed } = require("./embed");
const TOKEN = process.env.DISCORD_TOKEN;
const CLIENT_ID = process.env.CLIENT_ID;
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
// Store channels that want auto-updates
const watchList = new Map();
client.on("ready", () => {
console.log("Bot is online as " + client.user.tag);
// Auto-update every 5 minutes
cron.schedule("*/5 * * * *", async () => {
for (const [channelId, config] of watchList) {
try {
const data = await getServerStatus(config.address);
const embed = createStatusEmbed(data, config.address);
const channel = await client.channels.fetch(channelId);
if (config.messageId) {
const msg = await channel.messages.fetch(config.messageId);
await msg.edit({ embeds: [embed] });
}
} catch (err) {
console.error("Update failed for " + channelId, err.message);
}
}
});
});
Step 4: Add Slash Commands
Register two commands: /status for a one-time check and /watch for continuous monitoring:
// Add to bot.js
client.on("interactionCreate", async (interaction) => {
if (!interaction.isChatInputCommand()) return;
if (interaction.commandName === "status") {
const address = interaction.options.getString("server");
await interaction.deferReply();
try {
const data = await getServerStatus(address);
const embed = createStatusEmbed(data, address);
await interaction.editReply({ embeds: [embed] });
} catch (err) {
await interaction.editReply("Failed to check server: " + err.message);
}
}
if (interaction.commandName === "watch") {
const address = interaction.options.getString("server");
await interaction.deferReply();
try {
const data = await getServerStatus(address);
const embed = createStatusEmbed(data, address);
const msg = await interaction.editReply({ embeds: [embed] });
watchList.set(interaction.channelId, {
address,
messageId: msg.id,
});
await interaction.followUp("Now watching **" + address + "** in this channel. Updates every 5 minutes.");
} catch (err) {
await interaction.editReply("Failed: " + err.message);
}
}
});
client.login(TOKEN);
Step 5: Register Commands with Discord
Create a deployment script:
// deploy-commands.js
const { SlashCommandBuilder, REST, Routes } = require("discord.js");
const commands = [
new SlashCommandBuilder()
.setName("status")
.setDescription("Check a Minecraft server status")
.addStringOption(opt =>
opt.setName("server").setDescription("Server address (e.g. play.hypixel.net)").setRequired(true)
),
new SlashCommandBuilder()
.setName("watch")
.setDescription("Watch a server with auto-updates every 5 min")
.addStringOption(opt =>
opt.setName("server").setDescription("Server address").setRequired(true)
),
].map(cmd => cmd.toJSON());
const rest = new REST({ version: "10" }).setToken(process.env.DISCORD_TOKEN);
rest.put(Routes.applicationCommands(process.env.CLIENT_ID), { body: commands })
.then(() => console.log("Commands registered"))
.catch(console.error);
Running the Bot
export DISCORD_TOKEN="your-bot-token"
export CLIENT_ID="your-client-id"
node deploy-commands.js
node bot.js
Your bot is now live. Type /status play.hypixel.net in any channel to test it.
Adding Server Badges
Want to show your server status on your website too? Use the Minecraft ServerHub Badge Generator to create embeddable status badges. You can also install the minecraft-server-badge npm package for programmatic badge generation.
Exploring Live Data
If you want to see how different servers compare, check out the live statistics dashboard which tracks player counts across 5000+ servers. The server explorer lets you browse and search servers by gamemode, version, and region.
What's Next?
Some ideas to extend this bot:
- Player join/leave notifications using the player list endpoint
- Historical graphs by storing player counts over time
- Multi-server support with a database backend
- Web dashboard using Express.js and the Minecraft ServerHub API
Conclusion
Building a Discord bot for Minecraft server monitoring is straightforward with the right API. The Minecraft ServerHub platform provides free, reliable server data that you can integrate into any application — from Discord bots to web dashboards to mobile apps.
The full source code is available on GitHub. If you found this useful, check out my other tutorials on building with the Minecraft ServerHub developer tools.
Built with Minecraft ServerHub — the free Minecraft server monitoring platform.
Top comments (0)