Discord Message Crawler
Pricing
from $0.20 / 1,000 messages
Discord Message Crawler
Scrape entire discord servers, specific channels, or DMs with full metadata: message content, embeds, timestamps, reactions, mentions, polls, and more. If it's there, you will have it.
Pricing
from $0.20 / 1,000 messages
Rating
0.0
(0)
Developer
r. mann
Maintained by CommunityActor stats
1
Bookmarked
1
Total users
0
Monthly active users
5 days ago
Last modified
Categories
Share
Back up and archive Discord servers, channels, and direct messages with full metadata.
Features
- Crawl entire servers automatically, or target specific channels
- Incremental "catch-up" runs plus full historical backfill, with resumable per-channel state
- Optional DM and group-DM export
- Time-bounded exports via snowflake ID or ISO 8601 timestamps
- Configurable request cooldown to stay within Discord rate limits
- Output is plain JSON, one item per message, ready for analysis or downstream processing
Setup
Provide a Discord bot or user token for an account that already has access to the target servers/channels. Bot tokens cover server/channel backups; DM and "include all DMs" features require a user token.
Input schema
{"token": "", // Your Discord token. The only required field."servers": [ // Servers to back up. Each object represents one server.// Duplicate the object as needed, or drop the array into your agent to populate.{"id": "", // Server (guild) ID"name": "", // Optional cosmetic label, used only for logging/output. has no effect on crawling"catchup": true, // Forward sync: fetch messages newer than the last message seen on a previous run.// Has no effect on the first run for a channel (there's nothing to catch up from yet)."backfill": true, // Reverse sync: crawl historical messages backwards from the oldest seen message// towards the start of the channel, until the channel start is reached."channels": [ // Optional. If omitted or empty, every accessible text channel in the// server is discovered and crawled automatically.// Each entry is either a channel ID, or { "id": "", "name"?: "" }.{"id": "", // Channel ID"name": "" // Optional cosmetic label, used only for logging/output}]}],"dmChannels": [ // Direct message / group-DM channels to back up (user tokens only).{"id": "", // Channel ID"name": "" // Optional cosmetic label, used only for logging/output}],"includeAllDms": false, // If true, discover and back up every open DM and group-DM on the account// (user tokens only)."backfillLimit": null, // Optional cap on the number of messages backfilled per channel.// Leave null/empty for no limit (backfill runs to the channel start)."after": "", // Optional global lower bound. Only messages newer than this are crawled.// Accepts a Discord snowflake ID or an ISO 8601 timestamp."before": "", // Optional global upper bound. Only messages older than this are crawled.// Accepts a Discord snowflake ID or an ISO 8601 timestamp."requestCooldown": 3 // Minimum delay, in seconds, between Discord requests. Higher is gentler// on rate limits. recommended is 3 for a mix between efficiency// and rate-limit avoidance.}
Resumable state
Catch-up and backfill progress is tracked per-channel in a named key-value store
(discord-crawler-state), which is saved to your Apify account automatically and persists across runs.
Scheduled/incremental runs automatically continue from where the previous run left off.
FAQ
Where do i find my discord token?
For a user token, you can grab it straight from your browser:
- Log into Discord in Chrome (or another Chromium-based browser).
- Open Developer Tools (3-dot menu > More tools > Developer tools) or press CTRL + SHIFT + I.
- Switch to the "Console" tab, paste the snippet below, and press Enter. Your token will be copied to the clipboard automatically, and you'll see a "Worked!" message confirming it grabbed it successfully.
(()=>{const c=window.webpackChunkdiscord_app;c.push([[Symbol()],{},r=>{if(!r.c)return;for(const mod of Object.values(r.c)){try{if(!mod.exports||mod.exports===window)continue;if(mod.exports?.getToken)return copy(mod.exports.getToken());for(const k in mod.exports){const v=mod.exports[k];if(v?.getToken&&v[Symbol.toStringTag]!=='IntlMessagesProxy')return copy(v.getToken());}}catch(e){}}}]);c.pop();console.log('%cWorked!','font-size:64px');console.log('%cYour token is now on the clipboard!','font-size:24px');})();
What is catchup? What is backfill?
Check the resumable state section above. Note that these values are mutually exclusive: you can either catchup or backfill, From a single point in time. Only one can be true.
What does this actor actually crawl?
Everything accessible to the token you provide.
Every message, in every targeted channel, including attachments metadata,
embeds, reactions, and other fields Discord returns, is crawled and pushed to the dataset as-is.
If you only want specific channels or a specific time range,
use the channels, after, and before fields to scope the run accordingly.
The "API" tab's example code doesn't include my Discord token - is something missing?
No, Apify's auto-generated code samples build the run_input from each input field's
prefill value, but deliberately omit fields marked as secret (like token) so a
placeholder token isn't baked into example code. Add it manually:
run_input = {"token": "<YOUR_DISCORD_TOKEN>","servers": [...]}
I'm getting TypeError: 'int' object is not a mapping, what do I do?
TL;DR - make sure your server/channel IDs are strings and wrapped in "".
This means a server/guild ID or channel ID was entered as a bare number rather
than a string. Discord IDs are 64-bit integers, well beyond the 2^53 limit JavaScript
can represent exactly. When you hit 'copy server ID' on discord it copies a straight number,
and when you later paste it into Apify, the JS based parser rounds it to a near number.
fix: wrap every server, channel, and DM ID in quotes, e.g. "id": "877994882399080558"
instead of "id": 877994882399080558.