Discord Server Member Count Tracker - Online & Total Members avatar

Discord Server Member Count Tracker - Online & Total Members

Pricing

from $3.65 / 1,000 server row returneds

Go to Apify Store
Discord Server Member Count Tracker - Online & Total Members

Discord Server Member Count Tracker - Online & Total Members

For community managers and growth teams: total members, online members, boosts, name, tag, icon and creation date for every Discord server you name by its invite link. One measured server: 431,725 members, 45,600 online. Monitoring returns a server only when its member count moves.

Pricing

from $3.65 / 1,000 server row returneds

Rating

0.0

(0)

Developer

NeverEmpty

NeverEmpty

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Share

For community managers and growth teams: total members, online members, boosts, server name, tag, description, icon, verification level and creation date for every Discord server you name by its invite link or code, plus a monitoring mode that returns a server only when its member count moves. Measured on 2026-09-23 from the four servers in test/fixtures/: Python 431,725 members / 45,600 online, Discord Developers 304,393 / 80,142, Reactiflux 76,420 / 11,273, Node.js 24,642 / 2,804. Point it at the servers you actually care about - yours, your competitors', the communities you sponsor - and get a daily growth line instead of a directory dump.

Export as JSON, CSV or Excel.

Unofficial. Public data only. Not affiliated with, endorsed by or connected to Discord Inc.


What it does

You give it invite codes or invite links. It returns one row per server, with the numbers Discord publishes on the public invite endpoint.

{
"invites": ["python", "https://discord.gg/discord-developers", "discord.com/invite/nodejs"],
"maxServers": 100
}

A returned row (shortened - the real row has every column listed below):

{
"status": "ok",
"inputInvite": "python",
"inviteCode": "python",
"inviteUrl": "https://discord.gg/python",
"serverId": "267624335836053506",
"serverName": "Python",
"serverDescription": "We're a large community focused around the Python programming language. We believe that anyone can learn to code.",
"memberCount": 431725,
"onlineCount": 45600,
"countsAreApproximate": true,
"boostCount": 28,
"boostTier": 3,
"serverCreatedAt": "2017-01-08T12:03:33.883Z",
"serverAgeDays": 3544,
"vanityUrlCode": "python",
"serverTag": "snek",
"isVerified": false,
"isPartnered": false,
"isCommunity": true,
"isDiscoverable": true,
"verificationLevel": 2,
"verificationLevelName": "MEDIUM",
"nsfwLevel": 0,
"nsfwLevelName": "DEFAULT",
"iconUrl": "https://cdn.discordapp.com/icons/267624335836053506/95a69567efa60a48b8d9840cb38b106b.png",
"inviteChannelName": "welcome",
"inviteExpiresAt": null,
"inviteIsPermanent": true,
"scrapedAt": "2026-09-23T03:00:00.000Z"
}

Why this one

Most Discord Actors on the store are built to find servers: you give them a keyword or a category and they return whatever the public directories list. A couple of them do also resolve invite codes you supply, through the same public endpoint this one uses. What none of them does is remember between runs - run them again tomorrow and you pay full price for every server on your list, changed or not, and you diff the two exports yourself. That is the gap this Actor fills:

  • You name the servers. Invite code, discord.gg/code or https://discord.com/invite/code - all three work, and invite codes are case sensitive, so they are sent exactly as you type them.
  • Monitoring mode returns only what changed, with previousMemberCount, memberCountChange and previousCheckedAt in the row. Servers that did not move cost the check fee instead of the row price.
  • Two invites to the same server cost one row. Servers are joined on the id Discord returns, not on the code you typed.
  • It never says a server is empty or gone when it could not read it. Rate limits, blocks, unknown invites and expired invites each get their own free row with their own reason.

Input

