Is your Discord bot online on every shard?
A sharded bot can go half down: one shard drops, part of the servers lose the bot, and general-purpose monitoring sees nothing. NorminUp follows every shard.
Equinox, the Discord bot of NorminUp's author, uses it in production.
Shard grid, in your dashboard
ExampleOn your public status page
Badge for your README or your top.gg page
What you get
Every shard followed
Your bot reports its shards every 60 s. A silent shard, or one stuck reconnecting, shows up right away on a grid.
Alerts that name the shard
"Shards 3, 7 silent (8/10 ready)" in your Discord webhook, a single incident, then the all-clear when everything is back.
A status page for your users
"9/10 shards online" on your public page, and a badge for your README, included in the free plan.
Up and running in three steps
- 1
Create an account
Free, no credit card. The free plan follows up to 2 shards.
- 2
Add your bot
New service, type "Discord bot (shards)". Once saved, copy its token.
- 3
Paste the snippet
In your bot, with the token in NORMINUP_TOKEN. The first shards show up within a minute.
A few lines, no dependency
discord.js, discord.py or any language: every process of your bot reports the state of its shards. The token is created in your dashboard.
discord.js v14 or v15, ESM or CommonJS, no dependency. Paste after client.login(): covers internal sharding, ShardingManager and discord-hybrid-sharding.
1// NorminUp: reports this process's shards every 60 s. Paste after client.login().2// discord.js v14 or v15, ESM or CommonJS, no dependency.3const NORMINUP_TOKEN = process.env.NORMINUP_TOKEN ?? 'YOUR_TOKEN';4// Shard status enums by value: discord.js v14 Status,5// then @discordjs/ws WebSocketShardStatus (v15).6const NORMINUP_STATUS_V14 = [7 'ready', 'connecting', 'reconnecting', 'idle', 'nearly',8 'disconnected', 'waiting_for_guilds', 'identifying', 'resuming'9];10const NORMINUP_STATUS_V15 = ['idle', 'connecting', 'resuming', 'ready'];11 12async function norminupShards() {13 const guilds = id => client.guilds.cache.filter(guild => guild.shardId === id).size;14 if (client.ws.shards) {15 return [...client.ws.shards.values()].map(shard => ({16 id: shard.id,17 status: NORMINUP_STATUS_V14[shard.status] ?? 'unknown',18 ping: shard.ping,19 guilds: guilds(shard.id)20 }));21 }22 const statuses = await client.ws.fetchStatus();23 return [...statuses].map(([id, status]) => ({24 id,25 status: NORMINUP_STATUS_V15[status] ?? 'unknown',26 ping: client.pings?.get(id) ?? -1,27 guilds: guilds(id)28 }));29}30 31setInterval(async () => {32 try {33 const known = [34 client.cluster?.info?.TOTAL_SHARDS,35 client.shard?.count,36 client.options.shardCount37 ];38 const total = known.find(Number.isInteger) ?? await client.ws.getShardCount?.() ?? 1;39 const shards = await norminupShards();40 await fetch('https://api.norminup.com/api/heartbeat/shards', {41 method: 'POST',42 headers: {43 'Content-Type': 'application/json',44 Authorization: `Bearer ${NORMINUP_TOKEN}`45 },46 body: JSON.stringify({ v: 1, total, shards }),47 signal: AbortSignal.timeout(5000)48 });49 } catch (error) {50 // Monitoring must never crash the bot: the next ping retries.51 }52}, 60_000).unref();Shards tracked per plan
- Free
- 2 shards
- Starter
- 8 shards
- Pro
- 32 shards
- Business
- On quote
A bot counts as a single service, whatever its number of shards.
Your questions before pasting code
No. We never ask for the bot token. The snippet only sends, for each shard, its number, state, latency and server count.
No. The snippet waits 5 seconds at most, ignores every error and retries the next minute. It cannot stop your bot.
A discord.py snippet is provided, and any language that can send a JSON POST request works (see the "Other language" tab).
Yes: you know when your bot loses its Discord connection, even while its process keeps running, and your users see it on your status page.
Discord gives a bot 3 seconds to acknowledge a command, a button or a menu. Past that, the user sees one of these messages, and nothing crashes on your side: no error, no alert. The @norminup/discord module counts these failed interactions, and NorminUp alerts you.
Yes. After a deferReply(), Discord gives 15 minutes to answer. A command never finished is counted as abandoned, and the response time of the others is measured.
Ready to see your shards?
Create your account, add your bot, and the grid fills in with the first ping.
No credit card required • Cancel anytime