Discord Message Scraper avatar

Discord Message Scraper

Pricing

from $0.50 / 1,000 message scrapeds

Go to Apify Store
Discord Message Scraper

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

Khadin Akbar

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

12 days ago

Last modified

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.

FieldTypePurposeExample
discordTokenstringDiscord authentication token used to read messages via the APIYOUR_BOT_TOKEN
tokenTypebot or userSelects bot token handling or user token handlingbot
channelsarray of stringsChannel IDs or Discord channel/message URLs to scrape["112233445566778899"]
maxMessagesPerChannelintegerUpper bound for messages returned per channel500
newestFirstbooleanOrders each channel batch newest-first or oldest-firsttrue
beforeDatestringUpper time bound in ISO 8601 format2024-12-31T23:59:59Z
afterDatestringLower time bound in ISO 8601 formata source-provided date
beforeMessageIdstringExclusive upper boundary by Discord message ID1180000000000000000
afterMessageIdstringExclusive lower boundary by Discord message ID1170000000000000000
filterFromUserIdstringKeeps messages from one Discord user ID223344556677889900
filterContainsstringKeeps messages whose content includes a substringgiveaway
onlyWithAttachmentsbooleanKeeps messages that have at least one attachmentfalse
responseFormatdetailed or conciseChooses full arrays or compact count-based recordsconcise

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.

FieldTypePurposeExample
messageIdstringDiscord message snowflake ID1180000000000000000
channelIdstringChannel ID that owns the message112233445566778899
channelNamestring or nullChannel name, or null for DMs or unresolved channelsgeneral
guildIdstring or nullGuild ID, or null for direct messages998877665544332211
authorIdstring or nullAuthor's Discord user ID223344556677889900
authorUsernamestring or nullAuthor's usernamejdoe
authorGlobalNamestring or nullAuthor's display nameJohn
authorIsBotbooleanWhether the author is a bot accountfalse
contentstringRaw message textgm everyone, the giveaway starts now!
timestampstring or nullISO 8601 sent time2024-03-01T12:00:00.000Z
editedTimestampstring or nullISO 8601 last edit timenull
messageTypestringMessage type labeldefault
isPinnedbooleanPin statusfalse
mentionsEveryonebooleanWhether the message mentions @everyone or @heretrue
attachmentCountintegerAttachment count1
embedCountintegerEmbed count0
reactionCountintegerTotal reaction count12
replyToMessageIdstring or nullID of the replied-to messagenull
jumpUrlstringDirect link to the messagehttps://discord.com/channels/998877665544332211/112233445566778899/1180000000000000000
mentionedUserIdsarrayMentioned user IDs in detailed format["223344556677889900"]
attachmentsarrayAttachment objects in detailed format[{"url":"https://cdn.discordapp.com/...","filename":"banner.png","size":84211,"contentType":"image/png"}]
reactionsarrayReaction objects in detailed format[{"emoji":"🔥","count":12}]
stickerNamesarraySticker 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, and jumpUrl provide message-level provenance.
  • timestamp, authorUsername, and authorId identify when and who sent the message.
  • attachmentCount, reactionCount, and embedCount help agents summarize message structure quickly.
  • In detailed mode, attachments, reactions, mentionedUserIds, and stickerNames provide richer payloads.
  • In concise mode, the Actor keeps the payload smaller by returning counts instead of full arrays.

Provenance, scope, pagination, and cost guidance:

  • beforeDate, afterDate, beforeMessageId, and afterMessageId support bounded and incremental collection.
  • newestFirst controls ordering inside each channel.
  • filterFromUserId, filterContains, and onlyWithAttachments narrow the returned dataset after fetch.
  • Lower maxMessagesPerChannel when 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 beforeMessageId or afterMessageId for exact resume and incremental collection.
  • Use filterFromUserId when the workflow needs messages from one author.
  • Use onlyWithAttachments when the workflow centers on media links or file-bearing posts.
  • Use concise output 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.

  • Discord Member Scraper - Use after message collection when your next workflow step needs member-focused data alongside message history.