FieldWhat it does
invitesThe servers to check, named by an invite: python, discord.gg/python or https://discord.com/invite/python. Several per line is fine - the list is split on spaces, commas and semicolons. The same code is checked once. Up to 1,000 per run, one request each, 600 ms apart. Server URLs such as discord.com/channels/... are not invites and get a free invalid-input row. Leave it empty with monitoring off and the example servers python, discord-developers and nodejs are checked, with inputInvite saying so; leave it empty with monitoring on and nothing is checked and nothing is charged.
maxServersHow many charged rows to return when monitoring is off (default 100, max 1,000). Reading stops once that many servers have been read, and a free row says how many invites were not checked. It does not limit spending in monitoring mode: there every server you list is checked and every change comes back, and the run's maximum total charge is the cap. Cutting changes by this number would mean the servers at the end of your list never came back at all.
monitoringModeOff: every invite comes back with the server's counts right now. On: the Actor remembers each server and later runs return it only when the watched count changed. The first run returns every server once to set the baseline.
monitorOnWhat counts as a change: member-count (default) or any-count (members, online or boosts). See the measurement below for why the default is the total member count.
resetMonitoringStateClears every remembered count for this Actor, so the next monitoring run returns each server once again. The counts are stored per server, not per list, so this affects all your monitoring runs. Turn it off again after that one run - left on in a schedule, every run starts from scratch and charges a full server row for every server.
useProxyRequests go out directly. This only covers the case where a request does not reach Discord at all (a connection failure): it then retries through an Apify proxy. Blocks, bot checks and rate limits are never retried from another address either way; they come back as free rows.

Output columns

source status scrapedAt inputInvite inviteCode inviteUrl serverId serverName serverDescription memberCount onlineCount countsAreApproximate boostCount boostTier serverCreatedAt serverAgeDays vanityUrlCode serverTag isVerified isPartnered isCommunity isDiscoverable verificationLevel verificationLevelName nsfwLevel nsfwLevelName isNsfw features iconUrl bannerUrl splashUrl inviteChannelName inviteChannelId inviteExpiresAt inviteIsPermanent

In monitoring mode, also: change isFirstCheck previousCheckedAt previousMemberCount previousOnlineCount previousBoostCount memberCountChange onlineCountChange boostCountChange.

change is one of first-check, members-up, members-down, online-count-changed or boost-count-changed. previousCheckedAt is when that server was last checked, not when it last changed: every server read in a monitoring run has its record refreshed, changed or not.

Rows that are not charged

Every row that is not a server carries a status and a note saying why, and none of them is charged:

statusWhen
no-such-inviteDiscord answered Unknown Invite (error code 10006). A code that never existed, one that was deleted or revoked, and one that expired all get this same answer, so the row does not claim which.
invite-expiredDiscord returned the invite but its expiry time has already passed, so the counts attached to it may be out of date. Nothing is returned for it.
blockedA block, an error page or an empty response instead of the invite data. The server is not reported as gone or empty.
rate-limitedDiscord rate-limited the run and the invite was still not readable after the retries.
unreadableDiscord answered with something else that could not be read: a body that is not the invite data, a redirect (never followed), or the invite without any member count. The reason is in the note. A server is never returned with an empty member count.
invalid-inputThe text is not an invite code or invite link, or the invites field is not a list, or monitoring is on with an empty list. Nothing is requested.
duplicate-inviteThe invite leads to a server this run already returned.
no-changeMonitoring mode: nothing among the servers checked has changed.
not-checkedInvites past maxServers, or past the 1,000-per-run ceiling.
budget-reachedThe run's maximum total charge was reached. The row says how many of the ready rows fit inside the limit and how many invites were not checked at all.

Pricing

EventPrice
server-returned - one server row$5.00 per 1,000 rows
server-checked - one server checked in monitoring mode$0.30 per 1,000 checks

There is no start fee. With monitoring off you pay only for the rows you get. With monitoring on, every server checked costs the check fee, changed or not, plus the row price for the rows that come back; invites Discord returns nothing for, blocks and rate limits are free. Twenty servers checked every hour is 14,400 checks a month = $4.32, plus $0.005 for each row where a count moved.

