Fetches your Crunchyroll watch history and exports it to AniList, MyAnimeList, and a local MAL-compatible XML file.
Exports include watch progress, series status (watching/completed), and real start/finish dates from your Crunchyroll history.
- Python 3.11+
- A Crunchyroll account (active browser session required for auth)
Pre-built releases are available on the Releases page:
- Windows:
CrunchyExporter.exe(standalone, no Python needed) - Linux:
CrunchyExporter(standalone executable)
Security note: I strongly recommend building from source instead of running pre-built binaries from the internet — including mine. You have no way to verify what's inside an
.exeyou didn't compile yourself. The source is short, readable, and straightforward to audit.
Windows / Linux:
git clone https://github.com/ruflas/CrunchyExporter.git
cd CrunchyExporter
pip install -r requirements.txt
python main.pyMac:
git clone https://github.com/ruflas/CrunchyExporter.git
cd CrunchyExporter
pip3 install -r requirements.txt
python3 main.pyIf
gitis not installed on Mac, your system will prompt you to install Xcode Command Line Tools automatically — just accept it.
See the build instructions at the bottom of this page.
CrunchyExporter authenticates using the etp_rt session cookie from your browser. No password is stored or required.
- Open crunchyroll.com and log in
- Press
F12to open DevTools - Go to the Application tab (Chrome/Edge) or Storage tab (Firefox)
- In the left panel expand Cookies → https://www.crunchyroll.com
- Find the row named
etp_rtand copy its Value
You can just copy there but you will need to search for the token again after restart the program.
Here when you copy and paste the token you just press Sync Now and the script will sync your crunchyroll history.

