Discord Server Member Count Tracker - Online & Total Members
Pricing
from $3.65 / 1,000 server row returneds
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
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/codeorhttps://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,memberCountChangeandpreviousCheckedAtin 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
| Field | What it does |
|---|---|
invites | The 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. |
maxServers | How 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. |
monitoringMode | Off: 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. |
monitorOn | What 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. |
resetMonitoringState | Clears 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. |
useProxy | Requests 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:
status | When |
|---|---|
no-such-invite | Discord 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-expired | Discord 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. |
blocked | A block, an error page or an empty response instead of the invite data. The server is not reported as gone or empty. |
rate-limited | Discord rate-limited the run and the invite was still not readable after the retries. |
unreadable | Discord 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-input | The 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-invite | The invite leads to a server this run already returned. |
no-change | Monitoring mode: nothing among the servers checked has changed. |
not-checked | Invites past maxServers, or past the 1,000-per-run ceiling. |
budget-reached | The 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
| Event | Price |
|---|---|
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 insideprofileasmember_count/online_count. On all four servers measured the two pairs were identical, so the row carries one pair. Discord itself calls them approximate;countsAreApproximatesays 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 whymonitorOnwatches 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
serverCreatedAtcomes 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; thediscord.ggandcdn.discordapp.comlinks 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-readsdiscord.com/robots.txtas fetched on 2026-09-23, applies the longest-match rule and fails the build if that path is not the oneAllow: /api/v*/invitepermits. - 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/jsonandAccept-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-limitedrow. 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.