The Actor reads only as many servers as the run's maximum total charge can pay for with a check and a change row each, so a low limit never spends the whole budget on check fees and returns nothing. Invites it did not read are named in a free budget-reached row.

What was measured, and when

Everything below was measured on 2026-09-23 against the live endpoint. The four responses are in test/fixtures/ so the numbers in this README can be counted again from this repository.

  • On every server measured, the counts appear twice in the response - as approximate_member_count / approximate_presence_count, and again inside profile as member_count / online_count. On all four servers measured the two pairs were identical, so the row carries one pair. Discord itself calls them approximate; countsAreApproximate says so in every row.
  • Discord caches the answer for up to five minutes (Cache-Control: public, max-age=300, and repeats inside that window came back as a cache hit). Checking a server more often than every five minutes does not get a fresher number.
  • Both counts move; the online count moves more. The same four servers were read every 5.5 minutes for 33 minutes, 7 reads each, on 2026-09-22 between 18:03 and 18:36 UTC (test/fixtures/counts-jitter-2026-09-23.json, so you can count this again). Across the 24 intervals, the total member count changed 13 times and reversed direction 4 times; the online count changed 18 times and reversed direction 10 times (counting a reversal against the last interval that moved at all) (Python's online count went 45,600 -> 45,786 -> 45,674 while its member count went 431,725 -> 431,728 -> 431,729). Neither number is perfectly steady, but the member count moves less often and swings back less, which is why monitorOn watches it by default.
  • On a large server, expect a row on about half of five-minute checks. That is real movement, not a defect, but it is not what this is priced for: hourly or daily monitoring is. Discord caches the answer for five minutes anyway, so checking more often than that only costs check fees.
  • The creation date is calculated, not returned. Discord ids carry their creation time, so serverCreatedAt comes from the server id (Reactiflux 2015-10-11, Python 2017-01-08, Node.js 2018-03-21, Discord Developers 2019-08-20).
  • Unknown invites answer HTTP 404 with {"message": "Unknown Invite", "code": 10006} - a 44-byte body.

How the data is obtained, and what is not touched

  • The Actor requests exactly one address: https://discord.com/api/v10/invites/<code>?with_counts=true&with_expiration=true. That is the only address it ever requests; the discord.gg and cdn.discordapp.com links in the rows are built as text and never fetched. Redirects are not followed, so it cannot be sent anywhere else. A test in this repository re-reads discord.com/robots.txt as fetched on 2026-09-23, applies the longest-match rule and fails the build if that path is not the one Allow: /api/v*/invite permits.
  • No login, no bot token, no OAuth, no authorization header of any kind. Three request headers go out and nothing else: a browser User-Agent, Accept: application/json and Accept-Encoding: identity.
  • Blocks, bot checks and rate limits are not worked around, and a blocked request is never retried from another address. A rate limit is waited out only for as long as Discord asks, up to 30 seconds, from the same address; anything longer comes back as a free rate-limited row. An Apify proxy is used for one case only: a request that does not reach Discord at all (a connection failure).
  • No personal data. Discord's answer can include the account that created the invite; that object is never read into the row, and a test feeds a response containing one and asserts nothing about it reaches the output. Members, messages, channels and user profiles are not requested at all.

Notes and limits

  • The counts are the ones Discord publishes for the invite. They are approximate by Discord's own naming, and this Actor does not adjust, round or estimate them.
  • A server with no invite cannot be tracked. You need a working invite code, and a permanent one (no expiry) is what you want for monitoring.
  • Remembered counts are stored per server, in a key-value store named discord-server-monitoring. Do not put the same server in two schedules that can run at the same time: overlapping runs merge their records, but Apify's key-value store has no atomic update, so this cannot be prevented completely.
  • If a run is restarted by Apify mid-way, servers already returned in that run are not returned or charged again, and checks already paid for are not paid for again.
  • Discord can change this endpoint at any time. It is not a documented product surface for scrapers, so there is no promise that it keeps working unchanged.