Discord Message Scraper
Pricing
from $0.50 / 1,000 message scrapeds
Discord Message Scraper
Scrape Discord channel & DM messages via the official API with your own bot or user token — content, author, timestamps, attachments, reactions, replies. HTTP-only, MCP-ready.
Pricing
from $0.50 / 1,000 message scrapeds
Rating
0.0
(0)
Developer
Khadin Akbar
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
12 days ago
Last modified
Categories
Share
Discord Message Scraper is an Apify Actor for collecting Discord channel and DM messages through the Discord REST API using your own bot token or user token. It accepts Discord channel IDs or Discord channel/message URLs and writes one dataset record per message, including content, author identity, timestamps, attachments, reactions, replies, and a direct jump link.
The one-record meaning is one Discord message. Valuable fields for downstream workflows include content, authorUsername, authorGlobalName, timestamp, attachmentCount, reactionCount, replyToMessageId, and jumpUrl. The outcome is structured Discord message history that is ready for review, analysis, automation, and Apify MCP use.
Best fit and connected workflows
This Actor fits workflows that need message-level Discord history from channels or DMs that the provided token can access. It routes naturally into these next steps:
- collecting a channel history for analysis, archiving, or review,
- capturing a date window or continuing from a known message ID,
- filtering by author, text, or attachment presence,
- feeding structured Discord conversation data to an AI agent through Apify MCP.
For a connected workflow that focuses on member-centric Discord data after message collection, pair this Actor with Discord Member Scraper. That workflow moves from message history into member detail lookup for the same Discord workspace.
Practical scenario
Maya manages a support community. She starts with a channel ID for #announcements, a bot token, and a one-month date window. The Actor returns records with content, authorUsername, timestamp, reactionCount, and jumpUrl. Maya uses reactionCount to spot posts that drew attention, opens jumpUrl to review the source message, and then reuses the same collection pattern for the next announcement cycle.
Input
Required input is channels. The remaining fields narrow the scrape or change the record shape.
| Field | Type | Purpose | Example |
|---|---|---|---|
discordToken | string | Discord authentication token used to read messages via the API | YOUR_BOT_TOKEN |
tokenType | bot or user | Selects bot token handling or user token handling | bot |
channels | array of strings | Channel IDs or Discord channel/message URLs to scrape | ["112233445566778899"] |
maxMessagesPerChannel | integer | Upper bound for messages returned per channel | 500 |
newestFirst | boolean | Orders each channel batch newest-first or oldest-first | true |
beforeDate | string | Upper time bound in ISO 8601 format | 2024-12-31T23:59:59Z |
afterDate | string | Lower time bound in ISO 8601 format | a source-provided date |
beforeMessageId | string | Exclusive upper boundary by Discord message ID | 1180000000000000000 |
afterMessageId | string | Exclusive lower boundary by Discord message ID | 1170000000000000000 |
filterFromUserId | string | Keeps messages from one Discord user ID | 223344556677889900 |
filterContains | string | Keeps messages whose content includes a substring | giveaway |
onlyWithAttachments | boolean | Keeps messages that have at least one attachment | false |
responseFormat | detailed or concise | Chooses full arrays or compact count-based records | concise |
Input example
{"discordToken": "YOUR_BOT_TOKEN","tokenType": "bot","channels": ["112233445566778899","https://discord.com/channels/998877665544332211/112233445566778899"],"maxMessagesPerChannel": 250,"afterDate": "2024-01-01","filterContains": "giveaway","onlyWithAttachments": false,"responseFormat": "concise"}
Output
The dataset contains one record per scraped Discord message. The overview view surfaces timestamp, channelName, authorUsername, content, attachmentCount, reactionCount, and jumpUrl for quick review.
| Field | Type | Purpose | Example |
|---|---|---|---|
messageId | string | Discord message snowflake ID | 1180000000000000000 |
channelId | string | Channel ID that owns the message | 112233445566778899 |
channelName | string or null | Channel name, or null for DMs or unresolved channels | general |
guildId | string or null | Guild ID, or null for direct messages | 998877665544332211 |
authorId | string or null | Author's Discord user ID | 223344556677889900 |
authorUsername | string or null | Author's username | jdoe |
authorGlobalName | string or null | Author's display name | John |
authorIsBot | boolean | Whether the author is a bot account | false |
content | string | Raw message text | gm everyone, the giveaway starts now! |
timestamp | string or null | ISO 8601 sent time | 2024-03-01T12:00:00.000Z |
editedTimestamp | string or null | ISO 8601 last edit time | null |
messageType | string | Message type label | default |
isPinned | boolean | Pin status | false |
mentionsEveryone | boolean | Whether the message mentions @everyone or @here | true |
attachmentCount | integer | Attachment count | 1 |
embedCount | integer | Embed count | 0 |
reactionCount | integer | Total reaction count | 12 |
replyToMessageId | string or null | ID of the replied-to message | null |
jumpUrl | string | Direct link to the message | https://discord.com/channels/998877665544332211/112233445566778899/1180000000000000000 |
mentionedUserIds | array | Mentioned user IDs in detailed format | ["223344556677889900"] |
attachments | array | Attachment objects in detailed format | [{"url":"https://cdn.discordapp.com/...","filename":"banner.png","size":84211,"contentType":"image/png"}] |
reactions | array | Reaction objects in detailed format | [{"emoji":"🔥","count":12}] |
stickerNames | array | Sticker names in detailed format | [] |
Output example
{"messageId": "1180000000000000000","channelId": "112233445566778899","channelName": "general","guildId": "998877665544332211","authorId": "223344556677889900","authorUsername": "jdoe","authorGlobalName": "John","authorIsBot": false,"content": "gm everyone, the giveaway starts now!","timestamp": "2024-03-01T12:00:00.000Z","editedTimestamp": null,"messageType": "default","isPinned": false,"mentionsEveryone": true,"attachmentCount": 1,"embedCount": 0,"reactionCount": 12,"replyToMessageId": null,"jumpUrl": "https://discord.com/channels/998877665544332211/112233445566778899/1180000000000000000","mentionedUserIds": ["223344556677889900"],"attachments": [{"url": "https://cdn.discordapp.com/...","filename": "banner.png","size": 84211,"contentType": "image/png"}],"reactions": [{"emoji": "🔥","count": 12}],"stickerNames": []}
How it works
The Actor reads Discord messages through REST API v10 using the token you provide. It pages through each selected channel newest-first by default, applies date and message-ID boundaries, and writes one dataset item for each returned message.
The live contract also defines 429 backoff handling, soft-fail validation, and an honest-fail outcome when every requested channel is fully inaccessible. The dataset schema supports both detailed records and a compact, agent-friendly shape through responseFormat.
Pricing
This Actor uses Pay per event, plus Apify platform usage.
The charged events are:
- Actor start
- Message scraped
The primary event is Message scraped, and Apify also charges Actor start based on RAM usage.
Example in words: if a run returns one hundred messages, the message event is charged one hundred times. If a run returns five hundred messages, the message event is charged five hundred times. Use maxMessagesPerChannel to shape the number of returned records.
Open the live Pricing tab on the Actor page for the current pricing details for both the event model and Apify platform usage.
Use with AI agents (MCP)
This Actor is an Apify Actor usable through Apify MCP. It exposes a Discord message-scraping tool for token-based access and channel targets, returning structured message records that agents can reason over directly.
Exact Actor identity: khadinakbar/discord-message-scraper
Fetch messages from the Discord channel IDs or channel/message URLs in
channels, return one dataset record per message, and include author, timestamps, attachments, reactions, replies, and jump URLs for downstream reasoning.
Output interpretation:
messageId,channelId, andjumpUrlprovide message-level provenance.timestamp,authorUsername, andauthorIdidentify when and who sent the message.attachmentCount,reactionCount, andembedCounthelp agents summarize message structure quickly.- In
detailedmode,attachments,reactions,mentionedUserIds, andstickerNamesprovide richer payloads. - In
concisemode, the Actor keeps the payload smaller by returning counts instead of full arrays.
Provenance, scope, pagination, and cost guidance:
beforeDate,afterDate,beforeMessageId, andafterMessageIdsupport bounded and incremental collection.newestFirstcontrols ordering inside each channel.filterFromUserId,filterContains, andonlyWithAttachmentsnarrow the returned dataset after fetch.- Lower
maxMessagesPerChannelwhen an agent only needs a bounded sample or a targeted refresh. - The run cost follows the per-message event model described in Pricing.
API example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({token: process.env.APIFY_TOKEN,});const input = {discordToken: process.env.DISCORD_TOKEN,tokenType: 'bot',channels: ['112233445566778899'],maxMessagesPerChannel: 100,responseFormat: 'concise',};const run = await client.actor('khadinakbar/discord-message-scraper').call(input);const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Best results and outcome guidance
- Use a bot token when you want a Discord-sanctioned path that reads channels the bot was added to.
- Use channel IDs from Developer Mode when you want precise targeting.
- Use
beforeMessageIdorafterMessageIdfor exact resume and incremental collection. - Use
filterFromUserIdwhen the workflow needs messages from one author. - Use
onlyWithAttachmentswhen the workflow centers on media links or file-bearing posts. - Use
conciseoutput when an agent only needs counts and core message metadata.
Design note
I found that the dataset overview view is centered on timestamp, channelName, authorUsername, content, attachmentCount, reactionCount, and jumpUrl, which keeps the main table useful for quick review before downloading the full dataset.
FAQ
Can I send a channel URL instead of a raw channel ID?
Yes. The channels input accepts either a raw channel ID or a Discord channel/message URL.
Does the dataset include replies and attachments?
Yes. The dataset schema includes replyToMessageId, attachments, reactions, and stickerNames. In concise mode, the Actor keeps the counts while returning a smaller record shape.
When is afterMessageId useful?
It is useful for incremental scrapes that collect only newer messages than a known Discord snowflake ID.
Which Actor fits the next step after message collection?
Use Discord Member Scraper when the next workflow step needs member-focused data alongside message history.
Can this Actor read DMs?
The schema supports direct messages when the token can access them. The guildId field is null for direct messages.
Responsible use
Use credentials you are authorized to provide and read only channels and messages you are permitted to access. Review Discord's Terms of Service, Developer Terms, and applicable privacy rules before collecting or processing message data. Keep token secrets protected, and choose the token type that matches your policy and account risk tolerance.
Related Actors
- Discord Member Scraper - Use after message collection when your next workflow step needs member-focused data alongside message history.