DiscordChatExporter Documentation

Saves Discord chat logs to a file

12,286 stars C# C# 1 file Β· ~21,361 tokens #archival#archiver#chat#discord#export#expoter#log
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy DiscordChatExporter on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name discordchatexporter --restart always tyrrrz/discordchatexporter:latest

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)
  • 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)

[!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.

  1. Join the test server
  2. Locate your Discord authentication token
  3. Add your token to user secrets: dotnet user-secrets set DISCORD_TOKEN <token>
  4. 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

Guides

Video tutorial

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.

console
$ docker pull tyrrrz/discordchatexporter:stable

Note 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 the prime branch. 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:

console
$ docker run --rm tyrrrz/discordchatexporter:stable

To export a channel:

console
$ docker run --rm -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELID

If you want colored output and real-time progress reporting, pass the -it (interactive + pseudo-terminal) option:

console
$ docker run --rm -it -v /path/on/machine:/out tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELID

The -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 :z option after /out, e.g.:

console
$ docker run --rm -v /path/on/machine:/out:z tyrrrz/discordchatexporter:stable export -t TOKEN -c CHANNELID

For 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:/out in Bash
  • -v $pwd.Path:/out in 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:

console
$ 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 CHANNELID

Environment 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 the DiscordChatExporter.*.zip file.
  • 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 the DiscordChatExporter.Cli.*.zip file.

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
console
from:Tyrrrz
  • Filter by user (with discriminator)
console
from:Tyrrrz#1234
  • Filter by message content (allowed values: link, embed, file, video, image, sound)
console
has:image
  • Filter by mentioned user (same rules apply as with from: filter)
console
mentions:Tyrrrz#1234
  • Filter by contained text (has word "hello" and word "world" somewhere in the message text):
console
hello world
  • Filter by contained text (has the string "hello world" somewhere in the message text):
console
"hello world"
  • Combine multiple filters ('and'):
console
from:Tyrrrz has:image
  • Same thing but with an explicit operator:
console
from:Tyrrrz & has:image
  • Combine multiple filters ('or'):
console
from:Tyrrrz | from:"96-LB"
  • Combine multiple filters using groups:
console
(from:Tyrrrz | from:"96-LB") has:image
  • Negate a filter:
console
-from:Tyrrrz | -has:image
  • Negate a grouped filter:
console
-(from:Tyrrrz has:image)
  • Escape special characters (- is escaped below, so it's not parsed as negation operator):
console
from:96\-LB

CLI Caveats

In most cases, you will need to enclose your filter in quotes (") to escape characters that may have special meaning in your shell:

console
$ ./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:

console
$ ./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 (-):

console
$ ./DiscordChatExporter.Cli export [...] --filter ~from:Tyrrrz

File: .docs/Scheduling-Linux.md

Scheduling exports with Cron

Creating the script

  1. 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).

  1. Paste the following into the text file:
bash
#!/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
  1. Replace:
  • tokenhere with your Token.
  • channelhere with a Channel ID.
  • dceFOLDERpathhere with DCE's directory path (e.g., /path/to/folder, NOT /path/to/folder/DiscordChatExporter.dll).
  • filenamehere with the exported channel's filename, without spaces.
  • dirhere with the export directory (e.g., /home/user/Documents/Discord\ Exports).
  • formathere with 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.

  1. Make your script executable with chmod +x /path/to/DiscordChatExporter/cron.sh

  2. Let'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 with sudo 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.

  3. 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.log with /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

  1. Open TextEdit.app and create a new file

  2. Convert the file to a plain text one in 'Format > Make Plain Text' (β‡§βŒ˜T)

  3. Paste the following into the text editor:

bash
#!/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
  1. Replace:
  • tokenhere with your Token
  • channelhere with a Channel ID
  • dceFOLDERpathhere with DCE's directory's path (e.g., /Users/user/Desktop/DiscordChatExporterFolder, NOT /Users/user/Desktop/DiscordChatExporterFolder/DiscordChatExporter.DLL)
  • filenamehere with the exported channel's filename, without spaces
  • dirhere with the directory you want the files to be saved at (e.g., /Users/user/Documents/Discord\ Exports)
  • formathere with 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 βœ“
  1. Save the file as filename.sh, not .txt
  2. Open Terminal.app, type chmod +x, press the SPACE key, then drag & drop the filename.sh into 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
<?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 Label string is the name of the export job, it must be something unique. Replace the local.discordchatexporter between the <string> with another name if you'd like to run more than one script.
  • The Program string is the path to the script. Replace /path/to/filename.sh between the <string> with the path of the previously created script.
  • Replace the REPLACEME with 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

xml
<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:

xml
<key>StartInterval</key>
<integer>3600</integer>

Export at a specific time and date

xml
<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:

xml
<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):

xml
<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:

xml
<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

  1. Copy your filename.plist file to one of these folders according to how you want it to run:
  • ~/Library/LaunchAgents runs as the current logged-in user.

  • /Library/LaunchDaemons runs 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.

  1. To load the job into launchctl, in Terminal, type launchctl load, press SPACE, drag and drop the .plist into the Terminal window, then hit RETURN. It won't output anything if it was successfully loaded.

Extra launchctl commands

Unloading a job

text
launchctl unload /path/to/Library/LaunchAgents/local.discordchatexporter.plist

List every loaded job

text
launchctl list

Check if a specific job is enabled
You can also see error codes (2nd number) by running this command.

text
launchctl list | grep local.discordchatexporter

Further 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

  1. Open a text editor such as Notepad and paste:
console
# 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
  1. Replace:
  • tokenhere with your Token
  • channelhere with a Channel ID
  • exefolderhere with the .exe directory's path (e.g., C:\Users\User\Desktop\DiscordChatExporter)
  • filenamehere with a filename without spaces
  • dirhere with the export directory (e.g., C:\Users\User\Documents\Exports)
  • formathere with one of the available export formats

Make sure not to delete the quotes (")

  1. Save the file as filename.ps1, not as .txt

Note: You can also modify the script to use other options, such as include-threads or switch to a different command, e. g. exportguild.

Export at Startup

  1. Press Windows + R, type shell:startup and press ENTER
  2. Paste filename.ps1 or a shortcut into this folder

Scheduling with Task Scheduler

Please note that your computer must be turned on for the export to happen.

  1. Press Windows + R, type taskschd.msc and press ENTER

  2. Select Task Scheduler Library, create a Basic Task, and follow the instructions on-screen

  3. At 'Start a Program', write powershell -file -ExecutionPolicy ByPass -WindowStyle Hidden "C:\path\to\filename.ps1" in the Program/script text box

  4. Click 'Yes'

  5. 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

  1. Press Ctrl+Shift+I (βŒ₯+⌘+I on macOS). Chrome's DevTools tools will display.

  2. Click the Console tab. The console will open.

  3. Type

    js
    let 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

  1. Press Ctrl+Shift+I (βŒ₯+⌘+I on macOS). Chrome's DevTools tools will display.

  2. Click the Network tab. The network panel will open

  3. Press F5. The page will reload, and the network log (the lower half of the network panel) will display several entries.

  4. Click the text box labelled Filter and type messages. The entries will filter down to a single request named messages. If the request doesn't appear, switch to any other Discord channel to trigger it.

  5. Click the entry named messages. A panel will open to the right and display details about the entry. Click the Headers tab if it isn't already active.

  6. Scroll through the contents of the Headers tab until you find an entry beginning with authorization:.

  7. Right-click the entry and click copy value.

Using the storage inspector

  1. Press Ctrl+Shift+I (βŒ₯+⌘+I on macOS). Chrome's DevTools will display.

  2. Press Ctrl+Shift+M (⌘+Shift+M). Chrome will enter Device Mode, and the webpage will display as if on a mobile device.

  3. If necessary, click the Β» at the right end of the tab bar, and click Application. The application panel will display.

  4. In the menu to the right, under Storage, expand Local Storage if necessary, then click https://discord.com. The pane to the right will display a list of key-value pairs.

  5. In the text box marked Filter, type token. The entries will filter down to those containing the string token.

  6. Click the token entry. (Note: if the token doesn't display, try refreshing by pressing F5 or ⌘+R on macOS)

  7. 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

  1. 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.

  2. Click the Console tab. The console will open.

  3. Type

    js
    let 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

  1. 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.

  2. Press F5. The page will reload, and the network request list will populate with entries.

  3. Type messages into the filter. The network request list will filter out any entries not containing the string messages. If the request doesn't appear, switch to any other Discord channel to trigger it.

  4. Click messages. The network request details pane will display. The headers tab should be active by default. If it isn’t, click it.

  5. Type authorization into the text box labelled Filter Headers.

  6. Scroll down until you see an entry labeled authorization under Request Headers.

  7. Right-click the entry labeled authorization and select copy value.

Using the storage inspector

  1. Press Shift+F9. Firefox’s web developer tools will display at the bottom of the window, and the storage panel will be selected.

  2. 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.)

  3. 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.com will display beneath it.

  4. In the storage tree, click https://discord.com. The table widget to the right of the storage tree will display several key-value pairs.

  5. In the text box labelled Filter items at the top of the table widget, enter token. The table will now only display entries containing the string token.

  6. Click the entry token. The sidebar will display. (Note: If the token doesn’t display, try refreshing by pressing F5.)

  7. Right-click the single entry in the sidebar and select copy.

Through the desktop app / enabling web developer tools

By editing the settings file

  1. If Discord is running, exit the application by right-clicking the icon in your taskbar tray and clicking Quit Discord.

  2. 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.json
    macOS ~/Library/Application Support/discord/settings.json ~/Library/Application Support/discordcanary/settings.json ~/Library/Application Support/discordptb/settings.json
    Linux ~/.config/discord/settings.json ~/.config/discordcanary/settings.json ~/.config/discordptb/settings.json

    If 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.json
    macOS ~/Library/Application Support/BetterDiscord/data/stable/settings.json ~/Library/Application Support/BetterDiscord/data/canary/settings.json ~/Library/Application Support/BetterDiscord/data/ptb/settings.json
    Linux ~/.config/BetterDiscord/data/stable/settings.json ~/.config/BetterDiscord/data/canary/settings.json ~/.config/BetterDiscord/data/ptb/settings.json
  3. Insert 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:

json
{
  "DANGEROUS_ENABLE_DEVTOOLS_ONLY_ENABLE_IF_YOU_KNOW_WHAT_YOURE_DOING": true,
  "BACKGROUND_COLOR": "#202225",
  "IS_MAXIMIZED": true
}
  1. Launch Discord.

  2. To find your user token, continue here.

Via settings menu (BetterDiscord only)

  1. Click the User Settings button (the gear icon to the right of your username). Discord’s settings page will open.

  2. In the sidebar to the left, click Settings under the BetterDiscord group. BetterDiscord’s settings page will display.

  3. In the main panel to the right, expand the Developer Settings group if necessary, and toggle DevTools to enabled.

  4. Press Esc. The settings page will close.

  5. 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:

  1. Go to Discord developer portal
  2. Click on New Application in the top right corner
  3. 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.

  1. Go to Discord developer portal
  2. Navigate to General Information on the left
  3. Copy the Application ID
  4. Open the following URL in your browser, replacing YOUR_APP_ID with the copied Client ID:
text
https://discord.com/oauth2/authorize?scope=bot&permissions=66560&client_id=YOUR_APP_ID

Step 3 - Ensure message content intent is enabled

If this option is not enabled, the exported files will be empty.

  1. Go to Discord developer portal
  2. Open your Application's settings
  3. Navigate to the Bot section on the left
  4. Scroll down to the Privileged Gateway Intents section
  5. 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:

  1. Go to Discord developer portal
  2. Open your Application's settings
  3. Navigate to the Bot section on the left
  4. Under Token click Reset Token
  5. 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

  1. Open Discord Settings
  2. Go to the Advanced section
  3. Enable Developer Mode
  4. 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.

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

yml
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Authentication token is invalid.

↳ Make sure the provided token is correct.

yml
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Requested resource does not exist.

↳ Check your channel ID, it might be invalid. Read this if you need help.

yml
DiscordChatExporter.Domain.Exceptions.DiscordChatExporterException: Access is forbidden.

↳ This means you don't have access to the channel.

yml
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.

console
./DiscordChatExporter.Cli

Note:
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:

console
./DiscordChatExporter.Cli command --help

For example, to figure out how to use the export command, run:

console
./DiscordChatExporter.Cli export --help

Export a specific channel

You can quickly export with DCE's default settings by using just -t token and -c channelid.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555

Changing the format

You can change the export format to HtmlDark, HtmlLight, PlainText Json or Csv with -f format. The default
format is HtmlDark.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -f Json

Changing the output filename

You can change the filename by using -o name.ext. e.g., for the HTML format:

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -o myserver.html

Changing 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 (").

console
./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 (").

console
./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.

console
./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.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -p 10

A 45 MB channel set to be partitioned every 20 MB will output 3 files.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 -p 20mb

Downloading 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.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --media

Reusing 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.

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --media --reuse-media

Changing 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.

console
./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.

console
./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:

console
./DiscordChatExporter.Cli export -t "mfa.Ifrn" -c 53555 --before 2019-09-18

Messages 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:

console
./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:

console
./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.

console
./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:

console
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814

Including 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.

console
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814 --include-threads all

Including 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.

console
./DiscordChatExporter.Cli exportguild -t "mfa.Ifrn" -g 21814 --include-vc false

Export all channels

To export all accessible channels, use the exportall command:

console
./DiscordChatExporter.Cli exportall -t "mfa.Ifrn"

Excluding DMs

To exclude DMs, add the --include-dm false option.

console
./DiscordChatExporter.Cli exportall -t "mfa.Ifrn" --include-dm false

List 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:

console
./DiscordChatExporter.Cli channels -t "mfa.Ifrn" -g 21814

List direct message channels

To list all DM channels accessible to the current account, use the dm command:

console
./DiscordChatExporter.Cli dm -t "mfa.Ifrn"

List servers

To list all servers accessible by the current account, use the guilds command:

console
./DiscordChatExporter.Cli guilds -t "mfa.Ifrn" > C:\path\to\output.txt

File: .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.

  1. Open Terminal.app. You can search for it in Spotlight (press ⌘ + Space and type "Terminal").
  2. Paste the following into the terminal window:
    bash
    xattr -rd com.apple.quarantine
  3. Hit Space once to add a space after the command
  4. Drag and drop DiscordChatExporter.app into the terminal window
  5. Press Return to run the command
  6. 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 holding CTRL or SHIFT while 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: Enabled

    Note:
    Keep this option enabled to receive the latest features and bug fixes!

  • Dark mode - Use darker colors in the UI (User Interface).
    Default: Disabled

  • Persist token - Persist last used token between sessions.
    Default: Enabled

  • Show threads - Controls whether threads are shown in the channel list.
    Default: none

  • Locale - 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: 1

    Note:
    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:
      • "*"
  • package-ecosystem: docker
    directory: "/"
    schedule:
    interval: monthly
    labels:
    • enhancement
      groups:
      docker:
      patterns:
      • "*"
  • package-ecosystem: nuget
    directory: "/"
    schedule:
    interval: monthly
    labels:
    • enhancement
      groups:
      nuget:
      patterns:
      • "*"

File: .github/release.yml

changelog:
exclude:
authors:
- dependabot
- dependabot[bot]

categories:
- title: Enhancements
labels:
- enhancement

text
- 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: true

  • type: dropdown
    attributes:
    label: Flavor
    multiple: true
    options:
    - GUI (Graphical User Interface)
    - CLI (Command-Line Interface)

    validations:
    required: true

  • type: input
    attributes:
    label: Platform
    placeholder: Docker / Windows 11
    validations:
    required: true

  • type: dropdown
    attributes:
    label: Export format
    multiple: true
    options:
    - HTML
    - TXT
    - JSON
    - CSV

  • type: 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: true

  • type: textarea
    attributes:
    label: Details
    placeholder: |
    - Expected behavior: ...
    - Actual behavior: ...

    validations:
    required: true

  • type: 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: false

  • type: 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:


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

text
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' }}

text
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

text
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' }}

text
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

text
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' }}

text
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

text
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

text
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