CodeNewbie Community đŸŒ±

Jhon Lap
Jhon Lap

Posted on

Build a Smart Minecraft Server Stats Bot with Node.js

If you’ve ever hosted a Minecraft server—whether it’s for you and your friends or a bustling online community—you know how valuable it is to keep tabs on what’s happening inside. Is the server up? Who’s online? What’s the average player count over time? Has the ping dropped again?

These things matter. Constantly logging into the server or opening Minecraft just to check the status? Not efficient. What if you could automate that?

In this tutorial, I’ll walk you through building a Minecraft Server Stats Bot that runs on Node.js. It will:

  • Monitor your Minecraft server’s status
  • Log who’s online and when
  • Track player activity trends over time
  • Send smart updates to a Discord server (or email, Telegram, etc.)
  • Work with both vanilla and most modded servers (as long as they support Query)

We’ll use a combination of minecraft-server-util, dotenv, node-cron, and axios to build our bot.

What You’ll Need

Before we dive in, let’s get our tools ready:

  • A public Minecraft APK Download server IP & port (yours or someone else’s)
  • Node.js (v14 or newer)
  • Basic knowledge of JavaScript
  • A terminal and text editor (I use VS Code)
  • A Discord Webhook (optional but recommended for notifications)

Step 1: Initialize the Project

Start by creating your project folder and installing dependencies.

mkdir mc-server-bot
cd mc-server-bot
npm init -y
npm install minecraft-server-util dotenv express node-cron axios
Enter fullscreen mode Exit fullscreen mode

Now, create your .env file to store private config info:

touch .env

And add:

MC_SERVER_IP=play.example.com
MC_SERVER_PORT=25565
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the Express Server

We’ll set up a basic Express API for future expansion or local dashboarding.

// server.js
require('dotenv').config();
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Minecraft Server Stats Bot is running');
});

app.listen(port, () => {
  console.log ('Server listening at http://localhost:${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Run it:

node server.js
Enter fullscreen mode Exit fullscreen mode
Step 3: Query the Minecraft Server
Enter fullscreen mode Exit fullscreen mode

Time to get real-time data from the server using minecraft-server-util.

// stats.js
const { queryFull } = require('minecraft-server-util');

async function getServerStats() {
  try {
    const response = await queryFull(process.env.MC_SERVER_IP, parseInt(process.env.MC_SERVER_PORT), {
      timeout: 5000,
    });

    return {
      motd: response.motd.clean,
      playersOnline: response.players.online,
      maxPlayers: response.players.max,
      playerList: response.players.list,
      version: response.version.name,
    };
  } catch (err) {
    console.error('❌ Error querying server:', err.message);
    return null;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Schedule Regular Checks with Cron

Let’s log stats every 15 minutes and notify if something changes.

// monitor.js
const cron = require('node-cron');
const { getServerStats } = require('./stats');
const axios = require('axios');

let lastPlayerCount = 0;

cron.schedule('*/15 * * * *', async () => {
  const stats = await getServerStats();
  if (!stats) return;

  console.log(`[${new Date().toLocaleTimeString()}] ${stats.playersOnline}/${stats.maxPlayers} players online`);

  if (stats.playersOnline !== lastPlayerCount) {
    await axios.post(process.env.DISCORD_WEBHOOK_URL, {
      content: `🧑‍🚀 **Player Update**: ${stats.playersOnline} players online now.\nMOTD: ${stats.motd}`,
    });
    lastPlayerCount = stats.playersOnline;
  }
});
Enter fullscreen mode Exit fullscreen mode

Add this line to server.js to run monitoring when the server starts:

require('./monitor');
Enter fullscreen mode Exit fullscreen mode

Step 5: Track Player History

Let’s track which players were online and when. Create a lightweight history tracker.

// history.js
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'player-history.json');

function saveHistory(data) {
  let history = [];

  if (fs.existsSync(filePath)) {
    history = JSON.parse(fs.readFileSync(filePath));
  }

  history.push({
    timestamp: new Date().toISOString(),
    onlinePlayers: data.playersOnline,
    playerList: data.playerList,
  });

  fs.writeFileSync(filePath, JSON.stringify(history, null, 2));
}

module.exports = { saveHistory };
Enter fullscreen mode Exit fullscreen mode

Update monitor.js to use it:

const { saveHistory } = require('./history');

// Inside the cron job, after stats are fetched
if (stats) {
  saveHistory(stats);
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Smart Insights

Want to know who plays the most? Or when your server is busiest?

// insights.js
const fs = require('fs');
const path = require('path');

function topPlayers() {
  const data = JSON.parse(fs.readFileSync(path.join(__dirname, 'player-history.json')));
  const counter = {};

  data.forEach(entry => {
    entry.playerList.forEach(player => {
      counter[player] = (counter[player] || 0) + 1;
    });
  });

  const sorted = Object.entries(counter).sort((a, b) => b[1] - a[1]);
  console.log('🎖 Top players:');
  sorted.slice(0, 5).forEach(([name, count]) => {
    console.log(`${name}: ${count} sessions`);
  });
}
Enter fullscreen mode Exit fullscreen mode

topPlayers();

Step 7: Handle Errors & Caching

Handle downtime and avoid hammering the server too hard:

// cache.js
let lastStats = null;
let lastFetchTime = 0;

async function getCachedStats(fetchFn, ttlMs = 5 * 60 * 1000) {
  const now = Date.now();
  if (lastStats && now - lastFetchTime < ttlMs) {
    return lastStats;
  }

  const stats = await fetchFn();
  if (stats) {
    lastStats = stats;
    lastFetchTime = now;
  }

  return stats;
}

module.exports = { getCachedStats };
Enter fullscreen mode Exit fullscreen mode

Then in monitor.js:

const { getCachedStats } = require('./cache');

cron.schedule('*/5 * * * *', async () => {
  const stats = await getCachedStats(getServerStats);
  if (!stats) return;

  saveHistory(stats);
  // other logic...
});
Enter fullscreen mode Exit fullscreen mode

Optional: Create a Web Dashboard

Want to see stats in a browser? Expose an endpoint!

// Add to server.js
const { getCachedStats } = require('./cache');
const { getServerStats } = require('./stats');

app.get('/status', async (req, res) => {
  const stats = await getCachedStats(getServerStats);
  res.json(stats || { error: 'Server offline or unreachable' });
});
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

This Minecraft server bot is more than just a project—it’s a smart companion for server admins who want visibility without hassle. And the best part? You can build on it however you like.

Here are some ideas to level it up:

  • Use charting libraries to build a web dashboard
  • Integrate machine learning for activity prediction
  • Track mod usage or server performance
  • Auto-restart or alert you when the server goes down
  • Create a bot that logs gameplay stats like kill counts (with plugins)

Whether you're managing a hardcore SMP server or a relaxed creative build world, this bot can help you stay informed and proactive.

And hey—if you're like me and love tweaking servers more than actually playing, this kind of tool is just fun to build.

Top comments (0)