Recomended: Open the app, go to the Settings tab and paste the value in the etp_rt Cookie field. Click Save Settings.
Then go to the Sync tab and click Sync Now.
On success the status bar at the top will show something like:
● Cookie set ● 1513 eps · 28 series ● AniList ○ MAL ● XML ready
History is saved to data/history.json. Re-running sync only adds new episodes — it never duplicates.
Note: The
etp_rtcookie expires when your browser session ends. If sync starts failing with a 401 error, get a fresh cookie from DevTools.
Open the My Library tab to see all synced series with episode counts.
Open the Export tab. Each card shows whether a target is configured and ready.
Select the targets you want and click Export. If a token is missing, the authorization flow starts automatically.
Check Local XML and click Export.
Generates data/animelist.xml. Import it at:
- MyAnimeList: myanimelist.net/import.php
- AniList: anilist.co/settings/import — select MAL format
- Kitsu and most other tracking sites
Note: The XML does not include MAL IDs (Crunchyroll doesn't provide them). MAL and AniList resolve entries by title on import.
Syncs progress, status and real completion dates directly via the AniList API.
1. Create an API client
- Go to anilist.co/settings/developer and create a new client
- Set Redirect URL to exactly:
https://anilist.co/api/v2/oauth/pin - Copy the Client ID
2. Enter it in Settings
Open the Settings tab, paste the Client ID under AniList, then click Get Token.
Your browser will open — authorize the app and copy the access_token from the redirect URL back into the dialog.
Click Save Settings. The AniList card in the Export tab will turn green.
From now on the export runs without any browser interaction.
Syncs progress, status, start date and finish date directly via the MAL API.
1. Create an API client
- Go to myanimelist.net/apiconfig and click Create ID
- App Redirect URL:
http://localhost - Purpose of Use:
hobbyist - Choose an App Type:
other(recommended, simpler) — public client, no secret needed. Just copy the Client ID.web— MAL also requires a Client Secret for this type. Copy both the Client ID and the Client Secret.
2. Enter it in Settings
Open Settings, paste the Client ID under MyAnimeList.
- If you created a
webapp, check "My app is App Type web" and paste the Client Secret too. - If you created an
otherapp, leave the checkbox unchecked.
Then click Authorize MAL — your browser will open, authorize the app. MAL redirects to http://localhost/?code=XXXX — the page won't load, that's expected. Copy the code= value (not the access token) from the address bar and paste it into the dialog.
Click Save Settings. The MAL card in the Export tab will turn green.
Note: mixing them up causes an authentication error — a
webapp without its Client Secret (or vice versa) will fail the token exchange.
From now on the export runs without any browser interaction.
Open the Schedule tab, choose a time and export targets, then click Create scheduled task.
On Windows this creates a Windows Task Scheduler entry. On Linux/Mac it adds an entry to your crontab.
The task runs python src/main.py sync silently in the background — no window required.
Requires etp_rt saved in config.yaml (set it via the Settings tab).
Enable System tray in Settings → Interface. When active, closing the window keeps the app running in the notification area. Right-click the tray icon to sync immediately or exit.
All settings can be edited directly in the Settings tab. The underlying config.yaml looks like this:
locale: "en-US" # Language for series titles from Crunchyroll
ui:
language: "en" # GUI language: en | es | any file in locales/
tray_enabled: false # true to minimize to system tray on close
storage:
path: "data/history.json"
crunchyroll:
etp_rt: "" # Session cookie from browser (see Step 1)
client_id: "" # Leave blank to use built-in default
client_secret: "" # Leave blank (public client, no secret needed)
exporters:
mal_xml:
path: "data/animelist.xml"
anilist:
client_id: ""
access_token: ""
mal:
client_id: ""
access_token: ""Sync fails with Login failed (400): unsupported_grant_type
CR no longer supports email/password login via the API. Use the etp_rt cookie method described in Step 1.
Sync fails with Login failed (400): missing_required_field
The etp_rt value is missing or empty. Make sure you copied the full cookie value from DevTools.
Sync fails with 401 after working before
The etp_rt cookie expired. Log into Crunchyroll again and copy a fresh value from DevTools → Settings.
invalid_client error on AniList
The Client ID in Settings is wrong, or the redirect URL in your AniList app is not exactly https://anilist.co/api/v2/oauth/pin.
MAL authorization page shows 400 Bad Request
Your MAL app type is set to other. Change it to web in myanimelist.net/apiconfig — only web supports the authorization code flow.
Some series not found on AniList or MAL Crunchyroll sometimes uses different titles. The exporter automatically retries with a normalized title as fallback. If a series still fails, add it manually on the tracking site.
- Copy
locales/en.json→locales/<lang_code>.json - Translate the values (do not change the keys)
- Set
ui.language: "<lang_code>"in Settings and restart - Submit a pull request — contributions welcome
Current languages: English (en), Spanish (es)
CrunchyExporter/
├── src/ # Bundled library (from CrunchyExporter-cli)
│ ├── crunchyroll/
│ │ ├── auth.py # CR authentication (etp_rt_cookie grant)
│ │ ├── history.py # Watch history fetcher (paginated)
│ │ └── models.py # Data classes
│ ├── exporters/
│ │ ├── anilist.py # AniList GraphQL exporter
│ │ ├── mal.py # MyAnimeList REST exporter
│ │ └── mal_xml.py # Local MAL XML exporter
│ ├── storage/
│ │ └── history_store.py # JSON persistence
│ └── main.py # CLI entry point (used by Schedule/Tray)
├── gui/
│ ├── app.py # Main window
│ ├── i18n.py # Locale loader
│ ├── tray.py # System tray
│ ├── statusbar.py # Status indicator bar
│ └── tabs/ # One module per tab
├── locales/
│ ├── en.json
│ └── es.json
├── data/ # Generated — gitignored
├── main.py # GUI entry point
└── config.example.yaml
Contributions are welcome.
git clone https://github.com/ruflas/CrunchyExporter.git
cd CrunchyExporter
pip install -r requirements.txt
cp config.example.yaml config.yaml # Linux/Mac
Copy-Item config.example.yaml config.yaml # Windows
python main.py- New languages — copy
locales/en.json, translate, submit PR - New exporters — Kitsu, Anime-Planet, Shikimori (add to
src/exporters/) - Better title matching — fuzzy search or manual override mappings
- Bug reports — if a series fails to match or exports incorrectly, open an issue with the series title and the error
- Modifying
src/directly — it is a copy of CrunchyExporter-cli; fixes should go there first - Breaking the existing Settings/Export flow without discussion
- Adding dependencies that aren't strictly necessary
Building your own binary is the safest way to run the app — you know exactly what's in it.
Windows (produces CrunchyExporter.exe):
pip install pyinstaller
pyinstaller --onefile --windowed --icon=crunchyexporterlogo.ico --name CrunchyExporter main.pyLinux (produces CrunchyExporter):
pip install pyinstaller
pyinstaller --onefile --windowed --name CrunchyExporter main.pyMac (produces CrunchyExporter.app):
pip3 install pyinstaller
pyinstaller --onefile --windowed --name CrunchyExporter main.pyThe output lands in the dist/ folder. No Python installation needed on the target machine.
- CrunchyExporter-cli — CLI version / underlying library





