File: Readme.md
DiscordChatExporter
| Development of this project is entirely funded by the community. Consider donating to support! |
|---|
DiscordChatExporter is an application that can be used to export message history from any Discord channel to a file.
It works with direct messages, group messages, and server channels, and supports Discord's dialect of markdown as well as most other rich media features.
[!WARNING]
While DiscordChatExporter allows it, automating user accounts is against Discord TOS and may result in you getting banned.
If possible, use a bot to export chat logs from accessible channels.
Terms of use[[?]](https://github.com/Tyrrrz/.github/blob/prime/docs/why-so-political.md)
By using this project or its source code, for any purpose and in any shape or form, you grant your implicit agreement to all the following statements:
- You condemn Russia and its military aggression against Ukraine
- You recognize that Russia is an occupant that unlawfully invaded a sovereign state
- You support Ukraine's territorial integrity, including its claims over temporarily occupied territories of Crimea and Donbas
- You reject false narratives perpetuated by Russian state propaganda
To learn more about the war and how you can help, click here. Glory to Ukraine! πΊπ¦
Download
- Graphical user interface (desktop app):
- π’ Stable release: look for
DiscordChatExporter.*.zip - π CI build: look for
DiscordChatExporter.*.zip - π¦ Scoop:
scoop install extras/discordchatexporter(community-maintained) - π¦ WinGet:
winget install Tyrrrz.DiscordChatExporter.GUI(community-maintained) - π¦ AUR:
yay -S discord-chat-exporter-gui(community-maintained) - π¦ Nix:
nix-shell -p discordchatexporter-desktop(community-maintained)
- π’ Stable release: look for
- Command-line interface (terminal app):
- π’ Stable release: look for
DiscordChatExporter.Cli.*.zip - π CI build: look for
DiscordChatExporter.Cli.*.zip - π Docker:
docker pull tyrrrz/discordchatexporter - π¦ WinGet:
winget install Tyrrrz.DiscordChatExporter.CLI(community-maintained) - π¦ AUR:
yay -S discord-chat-exporter-cli(community-maintained) - π¦ Nix:
nix-shell -p discordchatexporter-cli(community-maintained)
- π’ Stable release: look for
[!IMPORTANT]
To launch the GUI version of the app on MacOS, you may need to first remove the downloaded file from quarantine.
You can do that by running the following command in the terminal:xattr -rd com.apple.quarantine DiscordChatExporter.app.
[!NOTE]
Community-maintained packages are published independently from this repository and may not always be up to date with the latest release.
[!NOTE]
If you're unsure which build is right for your system, consult with this page to determine your OS and CPU architecture.
Features
- Cross-platform graphical and command-line interfaces
- Authentication via either a user or a bot token
- Multiple output formats: HTML (dark/light), TXT, CSV, JSON
- Support for markdown, attachments, embeds, emoji, and other rich media features
- File partitioning, date ranges, message filtering, and other export options
- Self-contained exports that can be viewed offline
Screenshots
See also
- Chat Analytics β solution for analyzing chat patterns of Discord users, using exports produced by DiscordChatExporter.
- DiscordChatExporter-frontend β convenient viewer for exports produced by DiscordChatExporter.
File: Contributing.md
Contributing
Local Development
This project relies on DevContainers for setting up the local development environment in a consistent and reproducible manner.
Make sure you use VS Code or any other compatible IDE or tooling for it to work.
To interact with the desktop inside the container, you can use the web-based tunnel accessible at http://localhost:6080.
File: global.json
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature"
}
}
File: License.txt
MIT License
Copyright (c) 2017-2026 Oleksii Holub
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
File: DiscordChatExporter.Cli.Tests/Readme.md
DiscordChatExporter Tests
This test suite runs against a real Discord server, specifically created to exercise different behaviors required by the test scenarios.
In order to run these tests locally, you need to join the test server and configure your authentication token.
- Join the test server
- Locate your Discord authentication token
- Add your token to user secrets:
dotnet user-secrets set DISCORD_TOKEN <token> - Run the tests:
dotnet test
[!NOTE]
If you want to add a new test case, please let me know and I will give you the required permissions on the server.
File: DiscordChatExporter.Cli.Tests/xunit.runner.json
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"methodDisplayOptions": "all",
"methodDisplay": "method"
}
File: .devcontainer/devcontainer-lock.json
{
"features": {
"ghcr.io/devcontainers-extra/features/apt-get-packages:1": {
"version": "1.0.8",
"resolved": "ghcr.io/devcontainers-extra/features/apt-get-packages@sha256:776fa11c30c50fa91d5e1bf050444b0f130827457109c349db92e8e126b750ec",
"integrity": "sha256:776fa11c30c50fa91d5e1bf050444b0f130827457109c349db92e8e126b750ec"
},
"ghcr.io/devcontainers/features/desktop-lite:1": {
"version": "1.2.10",
"resolved": "ghcr.io/devcontainers/features/desktop-lite@sha256:3cfd1ed97b027614f3a56d53183d20ebf29e9c36ac58a3d669edf39890e3aec3",
"integrity": "sha256:3cfd1ed97b027614f3a56d53183d20ebf29e9c36ac58a3d669edf39890e3aec3"
},
"ghcr.io/devcontainers/features/dotnet": {
"version": "2.5.0",
"resolved": "ghcr.io/devcontainers/features/dotnet@sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093",
"integrity": "sha256:0fc16547ed4db6d7ff2a9f5981d2b93eb314e568affb9958029ad794f1f9a093"
},
"ghcr.io/nikiforovall/devcontainer-features/dotnet-csharpier:1": {
"version": "1.0.0",
"resolved": "ghcr.io/nikiforovall/devcontainer-features/dotnet-csharpier@sha256:e9938510ef18155c356480544dcb8b4fcb61e259099a917f09280dced3a756e4",
"integrity": "sha256:e9938510ef18155c356480544dcb8b4fcb61e259099a917f09280dced3a756e4",
"dependsOn": [
"ghcr.io/devcontainers/features/dotnet"
]
}
}
}
File: .devcontainer/devcontainer.json
{
"image": "mcr.microsoft.com/devcontainers/dotnet",
"features": {
"ghcr.io/nikiforovall/devcontainer-features/dotnet-csharpier:1": {},
"ghcr.io/devcontainers/features/desktop-lite:1": {
"webPort": "6080"
},
"ghcr.io/devcontainers-extra/features/apt-get-packages:1": {
"packages": [
"xfce4"
]
}
},
"forwardPorts": [
6080
],
"portsAttributes": {
"6080": {
"label": "Desktop",
"protocol": "http",
"onAutoForward": "openPreview"
}
},
"onCreateCommand": ".devcontainer/onCreateCommand.sh",
"customizations": {
"vscode": {
"extensions": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit",
"csharpier.csharpier-vscode",
"icsharpcode.ilspy-vscode",
"dabbinavo.xamlstyler"
],
"settings": {
"[csharp][xml]": {
"editor.defaultFormatter": "csharpier.csharpier-vscode"
},
"files.associations": {
"*.axaml": "xaml"
}
}
}
}
}
File: .docs/Readme.md
Home
Installation & Usage
- Getting started:
Guides
- How to get Token and Channel IDs
- How to use message filters
- Export scheduling with CLI:
Video tutorial
- Video by NoIntro Tutorials (using DiscordChatExporter GUI)
FAQ & Troubleshooting
File: .docs/Docker.md
Docker usage instructions
Docker distribution of DiscordChatExporter provides a way to run the app in a virtualized and isolated environment. Due to the nature of Docker, you also don't need to install any prerequisites otherwise required by DCE.
Note:
Only the CLI flavor of DiscordChatExporter is available for use with Docker.
Pulling
This will download the Docker image from the registry to your computer. You can run this command again to update when a new version is released.
$ docker pull tyrrrz/discordchatexporter:stableNote the :stable tag. DiscordChatExporter images are tagged according to the following patterns:
stableβ latest stable version release. This tag is updated with each release of a new project version. Recommended for personal use.x.y.z(e.g.,2.30.1) β specific stable version release. This tag is pushed when the corresponding version is released and never updated thereafter. Recommended for use in automation scenarios.latestβ latest (potentially unstable) build. This tag is updated with each new commit to theprimebranch. Not recommended, unless you want to test a new feature that has not been released in a stable version yet.
You can see all available tags here.
Usage
To run the CLI in Docker and render help text:
$ docker run --rm tyrrrz/discordchatexporter:stableTo export a channel:
$ docker run --rm -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELIDIf you want colored output and real-time progress reporting, pass the -it (interactive + pseudo-terminal) option:
$ docker run --rm -it -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELIDThe -v /path/on/machine:/out option instructs Docker to bind the /out directory inside the container to a path on your host machine. Replace /path/on/machine with the directory you want the files to be saved at.
Note:
If you are running SELinux, you will need to add the:zoption after/out, e.g.:console$ docker run --rm -v /path/on/machine:/out:z tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELIDFor more information, refer to the Docker docs SELinux labels for bind mounts page.
You can also use the current working directory as the output directory by specifying:
-v $PWD:/outin Bash-v $pwd.Path:/outin PowerShell
For more information, please refer to the Dockerfile and Docker documentation.
To get your Token and Channel IDs, please refer to this page.
Unix permissions issues
This image was designed with a user running as uid:gid of 1000:1000.
If your current user has different IDs, and you want to generate files directly editable for your user, you might want to run the container like this:
$ mkdir data # or chown -R $(id -u):$(id -g) data
$ docker run -it --rm -v $PWD/data:/out --user $(id -u):$(id -g) tyrrrz/discordchatexporter:stable export -t TOKEN -g CHANNELIDEnvironment variables
DiscordChatExpoter CLI accepts the DISCORD_TOKEN environment variable as a fallback for the --token option. You can set this variable either with the --env Docker option or with a combination of the --env-file Docker option and a .env file.
Please refer to the Docker documentation for more information.
File: .docs/Getting-started.md
Getting started
Welcome to the getting started page!
Here you'll learn how to use every DiscordChatExporter (DCE for short) feature.
For other things you can do with DCE, check out the Guides section.
If you still have unanswered questions after reading this page or if you have encountered a problem, please visit our FAQ & Troubleshooting section.
The information presented on this page is valid for all platforms.
GUI or CLI?
DCE has two different versions:
- Graphical User Interface (GUI) - it's the preferred version for newcomers as it is easy to use.
You can get it by downloading theDiscordChatExporter.*.zipfile. - Command-line Interface (CLI) - offers greater flexibility and more features for advanced users, such as export scheduling, ID lists, and more specific date ranges.
You can get it by downloading theDiscordChatExporter.Cli.*.zipfile.
There are dedicated guides for each version:
File formats
HTML
The HTML format replicates Discord's interface, making it the most user-friendly option.
It's the best format for attachment preview and sharing.
You can open .html files with a web browser, such as Google Chrome.
[!WARNING]
If a picture is deleted, or if a user changes its avatar, the respective images will no longer be displayed.
Export using the "Download assets" (--media) option to avoid this.
Plain Text
The Plain Text format formats messages as plain text, and has the smallest size.
You can open .txt files with a text editor, such as Notepad.
JSON
The JSON format contains more technical information and is easily parsable.
You can open .json files with a text editor, such as Notepad.
CSV
The CSV format allows for easy parsing of the chat log. Depending on your needs, the JSON format might be better.
You can open .csv files with a text editor, such as Notepad, or a spreadsheet app, like Microsoft Excel and Google Sheets.
File: .docs/Message-filters.md
Message filters
You can use a special notation to filter messages that you want to have included in an export. The notation syntax is designed to mimic Discord's search query syntax, but with additional capabilities.
To configure a filter, specify it in advanced export parameters when using the GUI or by passing the --filter option when using the CLI. For the CLI version, see also caveats.
Examples
- Filter by user
from:Tyrrrz- Filter by user (with discriminator)
from:Tyrrrz#1234- Filter by message content (allowed values:
link,embed,file,video,image,sound)
has:image- Filter by mentioned user (same rules apply as with
from:filter)
mentions:Tyrrrz#1234- Filter by contained text (has word "hello" and word "world" somewhere in the message text):
hello world- Filter by contained text (has the string "hello world" somewhere in the message text):
"hello world"- Combine multiple filters ('and'):
from:Tyrrrz has:image- Same thing but with an explicit operator:
from:Tyrrrz & has:image- Combine multiple filters ('or'):
from:Tyrrrz | from:"96-LB"- Combine multiple filters using groups:
(from:Tyrrrz | from:"96-LB") has:image- Negate a filter:
-from:Tyrrrz | -has:image- Negate a grouped filter:
-(from:Tyrrrz has:image)- Escape special characters (
-is escaped below, so it's not parsed as negation operator):
from:96\-LBCLI Caveats
In most cases, you will need to enclose your filter in quotes (") to escape characters that may have special meaning in your shell:
$ ./DiscordChatExporter.Cli export [...] --filter "from:Tyrrrz has:image"If you need to include quotes inside the filter itself as well, use single quotes (') for those instead:
$ ./DiscordChatExporter.Cli export [...] --filter "from:Tyrrrz 'hello world'"Additionally, negated filters (those that start with -) may cause parsing issues even when enclosed in quotes. To avoid this, use the tilde (~) character instead of the dash (-):
$ ./DiscordChatExporter.Cli export [...] --filter ~from:TyrrrzFile: .docs/Scheduling-Linux.md
Scheduling exports with Cron
Creating the script
- Open Terminal and create a new text file with
nano /path/to/DiscordChatExporter/cron.sh
Note:
You can't use your mouse in nano, use the arrow keys to control the cursor (caret).
- Paste the following into the text file:
#!/bin/bash
# Info: https://github.com/Tyrrrz/DiscordChatExporter/blob/prime/.docs
TOKEN=tokenhere
CHANNELID=channelhere
DLLFOLDER=dceFOLDERpathhere
FILENAME=filenamehere
EXPORTDIRECTORY=dirhere
EXPORTFORMAT=formathere
# Available export formats: plaintext, htmldark, htmllight, json, csv
# /\ CaSe-SeNsItIvE /\
# You can edit the export command on line 40 if you'd like to include more options like date ranges and date format. You can't use partitioning (-p) with this script.
# This will verify if EXPORTFORMAT is valid and will set the final file extension according to it. If the format is invalid, the script will display a message and exit.
if [[ "$EXPORTFORMAT" == "plaintext" ]]; then
FORMATEXT=.txt
elif [[ "$EXPORTFORMAT" == "htmldark" ]] || [[ "$EXPORTFORMAT" == "htmllight" ]]; then
FORMATEXT=.html
elif [[ "$EXPORTFORMAT" == "json" ]]; then
FORMATEXT=.json
elif [[ "$EXPORTFORMAT" == "csv" ]]; then
FORMATEXT=.csv
else
echo "$EXPORTFORMAT - Unknown export format"
echo "Available export formats: plaintext, htmldark, htmllight, csv, json"
echo "/\ CaSe-SeNsItIvE /\\"
exit 1
fi
# This will change the script's directory to DLLPATH, if unable to do so, the script will exit.
cd $DLLFOLDER || exit 1
# This will export your chat
./DiscordChatExporter.Cli export -t $TOKEN -c $CHANNELID -f $EXPORTFORMAT -o $FILENAME.tmp
# This sets the current time to a variable
CURRENTTIME=$(date +"%Y-%m-%d-%H-%M-%S")
# This will move the .tmp file to the desired export location, if unable to do so, it will attempt to delete the .tmp file.
if ! mv "$FILENAME.tmp" "${EXPORTDIRECTORY//\"}/$FILENAME-$CURRENTTIME$FORMATEXT" ; then
echo "Unable to move $FILENAME.tmp to $EXPORTDIRECTORY/$FILENAME-$CURRENTTIME$FORMATEXT."
echo "Cleaning up..."
if ! rm -Rf "$FILENAME.tmp" ; then
echo "Unable to remove $FILENAME.tmp."
fi
exit 1
fi
exit 0- Replace:
tokenherewith your Token.channelherewith a Channel ID.dceFOLDERpathherewith DCE's directory path (e.g.,/path/to/folder, NOT/path/to/folder/DiscordChatExporter.dll).filenameherewith the exported channel's filename, without spaces.dirherewith the export directory (e.g., /home/user/Documents/Discord\ Exports).formatherewith one of the available export formats.
Note:
Remember to escape spaces (add\before them) or to quote (") the paths ("/home/my user")!
Note:
To save, hold down CTRL and then press O, if asked for a filename, type it and press ENTER. Hit CTRL+X to exit the text editor.
Check out this page if you want to know more about nano.
Make your script executable with
chmod +x /path/to/DiscordChatExporter/cron.shLet's edit the cron file. If you want to run the script with your user privileges, edit it by running
crontab -e. If you want to run the script as root, edit it withsudo crontab -e. If this is your first time running this command, you might be asked to select a text editor. Nano is easier for beginners.Add the following to the end of the file
* * * * * /path/to/DiscordChatExporter/cron.sh >/tmp/discordchatexporter.log 2>/tmp/discordchatexportererror.log. Don't forget to replace the/path/to/DiscordChatExporter/cron.sh!
Note:
If you don't want logs to be created, replace both/tmp/discordchatexporter.logwith/dev/null.
Then replace the *s according to:
Examples:
- If you want to execute the script at minute 15 of every hour:
15 * * * * - Every 30 minutes
*/30 * * * * - Every day at midnight
0 0 * * * - Every day at noon
0 12 * * * - Every day at 3, 4 and 6 PM
0 15,16,18 * * * - Every Wednesday at 9 AM
0 9 * * 3
Verify your cron time here.
Additional information
The week starts on Sunday. 0 = SUN, 1 = MON ... 7 = SUN.
Be aware that if you set the day to '31', the script will only run on months that have the 31st day.
Learn more about running a cron job on the last day of the month here (expert).
The default filename for the exported channel is YYYY-MM-DD-hh-mm-ss-yourfilename. You can change it if you'd like.
Don't forget to update your token in the script after it has been reset!
Special thanks to @Yudi
File: .docs/Scheduling-MacOS.md
Scheduling exports on macOS
Creating the script
Open TextEdit.app and create a new file
Convert the file to a plain text one in 'Format > Make Plain Text' (β§βT)
Paste the following into the text editor:
#!/bin/bash
# Info: https://github.com/Tyrrrz/DiscordChatExporter/blob/prime/.docs
TOKEN=tokenhere
CHANNELID=channelhere
DLLFOLDER=dceFOLDERpathhere
FILENAME=filenamehere
EXPORTDIRECTORY=dirhere
EXPORTFORMAT=formathere
# Available export formats: plaintext, htmldark, htmllight, json, csv
# /\ CaSe-SeNsItIvE /\
# You can edit the export command on line 43 if you'd like to include more options like date ranges and date format. You can't use partitioning (-p) with this script.
# This variable specifies in which directories the executable programs are located. Don't change it.
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/share/dotnet
# This will verify if EXPORTFORMAT is valid and will set the final file extension according to it. If the format is invalid, the script will display a message and exit.
if [[ "$EXPORTFORMAT" == "plaintext" ]]; then
FORMATEXT=.txt
elif [[ "$EXPORTFORMAT" == "htmldark" ]] || [[ "$EXPORTFORMAT" == "htmllight" ]]; then
FORMATEXT=.html
elif [[ "$EXPORTFORMAT" == "json" ]]; then
FORMATEXT=.json
elif [[ "$EXPORTFORMAT" == "csv" ]]; then
FORMATEXT=.csv
else
echo "$EXPORTFORMAT - Unknown export format"
echo "Available export formats: plaintext, htmldark, htmllight, csv, json"
echo "/\ CaSe-SeNsItIvE /\\"
exit 1
fi
# This will change the script's directory to DLLPATH, if unable to do so, the script will exit.
cd $DLLFOLDER || exit 1
# This will export your chat
./DiscordChatExporter.Cli export -t $TOKEN -c $CHANNELID -f $EXPORTFORMAT -o $FILENAME.tmp
# This sets the current time to a variable
CURRENTTIME=$(date +"%Y-%m-%d-%H-%M-%S")
# This will move the .tmp file to the desired export location. If unable to do so, it will attempt to delete the .tmp file.
if ! mv "$FILENAME.tmp" "${EXPORTDIRECTORY//\"}/$FILENAME-$CURRENTTIME$FORMATEXT" ; then
echo "Unable to move $FILENAME.tmp to $EXPORTDIRECTORY/$FILENAME-$CURRENTTIME$FORMATEXT."
echo "Cleaning up..."
if ! rm -Rf "$FILENAME.tmp" ; then
echo "Unable to remove $FILENAME.tmp."
fi
exit 1
fi
exit 0- Replace:
tokenherewith your Tokenchannelherewith a Channel IDdceFOLDERpathherewith DCE's directory's path (e.g.,/Users/user/Desktop/DiscordChatExporterFolder, NOT/Users/user/Desktop/DiscordChatExporterFolder/DiscordChatExporter.DLL)filenameherewith the exported channel's filename, without spacesdirherewith the directory you want the files to be saved at (e.g.,/Users/user/Documents/Discord\ Exports)formatherewith one of the available export formats
To quickly get file or folder paths, select the file/folder, then hit Command+I (βI) and copy what's after Where:.
After copying and pasting, make sure the file/folder name is not missing. If a folder has spaces in its name, add \ before the spaces, like in the example below:
Discord\ Exports- Wrong β/Users/user/Documents- Wrong β/Users/user/Documents/Discord Exports- Wrong β/Users/user/Documents/Discord\ Exports/DCE.Cli.dll- Wrong β/Users/user/Documents/Discord \Exports- Wrong β/Users/user/Documents/Discord\ Exports- Correct β/Users/user/Desktop/DiscordChatExporter- Correct β
- Save the file as
filename.sh, not.txt - Open Terminal.app, type
chmod +x, press the SPACE key, then drag & drop thefilename.shinto the Terminal window and hit RETURN. You may be prompted for your password, and you won't be able to see it as you type.
Creating the .plist file
Open TextEdit, make a Plain Text (β§βT) and then paste the following into it:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.discordchatexporter</string>
<key>Program</key>
<string>/path/to/filename.sh</string>
REPLACEME
</dict>
</plist>- The
Labelstring is the name of the export job, it must be something unique. Replace thelocal.discordchatexporterbetween the<string>with another name if you'd like to run more than one script. - The
Programstring is the path to the script. Replace/path/to/filename.shbetween the<string>with the path of the previously created script. - Replace the
REPLACEMEwith the content presented in the following sections according to when you want to export.
When you're done, save the file with the same name as the Label and with the .plist extension (not .txt), like local.discordchatexporter.plist.
Exporting on System Boot/User Login
<key>RunAtLoad</key>
<true/>Export every _n_ seconds
The following example is to export every 3600 seconds (1 hour), replace the integer value with your desired time:
<key>StartInterval</key>
<integer>3600</integer>Export at a specific time and date
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>0</integer>
<key>Month</key>
<integer>0</integer>
<key>Day</key>
<integer>0</integer>
<key>Hour</key>
<integer>0</integer>
<key>Minute</key>
<integer>0</integer>
</dict>| Key | Integer |
|---|---|
| Month | 1-12 |
| Day | 1-31 |
| Weekday | 0-6 (0 is Sunday) |
| Hour | 0-23 |
| Minute | 0-59 |
Sunday - 0; Monday - 1; Tuesday - 2; Wednesday - 3; Thursday - 4; Friday - 5; Saturday - 6
Replace the template's 0s according to the desired times.
You can delete the <key>s you don't need, don't forget to remove the 0 under it.
Omitted keys are interpreted as wildcards, for example, if you delete the Minute key, the script will run at every minute, delete the Weekday key and it'll run at every weekday, and so on.
Be aware that if you set the day to '31', the script will only run on months that have the 31st day.
Check the examples below (or skip to step 3 (loading the file)):
Export everyday at 5:15 PM:
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>17</integer>
<key>Minute</key>
<integer>15</integer>
</dict>Every 15 minutes of an hour (xx:15):
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>15</integer>
</dict>Every Sunday at midnight and every Wednesday full hour (xx:00). Notice the inclusion of <array> and </array> to allow multiple values:
<key>StartCalendarInterval</key>
<array>
<dict>
<key>Weekday</key>
<integer>0</integer>
<key>Hour</key>
<integer>00</integer>
<key>Minute</key>
<integer>00</integer>
</dict>
<dict>
<key>Weekday</key>
<integer>3</integer>
<key>Minute</key>
<integer>00</integer>
</dict>
</array>Loading the .plist into launchctl
- Copy your
filename.plistfile to one of these folders according to how you want it to run:
~/Library/LaunchAgentsruns as the current logged-in user./Library/LaunchDaemonsruns as the system "administrator" (root).If macOS has a single user:
- If you want to export only when the user is logged in, choose the first one.
- If you want the script to always run on System Startup, choose the second one.
If macOS has multiple users:
- If you want the script to run only when a certain user is logged in, choose the first one.
- If you want the script to always run on System Startup, choose the second one.
To quickly go to these directories, open Finder and press Command+Shift+G (ββ§G), then paste the path into the text box.
- To load the job into launchctl, in Terminal, type
launchctl load, press SPACE, drag and drop the.plistinto the Terminal window, then hit RETURN. It won't output anything if it was successfully loaded.
Extra launchctl commands
Unloading a job
launchctl unload /path/to/Library/LaunchAgents/local.discordchatexporter.plistList every loaded job
launchctl listCheck if a specific job is enabled
You can also see error codes (2nd number) by running this command.
launchctl list | grep local.discordchatexporterFurther reading: Script management with launchd in Terminal on Mac and launchd.info.
Special thanks to @Yudi
File: .docs/Scheduling-Windows.md
Scheduling exports on Windows
Creating the script
- Open a text editor such as Notepad and paste:
# Info: https://github.com/Tyrrrz/DiscordChatExporter/blob/prime/.docs
$TOKEN = "tokenhere"
$CHANNEL = "channelhere"
$EXEPATH = "exefolderhere"
$FILENAME = "filenamehere"
$EXPORTDIRECTORY = "dirhere"
$EXPORTFORMAT = "formathere"
# Available export formats: PlainText, HtmlDark, HtmlLight, Json, Csv
cd $EXEPATH
./DiscordChatExporter.Cli export -t $TOKEN -c $CHANNEL -f $EXPORTFORMAT -o "$FILENAME.tmp"
$Date = Get-Date -Format "yyyy-MM-dd-HH-mm"
If($EXPORTFORMAT -match "PlainText"){mv "$FILENAME.tmp" -Destination "$EXPORTDIRECTORY\$FILENAME-$Date.txt"}
ElseIf($EXPORTFORMAT -match "HtmlDark"){mv "$FILENAME.tmp" -Destination "$EXPORTDIRECTORY\$FILENAME-$Date.html"}
ElseIf($EXPORTFORMAT -match "HtmlLight"){mv "$FILENAME.tmp" -Destination "$EXPORTDIRECTORY\$FILENAME-$Date.html"}
ElseIf($EXPORTFORMAT -match "Json"){mv "$FILENAME.tmp" -Destination "$EXPORTDIRECTORY\$FILENAME-$Date.json"}
ElseIf($EXPORTFORMAT -match "Csv"){mv "$FILENAME.tmp" -Destination "$EXPORTDIRECTORY\$FILENAME-$Date.csv"}
exit- Replace:
tokenherewith your Tokenchannelherewith a Channel IDexefolderherewith the .exe directory's path (e.g., C:\Users\User\Desktop\DiscordChatExporter)filenameherewith a filename without spacesdirherewith the export directory (e.g., C:\Users\User\Documents\Exports)formatherewith one of the available export formats
Make sure not to delete the quotes (")
- Save the file as
filename.ps1, not as.txt
Note: You can also modify the script to use other options, such as
include-threadsor switch to a different command, e. g.exportguild.
Export at Startup
- Press Windows + R, type
shell:startupand press ENTER - Paste
filename.ps1or a shortcut into this folder
Scheduling with Task Scheduler
Please note that your computer must be turned on for the export to happen.
Press Windows + R, type
taskschd.mscand press ENTERSelect
Task Scheduler Library, create a Basic Task, and follow the instructions on-screenAt 'Start a Program', write
powershell -file -ExecutionPolicy ByPass -WindowStyle Hidden "C:\path\to\filename.ps1"in the Program/script text boxClick 'Yes'
Click 'Finish'
Special thanks to @Yudi
File: .docs/Token-and-IDs.md
Obtaining Token and Channel IDs
[!WARNING]
Do not share your token! A token gives full access to an account.
To reset a user token, change your account password.
To reset a bot token, click on Reset Token in the bot settings.
How to get a user token
Caution: Automating user accounts violates Discord's terms of service and may result in account termination. Use at your own risk.
Through your web browser
Prerequisite step: Navigate to discord.com and login.
In Chrome
Using the console
Press Ctrl+Shift+I (β₯+β+I on macOS). Chrome's DevTools tools will display.
Click the
Consoletab. The console will open.Type
jslet m;webpackChunkdiscord_app.push([[Math.random()],{},e=>{for(let i in e.c){let x=e.c[i];if(x?.exports?.getToken){m=x;break}}}]);m&&console.log("Token:",m.exports.getToken());into the console and press Enter. The console will display your user token.
Using the network monitor
Press Ctrl+Shift+I (β₯+β+I on macOS). Chrome's DevTools tools will display.
Click the
Networktab. The network panel will openPress F5. The page will reload, and the network log (the lower half of the network panel) will display several entries.
Click the text box labelled
Filterand typemessages. The entries will filter down to a single request namedmessages. If the request doesn't appear, switch to any other Discord channel to trigger it.Click the entry named
messages. A panel will open to the right and display details about the entry. Click theHeaderstab if it isn't already active.Scroll through the contents of the
Headerstab until you find an entry beginning withauthorization:.Right-click the entry and click
copy value.
Using the storage inspector
Press Ctrl+Shift+I (β₯+β+I on macOS). Chrome's DevTools will display.
Press Ctrl+Shift+M (β+Shift+M). Chrome will enter Device Mode, and the webpage will display as if on a mobile device.
If necessary, click the
Β»at the right end of the tab bar, and clickApplication. The application panel will display.In the menu to the right, under
Storage, expandLocal Storageif necessary, then clickhttps://discord.com. The pane to the right will display a list of key-value pairs.In the text box marked
Filter, typetoken. The entries will filter down to those containing the stringtoken.Click the
tokenentry. (Note: if the token doesn't display, try refreshing by pressing F5 or β+R on macOS)Click the text box at the bottom, press Ctrl+A (β+A on macOS) then Ctrl+C (β+C on macOS) to copy the value to your clipboard.
In Firefox
Using the console
Press Ctrl+Shift+K (β₯+β+K on macOS). Firefoxβs web developer tools will display at the bottom of the window, and the web console will display.
Click the
Consoletab. The console will open.Type
jslet m;webpackChunkdiscord_app.push([[Math.random()],{},e=>{for(let i in e.c){let x=e.c[i];if(x?.exports?.getToken){m=x;break}}}]);m&&console.log("Token:",m.exports.getToken());into the console and press Enter. The console will display your user token.
Using the network monitor
Press Ctrl+Shift+E (β₯+β+E on macOS). Firefoxβs web developer tools will display at the bottom of the window, and the network monitor will display.
Press F5. The page will reload, and the network request list will populate with entries.
Type
messagesinto the filter. The network request list will filter out any entries not containing the stringmessages. If the request doesn't appear, switch to any other Discord channel to trigger it.Click
messages. The network request details pane will display. The headers tab should be active by default. If it isnβt, click it.Type
authorizationinto the text box labelledFilter Headers.Scroll down until you see an entry labeled authorization under
Request Headers.Right-click the entry labeled
authorizationand selectcopy value.
Using the storage inspector
Press Shift+F9. Firefoxβs web developer tools will display at the bottom of the window, and the storage panel will be selected.
Press Ctrl+Shift+M (β₯+β+M on macOS). Firefox will toggle responsive design mode, and the web page will display as if on a mobile device. (Note: Discord may steal focus and respond to the command by toggling mute. If this happens, return focus to Firefoxβs web developer tools by clicking somewhere in it, then try the command again.)
In the storage tree (the list on the left side of the web developer tools panel), click Local Storage. The entry will expand, and the entry
https://discord.comwill display beneath it.In the storage tree, click
https://discord.com. The table widget to the right of the storage tree will display several key-value pairs.In the text box labelled
Filter itemsat the top of the table widget, entertoken. The table will now only display entries containing the stringtoken.Click the entry
token. The sidebar will display. (Note: If the token doesnβt display, try refreshing by pressing F5.)Right-click the single entry in the sidebar and select
copy.
Through the desktop app / enabling web developer tools
By editing the settings file
If Discord is running, exit the application by right-clicking the icon in your taskbar tray and clicking
Quit Discord.Open Discord's settings file in your preferred text editor. See the following table for help finding it:
OS Stable Canary Public Test Build (PTB) Windows %APPDATA%\discord\settings.json%APPDATA%\discordcanary\settings.json%APPDATA%\discordptb\settings.jsonmacOS ~/Library/Application Support/discord/settings.json~/Library/Application Support/discordcanary/settings.json~/Library/Application Support/discordptb/settings.jsonLinux ~/.config/discord/settings.json~/.config/discordcanary/settings.json~/.config/discordptb/settings.jsonIf you use BetterDiscord, use the following table instead:
OS Stable Canary Public Test Build (PTB) Windows %APPDATA%\BetterDiscord\data\stable\settings.json%APPDATA%\BetterDiscord\data\canary\settings.json%APPDATA%\BetterDiscord\data\ptb\settings.jsonmacOS ~/Library/Application Support/BetterDiscord/data/stable/settings.json~/Library/Application Support/BetterDiscord/data/canary/settings.json~/Library/Application Support/BetterDiscord/data/ptb/settings.jsonLinux ~/.config/BetterDiscord/data/stable/settings.json~/.config/BetterDiscord/data/canary/settings.json~/.config/BetterDiscord/data/ptb/settings.jsonInsert a blank line after the first curly bracket (
{), add the text"DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING": true,to it, and save the file. Your file should resemble the following:
{
"DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING": true,
"BACKGROUND_COLOR": "#202225",
"IS_MAXIMIZED": true
}Launch Discord.
To find your user token, continue here.
Via settings menu (BetterDiscord only)
Click the User Settings button (the gear icon to the right of your username). Discordβs settings page will open.
In the sidebar to the left, click
Settingsunder theBetterDiscordgroup. BetterDiscordβs settings page will display.In the main panel to the right, expand the
Developer Settingsgroup if necessary, and toggleDevToolsto enabled.Press Esc. The settings page will close.
To find your user token, continue here.
How to export with a bot token
Step 1 - Create an application
You can create a new application or use an existing one. If you want to create a new one:
- Go to Discord developer portal
- Click on New Application in the top right corner
- Enter a name for your application and click Create
Step 2 - Invite the bot to your server
The bot needs to be invited to the server you'd like to export from.
- Go to Discord developer portal
- Navigate to General Information on the left
- Copy the Application ID
- Open the following URL in your browser, replacing
YOUR_APP_IDwith the copied Client ID:
https://discord.com/oauth2/authorize?scope=bot&permissions=66560&client_id=YOUR_APP_IDStep 3 - Ensure message content intent is enabled
If this option is not enabled, the exported files will be empty.
- Go to Discord developer portal
- Open your Application's settings
- Navigate to the Bot section on the left
- Scroll down to the Privileged Gateway Intents section
- Enable Message Content Intent by toggling the switch
Step 4 - Copy the bot token
If you don't have a bot token yet or if you've lost it, follow these steps to reset it:
- Go to Discord developer portal
- Open your Application's settings
- Navigate to the Bot section on the left
- Under Token click Reset Token
- Click Yes, do it! and authenticate to confirm
Tip:
As the token is only shown once, make sure to store it in a safe place. If you lose the token, you will have to reset it again.
[!WARNING]
Resetting the token will invalidate the old one. Any integrations relying on the old token will cease to function until they are updated.
How to get a Server ID or a Channel ID
- Open Discord Settings
- Go to the Advanced section
- Enable Developer Mode
- Right-click on the desired server or channel and click Copy Server ID or Copy Channel ID
File: .docs/Troubleshooting.md
Troubleshooting
Welcome to the Frequently Asked Questions (FAQ) and Troubleshooting page!
Here you'll find the answers to most of the questions related to DiscordChatExporter (DCE for short) and its core features.
- β If you still have unanswered questions after reading this page, feel free to create a new discussion.
- π If you have encountered a problem that's not described here, has not been discussed before, and is not a known issue, please create a new discussion or open a bug report. Don't forget to include your platform (Windows, Mac, Linux, etc.) and a detailed description of your question/problem.
General questions
Token stealer?
No. That's why this kind of software needs to be open-source, so the code can be audited by anyone.
Your token is only used to connect to Discord's API, it's not sent anywhere else.
If you're using the GUI, be aware that your token will be saved to a plain text file unless you disable it in the settings menu.
Why should I be worried about the safety of my token?
A token can be used to log into your account, so treat it like a password and never share it.
How can I reset my token?
Follow the instructions here.
Will I get banned if I use this?
Automating user accounts is technically against TOS, use at your discretion. Bot accounts don't have this restriction.
Will the messages disappear from the exported file if I delete a message, delete my account or block a person?
Text messages will not be removed from the exported file, but if media, such as images and user avatars, is changed or deleted, it will no longer be displayed. To avoid this, export using the "Download media" (--media) option.
Can DCE export messages that have already been deleted?
No, DCE cannot access them since they have been permanently deleted from Discord's servers.
Can DCE export private chats?
Yes, if your account has access to them.
Can DCE download images?
Yes, and other media too. Export using the "Download media" (--media) option.
Can the exported chats be shared?
Yes.
Can DCE export multiple formats at once?
No, you can only export one format at a time.
Can DCE recreate the exported chats in Discord?
No, DCE is an exporter.
Can DCE reupload exported messages to another channel?
No, DCE is an exporter.
Can DCE add new messages to an existing export?
No.
First steps
How can I find my token?
Check the following page: Obtaining token
When I open DCE a black window pops up quickly or nothing shows up
You might have downloaded the CLI flavor of the app, which is meant to be run in a terminal. Try downloading the GUI instead if that's what you want.
How can I set DCE to export automatically at certain times?
Check the following pages to learn how to schedule DiscordChatExporter.CLI runs (advanced):
The exported file is too large, I can't open it
Try opening it with a different program, try partitioning or use a different file format, like PlainText.
I see messages in the export, but they have no content
Your bot is missing the 'Message Content Intent'. Go to the Discord Developer Portal, navigate to the 'Bot' section and enable it.
CLI
How do I use the CLI?
Check the following page:
If you're using Docker, please refer to the Docker Usage Instructions instead.
Where can I find the 'Channel IDs'?
Check the following page:
I can't find Docker exported chats
Check the following page:
I can't export Direct Messages
Make sure you're copying the DM Channel ID, not the person's user ID.
Errors
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Authentication token is invalid.β³ Make sure the provided token is correct.
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Requested resource does not exist.β³ Check your channel ID, it might be invalid. Read this if you need help.
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Access is forbidden.β³ This means you don't have access to the channel.
System.Net.WebException: Error: TrustFailure ... Invalid certificate received from server.β³ Try running cert-sync.
Debian/Ubuntu: cert-sync /etc/ssl/certs/ca-certificates.crt
Red Hat: cert-sync --user /etc/pki/tls/certs/ca-bundle.crt
If it still doesn't work, try mozroots: mozroots --import --ask-remove
macOS-specific
DiscordChatExporter is damaged and canβt be opened. You should move it to the Trash.
Check the Using the GUI page for instructions on how to run the app.
β If you still have unanswered questions, feel free to create a new discussion.
π If you have encountered a problem that's not described here, has not been discussed before, and is not a known issue, please create a new discussion or open a bug report.
File: .docs/Using-the-CLI.md
Using the CLI
Step 1
After extracting the .zip archive, open your preferred terminal.
Step 2
Change the current directory to DCE's folder with cd C:\path\to\DiscordChatExporter (cd /path/to/DiscordChatExporter on MacOS and Linux), then press ENTER to run the command.
Windows users can quickly get the folder's path by clicking the address bar while inside the folder.
macOS users can press Command+Option+C (ββ₯C) while inside the folder (or selecting it) to copy its path to the clipboard.
You can also drag and drop the folder on every platform.
Step 3
Now we're ready to run the commands.
Type the following command in your terminal of choice, then press ENTER to run it. This will list all available subcommands and options.
./DiscordChatExporter.CliNote:
On Windows, if you're using the default Command Prompt (cmd), omit the leading./at the start of the command.
Docker users, please refer to the Docker usage instructions.
CLI commands
| Command | Description |
|---|---|
| export | Exports a channel |
| exportdm | Exports all direct message channels |
| exportguild | Exports all channels within the specified server |
| exportall | Exports all accessible channels |
| channels | Outputs the list of channels in the given server |
| dm | Outputs the list of direct message channels |
| guilds | Outputs the list of accessible servers |
| guide | Explains how to obtain token, server, and channel ID |
To use the commands, you'll need a token. For the instructions on how to get a token, please refer to this page, or run ./DiscordChatExporter.Cli guide.
To get help with a specific command, run:
./DiscordChatExporter.Cli command --helpFor example, to figure out how to use the export command, run:
./DiscordChatExporter.Cli export --helpExport a specific channel
You can quickly export with DCE's default settings by using just -t token and -c channelid.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555Changing the format
You can change the export format to HtmlDark, HtmlLight, PlainText Json or Csv with -f format. The default
format is HtmlDark.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -f JsonChanging the output filename
You can change the filename by using -o name.ext. e.g., for the HTML format:
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -o myserver.htmlChanging the output directory
You can change the export directory by using -o and providing a path that ends with a slash or does not have a file
extension.
If any of the folders in the path have a space in its name, escape them with quotes (").
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -o "C:\Discord Exports"Changing the filename and output directory
You can change both the filename and export directory by using -o directory\name.ext.
Note that the filename must have an extension, otherwise it will be considered a directory name.
If any of the folders in the path have a space in its name, escape them with quotes (").
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -o "C:\Discord Exports\myserver.html"Generating the filename and output directory dynamically
You can use template tokens to generate the output file path based on the server and channel metadata.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -o "C:\Discord Exports\%G\%T\%C.html"Assuming you are exporting a channel named "my-channel" in the "Text channels" category from a server
called "My server", you will get the following output file
path: C:\Discord Exports\My server\Text channels\my-channel.html
Here is the full list of supported template tokens:
%g- server ID%G- server name%t- category ID%T- category name%c- channel ID%C- channel name%p- channel position%P- category position%a- the "after" date%b- the "before" date%d- the current date%%- escapes%
Partitioning
You can use partitioning to split files after a given number of messages or file size.
For example, a channel with 36 messages set to be partitioned every 10 messages will output 4 files.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -p 10A 45 MB channel set to be partitioned every 20 MB will output 3 files.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -p 20mbDownloading assets
If this option is set, the export will include additional files such as user avatars, attached files, images, etc.
Only files that are referenced by the export are downloaded, which means that, for example, user avatars will not be
downloaded when using the plain text (TXT) export format.
A folder containing the assets will be created along with the exported chat. They must be kept together.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --mediaReusing assets
Previously downloaded assets can be reused to skip redundant downloads as long as the chat is always exported to the
same folder. Using this option can speed up future exports. This option requires the --media option.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --media --reuse-mediaChanging the media directory
By default, the media directory is created alongside the exported chat. You can change this by using --media-dir and
providing a path that ends with a slash. All of the exported media will be stored in this directory.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --media --media-dir "C:\Discord Media"Changing the date format
You can customize how dates are formatted in the exported files by using --locale and inserting one of Discord's
locales. The default locale is en-US.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --locale "de-DE"Date ranges
Messages sent before a date
Use --before to export messages sent before the provided date. e.g., messages sent before September 18th, 2019:
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --before 2019-09-18Messages sent after a date
Use --after to export messages sent after the provided date. e.g., messages sent after September 17th, 2019 11:34 PM:
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --after "2019-09-17 23:34"Messages sent in a date range
Use --before and --after to export messages sent during the provided date range. e.g., messages sent between
September 17th, 2019 11:34 PM and September 18th:
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --after "2019-09-17 23:34" --before "2019-09-18"You can try different formats like 17-SEP-2019 11:34 PM or even refine your ranges down to
milliseconds 17-SEP-2019 23:45:30.6170!
Don't forget to quote (") the date if it has spaces!
More info about .NET date
formats here.
Filtering messages
Use --filter to filter what messages are included in the export.
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --filter "from:Tyrrrz has:image"Documentation on message filter syntax can be found here.
Export channels from a specific server
To export all channels in a specific server, use the exportguild command and provide the server ID through the -g|--guild option:
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814Including threads
By default, threads are not included in the export. You can change this behavior by using --include-threads and
specifying which threads should be included. It has possible values of none, active, or all, indicating which
threads should be included. To include both active and archived threads, use --include-threads all.
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814 --include-threads allIncluding voice channels
By default, voice channels are included in the export. You can change this behavior by using --include-vc and
specifying whether to include voice channels in the export. It has possible values of true or false, to exclude
voice channels, use --include-vc false.
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814 --include-vc falseExport all channels
To export all accessible channels, use the exportall command:
./DiscordChatExporter.Cli exportall -t "mfa.Ifrn"Excluding DMs
To exclude DMs, add the --include-dm false option.
./DiscordChatExporter.Cli exportall -t "mfa.Ifrn" --include-dm falseList channels in a server
To list the channels available in a specific server, use the channels command and provide the server ID through the -g|--guild option:
./DiscordChatExporter.Cli channels -t "mfa.Ifrn" -g 21814List direct message channels
To list all DM channels accessible to the current account, use the dm command:
./DiscordChatExporter.Cli dm -t "mfa.Ifrn"List servers
To list all servers accessible by the current account, use the guilds command:
./DiscordChatExporter.Cli guilds -t "mfa.Ifrn" > C:\path\to\output.txtFile: .docs/Using-the-GUI.md
Using the GUI
Video tutorial
Video by NoIntro Tutorials.
Guide
Step 1
After extracting the .zip, run DiscordChatExporter.exe (Windows), or DiscordChatExporter (Linux).
If you're using macOS, you'll need to manually grant permission for the app to run.
If you skip these steps, the "DiscordChatExporter is damaged and canβt be opened" error will be shown.
- Open Terminal.app. You can search for it in Spotlight (press β + Space and type "Terminal").
- Paste the following into the terminal window:bash
xattr -rd com.apple.quarantine - Hit Space once to add a space after the command
- Drag and drop DiscordChatExporter.app into the terminal window
- Press Return to run the command
- Open DiscordChatExporter.app normally
Apple requires apps to be notarized and signed in order to run on macOS without warnings, which in turn requires an Apple Developer membership ($99/year). This open-source project is distributed for free and without commercial intent.
Step 2
Please refer to the on-screen instructions to get your token, then paste your token in the upper text box and hit ENTER or click the arrow (β).
[!WARNING]
Never share your token!
A token gives full access to an account, treat it like a password.
Step 3
DCE will display your Direct Messages and a sidebar with your server list. Select the channel you would like to export, then click the button to continue.
Note:
You can export multiple channels at once by holdingCTRLorSHIFTwhile selecting.
You can also double-click a channel to export it without clicking the button.
Step 4
In this screen you can customize the following:
Output path - The folder where the exported chat(s) will be saved.
Export format - HTML (Dark), HTML (Light), TXT, CSV and JSON
Date range (after/before) (Optional) - If set, only messages sent in the provided date range will be exported. Only one value (either after or before) is required if you want to use this option.
Note:
Please note that the time defaults to 12:00 AM (midnight/00:00). This means that if you choose to export between Sep 17th and Sep 18th, messages from Sep 18th won't be exported.Partition limit (Optional) - Split output into partitions, each limited to this number of messages (e.g., 100) or file size (e.g., 10mb). For example, a channel with 36 messages set to be partitioned every 10 messages will output 4 files.
Message Filter (Optional) - Special notation for filtering the messages that get included in the export. See Message filters for more info.
Format markdown (Optional) - Disable markdown processing when exporting. You can use this to produce JSON or plain text exports without unwrapping mentions, custom emoji, and certain other special tokens.
Download assets (Optional) - If this option is set, the export will include additional files such as user avatars, attached files, images, etc. Only files that are referenced by the export are downloaded, which means that, for example, user avatars will not be downloaded when using the plain text (TXT) export format. A folder containing the assets will be created along with the exported chat. They must be kept together.
Reuse assets (Optional) - If this option is set, the export will reuse already downloaded assets to skip redundant requests. This option is only available when Download assets is enabled.
Assets directory path (Optional) - If this option is set, the export will use the specified directory to store assets from all exported channels in the same place.
Note:
You need to scroll down to see all available options.
Settings
Auto-update - Perform automatic updates on every launch.
Default: EnabledNote:
Keep this option enabled to receive the latest features and bug fixes!Dark mode - Use darker colors in the UI (User Interface).
Default: DisabledPersist token - Persist last used token between sessions.
Default: EnabledShow threads - Controls whether threads are shown in the channel list.
Default: noneLocale - Customize how dates are formatted in the exported files.
Date format - Customize how dates are formatted in the exported files in the settings menu ().
Parallel limit - The number of channels that will be exported at the same time.
Default: 1Note:
Try to keep this number low so that your account doesn't get flagged.Normalize to UTC - Convert all dates to UTC before exporting.
File: .github/dependabot.yml
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: monthly
labels:- enhancement
groups:
actions:
patterns:- "*"
- enhancement
- package-ecosystem: docker
directory: "/"
schedule:
interval: monthly
labels:- enhancement
groups:
docker:
patterns:- "*"
- enhancement
- package-ecosystem: nuget
directory: "/"
schedule:
interval: monthly
labels:- enhancement
groups:
nuget:
patterns:- "*"
- enhancement
File: .github/release.yml
changelog:
exclude:
authors:
- dependabot
- dependabot[bot]
categories:
- title: Enhancements
labels:
- enhancement
- title: Bugs
labels:
- bug
- title: Other
labels:
- "*"File: .github/ISSUE_TEMPLATE/bug-report.yml
name: π Bug report
labels: [bug]
body:
type: markdown
attributes:
value: |
- Avoid generic or vague titles such as "Something's not working" or "A couple of problems" β be as descriptive as possible.
- Keep your issue focused on one single problem. If you have multiple bug reports, please create a separate issue for each of them.
- Issues should represent complete and actionable work items. If you are unsure about something or have a question, please start a discussion instead.
- Remember that DiscordChatExporter is an open-source project funded by the community. If you find it useful, please consider donating to support its development.
___type: input
attributes:
label: Version
placeholder: v1.0.0
validations:
required: truetype: dropdown
attributes:
label: Flavor
multiple: true
options:
- GUI (Graphical User Interface)
- CLI (Command-Line Interface)
validations:
required: truetype: input
attributes:
label: Platform
placeholder: Docker / Windows 11
validations:
required: truetype: dropdown
attributes:
label: Export format
multiple: true
options:
- HTML
- TXT
- JSON
- CSVtype: textarea
attributes:
label: Steps to reproduce
Minimum steps required to reproduce the bug, including prerequisites, export settings, or other relevant items.
The information provided in this field must be readily actionable, meaning that anyone should be able to reproduce the bug by following these steps.
If the bug depends on external factors (such as a specific server, channel, or message), then this field must include the server invite and the corresponding link.
placeholder: |
Server invite: https://discord.gg/...
Channel or message link: https://discord.com/channels/.../...
Export settings:
- ...
Application settings:
- ...
Steps:
- Step 1
- Step 2
- Step 3
validations:
required: truetype: textarea
attributes:
label: Details
placeholder: |
- Expected behavior: ...
- Actual behavior: ...
validations:
required: truetype: checkboxes
attributes:
label: Checklist
options:
- label: I have looked through existing issues to make sure that this bug has not been reported before
required: true
- label: I have provided a descriptive title for this issue
required: true
- label: I have made sure that this bug is reproducible on the latest version of the application
required: true
- label: I have provided all the information needed to reproduce this bug as efficiently as possible
required: true
- label: I have sponsored this project
required: false
- label: I have not read any of the above and just checked all the boxes to submit the issue
required: falsetype: markdown
attributes:
value: |
If you are struggling to provide actionable reproduction steps, or if something else is preventing you from creating a complete bug report, please start a discussion instead.
File: .github/ISSUE_TEMPLATE/config.yml
blank_issues_enabled: false
contact_links:
- name: β Feature request
url: https://github.com/Tyrrrz/.github/blob/prime/docs/project-status.md
about: Sorry, but this project is in maintenance mode and currently doesn't accept new feature requests. - name: π Documentation
url: https://github.com/Tyrrrz/DiscordChatExporter/blob/prime/.docs
about: Find usage guides and frequently asked questions. - name: π¨ Discussions
url: https://github.com/Tyrrrz/DiscordChatExporter/discussions/new
about: Ask and answer questions. - name: π¬ Discord server
url: https://discord.gg/2SUWKFnHSm
about: Chat with the project community.
File: .github/workflows/docker.yml
name: docker
on:
workflow_dispatch:
push:
branches:
- prime
tags:
- "*"
pull_request:
branches:
- prime
jobs:
Outputs from this job aren't really used, but it's here to verify that the Dockerfile builds correctly
pack:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
actions: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Build image
run: >
docker buildx build .
--file DiscordChatExporter.Cli.dockerfile
--platform linux/amd64,linux/arm64
--build-arg VERSION=${{ github.ref_type == 'tag' && github.ref_name || format('999.9.9-ci-{0}', github.sha) }}
--output type=tar,dest=DiscordChatExporter.Cli.Docker.tar
- name: Upload image
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: DiscordChatExporter.Cli.Docker
path: DiscordChatExporter.Cli.Docker.tar
if-no-files-found: error deploy:
# Deploy to DockerHub only on tag push or prime branch push
if: ${{ github.ref_type == 'tag' || github.ref_type == 'branch' && github.ref_name == 'prime' }}
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Docker Buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Login to DockerHub
run: >
echo ${{ secrets.DOCKER_TOKEN }} |
docker login --username tyrrrz --password-stdin
- name: Build & push image
run: >
docker buildx build .
--file DiscordChatExporter.Cli.dockerfile
--platform linux/amd64,linux/arm64
--build-arg VERSION=${{ github.ref_type == 'tag' && github.ref_name || format('999.9.9-ci-{0}', github.sha) }}
--push
--tag tyrrrz/discordchatexporter:latest
${{ github.ref_type == 'tag' && '--tag tyrrrz/discordchatexporter:$GITHUB_REF_NAME' || '' }}
${{ github.ref_type == 'tag' && '--tag tyrrrz/discordchatexporter:stable' || '' }}File: .github/workflows/main.yml
name: main
on:
workflow_dispatch:
push:
branches:
- prime
tags:
- "*"
pull_request:
branches:
- prime
env:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
format:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
# Build the project separately to discern between build and format errors
- name: Build
run: >
dotnet build
-p:CSharpier_Bypass=true
--configuration Release
- name: Verify formatting
id: verify
run: >
dotnet build
-t:CSharpierFormat
--configuration Release
--no-restore
- name: Report issues
if: ${{ failure() && steps.verify.outcome == 'failure' }}
run: echo "::error title=Bad formatting::Formatting issues detected. Please build the solution locally to fix them." test:
# Tests need access to secrets, so we can't run them against PRs because of limited trust
if: ${{ github.event_name != 'pull_request' }}
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
- name: Run tests
env:
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
run: >
dotnet test
-p:CSharpier_Bypass=true
--configuration Release
--logger "GitHubActions;summary.includePassedTests=true;summary.includeSkippedTests=true"
--collect:"XPlat Code Coverage"
--
RunConfiguration.CollectSourceInformation=true
DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
- name: Upload coverage
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
token: ${{ secrets.CODECOV_TOKEN }} pack:
strategy:
matrix:
app:
- DiscordChatExporter.Cli
- DiscordChatExporter.Gui
rid:
- win-arm64
- win-x86
- win-x64
- linux-arm
- linux-arm64
- linux-musl-x64
- linux-x64
- osx-arm64
- osx-x64
include:
- app: DiscordChatExporter.Cli
asset: DiscordChatExporter.Cli
- app: DiscordChatExporter.Gui
# GUI assets aren't suffixed, unlike the CLI assets
asset: DiscordChatExporter
runs-on: ${{ startsWith(matrix.rid, 'win-') && 'windows-latest' || startsWith(matrix.rid, 'osx-') && 'macos-latest' || 'ubuntu-latest' }}
timeout-minutes: 10
permissions:
actions: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install .NET
uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
- name: Publish app
run: >
dotnet publish ${{ matrix.app }}
-p:Version=${{ github.ref_type == 'tag' && github.ref_name || format('999.9.9-ci-{0}', github.sha) }}
-p:CSharpier_Bypass=true
-p:EncryptionSalt=${{ secrets.ENCRYPTION_SALT || 'HimalayanPinkSalt' }}
--output ${{ matrix.app }}/bin/publish/
--configuration Release
--runtime ${{ matrix.rid }}
--self-contained
- name: Rename macOS bundle
if: ${{ startsWith(matrix.rid, 'osx-') && matrix.app == 'DiscordChatExporter.Gui' }}
run: >
mv ${{ matrix.app }}/bin/publish/DCE.app ${{ matrix.app }}/bin/publish/${{ matrix.asset }}.app
- name: Upload app binaries
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.asset }}.${{ matrix.rid }}
path: ${{ matrix.app }}/bin/publish/
if-no-files-found: error release:
if: ${{ github.ref_type == 'tag' }}
needs:
- format
- test
- pack
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: >
gh release create ${{ github.ref_name }}
--repo ${{ github.event.repository.full_name }}
--title ${{ github.ref_name }}
--generate-notes
--verify-tag deploy:
needs: release
strategy:
matrix:
app:
- DiscordChatExporter.Cli
- DiscordChatExporter.Gui
rid:
- win-arm64
- win-x86
- win-x64
- linux-arm
- linux-arm64
- linux-musl-x64
- linux-x64
- osx-arm64
- osx-x64
include:
- app: DiscordChatExporter.Cli
asset: DiscordChatExporter.Cli
- app: DiscordChatExporter.Gui
# GUI assets aren't suffixed, unlike the CLI assets
asset: DiscordChatExporter
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
actions: read
contents: write
steps:
- name: Download app binaries
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ matrix.asset }}.${{ matrix.rid }}
path: ${{ matrix.app }}/
- name: Set permissions
if: ${{ !startsWith(matrix.rid, 'win-') }}
run: |
[ -f ${{ matrix.app }}/${{ matrix.asset }} ] && chmod +x ${{ matrix.app }}/${{ matrix.asset }} || true
# macOS bundle
[ -f ${{ matrix.app }}/${{ matrix.asset }}.app/Contents/MacOS/${{ matrix.asset }} ] && chmod +x ${{ matrix.app }}/${{ matrix.asset }}.app/Contents/MacOS/${{ matrix.asset }} || true
- name: Create package
# Change into the artifacts directory to avoid including the directory itself in the zip archive
working-directory: ${{ matrix.app }}/
run: zip -r ../${{ matrix.asset }}.${{ matrix.rid }}.zip .
- name: Upload release asset
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: >
gh release upload ${{ github.ref_name }}
${{ matrix.asset }}.${{ matrix.rid }}.zip
--repo ${{ github.event.repository.full_name }} notify:
needs: deploy
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Notify Discord
uses: tyrrrz/action-http-request@110f1a0f0f7e91c3b2de349539249f4573c243fa # 1.1.5
with:
url: ${{ secrets.DISCORD_WEBHOOK }}
method: POST
headers: |
Content-Type: application/json; charset=UTF-8
body: |
{
"avatar_url": "https://raw.githubusercontent.com/${{ github.event.repository.full_name }}/${{ github.ref_name }}/favicon.png",
"content": "[**${{ github.event.repository.name }}**](<${{ github.event.repository.html_url }}>) v${{ github.ref_name }} has been released!"
}
retry-count: 5