A web dashboard gives server admins a visual interface to configure your bot without using Discord commands. It's the feature that separates hobbyist bots from professional ones.
Architecture
Browser → Express.js Web Server → Bot API → Discord.js Bot
↓
Discord OAuth2
Users authenticate with their Discord account. The dashboard shows servers they manage. They configure bot settings through a web UI.
OAuth2 Setup
Create Application
- Go to Discord Developer Portal
- Select your application
- OAuth2 → Add redirect:
http://yourdomain.com/callback - Note your Client ID and Client Secret
Express.js OAuth2 Flow
const express = require('express');
const fetch = require('node-fetch');
const session = require('express-session');
const app = express();
app.use(session({ secret: 'your-session-secret', resave: false, saveUninitialized: false }));
// Login redirect
app.get('/login', (req, res) => {
const params = new URLSearchParams({
client_id: CLIENT_ID,
redirect_uri: 'http://yourdomain.com/callback',
response_type: 'code',
scope: 'identify guilds'
});
res.redirect(`https://discord.com/api/oauth2/authorize?${params}`);
});
// OAuth2 callback
app.get('/callback', async (req, res) => {
const code = req.query.code;
const tokenResponse = await fetch('https://discord.com/api/oauth2/token', {
method: 'POST',
body: new URLSearchParams({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: 'authorization_code',
code: code,
redirect_uri: 'http://yourdomain.com/callback'
})
});
const tokens = await tokenResponse.json();
// Get user info
const userResponse = await fetch('https://discord.com/api/users/@me', {
headers: { Authorization: `Bearer ${tokens.access_token}` }
});
const user = await userResponse.json();
req.session.user = user;
req.session.accessToken = tokens.access_token;
res.redirect('/dashboard');
});
Dashboard Pages
Server List
Show servers where the user has MANAGE_SERVER permission:
app.get('/dashboard', async (req, res) => {
if (!req.session.user) return res.redirect('/login');
const guildsResponse = await fetch('https://discord.com/api/users/@me/guilds', {
headers: { Authorization: `Bearer ${req.session.accessToken}` }
});
const guilds = await guildsResponse.json();
const manageable = guilds.filter(g => (g.permissions & 0x20) === 0x20);
// Filter to guilds where bot is present
const botGuilds = manageable.filter(g => client.guilds.cache.has(g.id));
res.render('dashboard', { guilds: botGuilds, user: req.session.user });
});
Server Settings
app.get('/dashboard/:guildId', async (req, res) => {
const guild = client.guilds.cache.get(req.params.guildId);
if (!guild) return res.status(404).send('Bot not in this server');
const settings = await getGuildSettings(req.params.guildId);
const channels = guild.channels.cache.filter(c => c.type === 0); // Text channels
res.render('server-settings', { guild, settings, channels });
});
app.post('/dashboard/:guildId/settings', async (req, res) => {
await updateGuildSettings(req.params.guildId, {
prefix: req.body.prefix,
welcomeChannel: req.body.welcomeChannel,
logChannel: req.body.logChannel
});
res.redirect(`/dashboard/${req.params.guildId}`);
});
Frontend
Use a simple template engine or React for the frontend. Key pages:
- Login page
- Server selection
- Server settings (prefix, channels, features)
- Moderation logs viewer
- Analytics/statistics
API Design
Separate the dashboard API from the bot:
// Bot exposes internal API
const apiApp = express();
apiApp.get('/api/guilds/:id/settings', authenticateInternal, async (req, res) => {
const settings = await getGuildSettings(req.params.id);
res.json(settings);
});
apiApp.post('/api/guilds/:id/settings', authenticateInternal, async (req, res) => {
await updateGuildSettings(req.params.id, req.body);
res.json({ success: true });
});
Hosting
The dashboard needs:
- Express.js server (port 80/443)
- SSL certificate (Let's Encrypt)
- Domain name
On Space-Node VPS hosting, run both the bot and dashboard on the same server. A 2-core VPS handles both comfortably.
For bot-only hosting on Discord Bot plans, the dashboard would need separate web hosting.
Security Notes
- Store tokens securely (environment variables, not code)
- Validate that users have permission to manage the guild they're accessing
- Rate limit API endpoints
- Use HTTPS in production
- Don't expose your bot token through the dashboard
