MangaDex Sync — Export & Import your library to/from MAL and AniList

Member
Joined
Sep 2, 2025
Messages
8
MangaDex Sync — Export & Import your library to/from MAL and AniList

Hey everyone! I made a small tool that lets you sync your MangaDex library with other platforms and wanted to share it here.

What it does:
  • Export your full MangaDex library (reading, completed, on-hold, dropped, plan to read, re-reading) to MAL and AniList XML files — ready to import directly on their sites
  • Import your library back into MangaDex from a JSON backup, MAL XML, or AniList XML file
  • Carries over your scores and statuses
  • Fast mode (minutes) or Deep mode (includes last read chapter)
  • Resumes from where it left off if interrupted

How to use:
pip install mangadex-sync
mangadex-sync

Opens as a desktop app. Also works in a browser at http://localhost:7337, including on Android via Termux.

PyPI: https://pypi.org/project/mangadex-sync/
GitHub: https://github.com/spider2742/mangadex-sync

---

This tool uses the official MangaDex API with a personal client and follows the usage guidelines. It's a free, open source, ad-free personal project — I just hope it's useful to someone. If there are any concerns from the MangaDex team I'm happy to address them!
 
Contributor
Joined
Jan 19, 2018
Messages
760
Hey @Spider2742 , I took a look at your project and noticed a slight bug with how you collect ratings.
If you get to a batch of titles that have not been rated you get an empty "ratings" array. Calling "items()" on that causes an exception which stops the process of gather ratings for all remaining titles.

Example problem response:
JSON:
{'result': 'ok', 'ratings': []}

Problem code
Python:
def ratings(self, ids):
    out, bs = {}, 100
    for batch in [ids[i:i+bs] for i in range(0,len(ids),bs)]:
        d = self.get(f"{API_BASE}/rating", {"manga[]":batch})
        if d:
            for mid, rd in d.get("ratings",{}).items():
                out[mid] = rd.get("rating",0)
        time.sleep(0.25)
    return out

As for some feedback its nice that you show titles without a MAL id in the UI but i think it would also be useful to have that list exported even if its just in the JSON format
 
Last edited:
Contributor
Joined
Jan 19, 2018
Messages
760
Back again with another issue. When gathering details about titles "mature" titles will get excluded by the MD API unless you include the appropriate content rating parameter in the url

Updated code with content rating param
Python:
def manga_details(self, ids, cb=None):
    out, bs = {}, 100
    for i, batch in enumerate([ids[j:j+bs] for j in range(0,len(ids),bs)]):
        d = self.get(f"{API_BASE}/manga", {"ids[]":batch,"limit":100,"includes[]":["author"],"contentRating[]":["safe","suggestive","erotica","pornographic"]})
        if d:
            for m in d.get("data",[]): out[m["id"]] = m
        if cb: cb(min((i+1)*bs,len(ids)), len(ids))
        time.sleep(0.25)
    return out
 
Member
Joined
Sep 2, 2025
Messages
8
Thanks for checking out my projects and pointing out the bugs I have the json export idea already in list and thanks for telling me about the bugs I will fix them when I update it
 
Joined
Aug 7, 2026
Messages
1
I'm having an issue with importing MAL to MangaDex. Every single item returns Could not find MangaDex ID for 'xyz' - skipped
I've let it run for a while ( a couple hundred manga) and it never finds a single one. I tried the standalone and using the browser to the same outcome. The xml file I'm using came straight from MAL's export function. I'm on Linux, CachyOS specifically.
 
Member
Joined
Sep 2, 2025
Messages
8
I'm having an issue with importing MAL to MangaDex. Every single item returns Could not find MangaDex ID for 'xyz' - skipped
I've let it run for a while ( a couple hundred manga) and it never finds a single one. I tried the standalone and using the browser to the same outcome. The xml file I'm using came straight from MAL's export function. I'm on Linux, CachyOS specifically.
Oh is that so, I will go ahead and check it out it was working before but In lattest version I only tested mdex json backup import I will check it out later
 
Contributor
Joined
Jan 19, 2018
Messages
760
Hello, back with a new "issue".
When doing an export with the "deep" option set to get last read chapter/volume if a chapter has been removed because of a take down request the tool doesn't pick it up

I believe adding "includeUnavailable" to the request made in "chapter_details" should fix this
Python:
    def chapter_details(self, ids, cb=None):
        out, bs = {}, 100
        for i, batch in enumerate([ids[j:j+bs] for j in range(0,len(ids),bs)]):
            d = self.get(f"{API_BASE}/chapter", {"ids[]":batch,"limit":100,"includeUnavailable":1,
                "contentRating[]":["safe","suggestive","erotica","pornographic"]})
            if d:
                for ch in d.get("data",[]): out[ch["id"]] = ch
            if cb: cb(min((i+1)*bs,len(ids)), len(ids))
            time.sleep(self._rate_delay)
        return out
 
Member
Joined
Sep 2, 2025
Messages
8
Hello, back with a new "issue".
When doing an export with the "deep" option set to get last read chapter/volume if a chapter has been removed because of a take down request the tool doesn't pick it up

I believe adding "includeUnavailable" to the request made in "chapter_details" should fix this
Python:
    def chapter_details(self, ids, cb=None):
        out, bs = {}, 100
        for i, batch in enumerate([ids[j:j+bs] for j in range(0,len(ids),bs)]):
            d = self.get(f"{API_BASE}/chapter", {"ids[]":batch,"limit":100,"includeUnavailable":1,
                "contentRating[]":["safe","suggestive","erotica","pornographic"]})
            if d:
                for ch in d.get("data",[]): out[ch["id"]] = ch
            if cb: cb(min((i+1)*bs,len(ids)), len(ids))
            time.sleep(self._rate_delay)
        return out
thanks for sharing this information, I will look into it
 
Member
Joined
Sep 2, 2025
Messages
8
Hello, back with a new "issue".
When doing an export with the "deep" option set to get last read chapter/volume if a chapter has been removed because of a take down request the tool doesn't pick it up

I believe adding "includeUnavailable" to the request made in "chapter_details" should fix this
Python:
    def chapter_details(self, ids, cb=None):
        out, bs = {}, 100
        for i, batch in enumerate([ids[j:j+bs] for j in range(0,len(ids),bs)]):
            d = self.get(f"{API_BASE}/chapter", {"ids[]":batch,"limit":100,"includeUnavailable":1,
                "contentRating[]":["safe","suggestive","erotica","pornographic"]})
            if d:
                for ch in d.get("data",[]): out[ch["id"]] = ch
            if cb: cb(min((i+1)*bs,len(ids)), len(ids))
            time.sleep(self._rate_delay)
        return out
Hey @RogueKitsune, quick update on this one! 👋

Looked into it and you were spot on: chapter_details wasn't passing includeUnavailable, so any chapter hit by a takedown just silently vanished, and deep mode would fall back to an older chapter (or 0).

It's fixed in v2.2.0, which is out now:

  • Deep exports now pick up unavailable chapters too, so takedowns won't mess with your last-read chapter/volume anymore.
  • If a read chapter still can't be found at all (fully deleted, not just unavailable), the log now shows a warning with the count instead of skipping it quietly.
  • Bonus fix while I was in there: rate-limit handling now reads MangaDex's actual retry header, so throttled runs wait the right amount instead of a flat 5s.

To update:
pip install -U mangadex-sync
or grab the latest standalone script from GitHub.

I also gave the UI a proper overhaul in this release, with a few new goodies:
  • a "verify credentials" button so you know your login works before a run
  • live per-status counts pulled from your library
  • much better run history
  • a one-click MAL search for anything that gets skipped

Give it a spin and let me know if anything breaks. Thanks again for the report and the fix suggestion, made this one super easy
 
Member
Joined
Sep 2, 2025
Messages
8
I'm having an issue with importing MAL to MangaDex. Every single item returns Could not find MangaDex ID for 'xyz' - skipped
I've let it run for a while ( a couple hundred manga) and it never finds a single one. I tried the standalone and using the browser to the same outcome. The xml file I'm using came straight from MAL's export function. I'm on Linux, CachyOS specifically.
Hey @FeralFantom, sorry for the delay and for missing this earlier—I got caught up with other stuff and completely forgot until I was looking back through the chat just now!
Found the issue: MangaDex's API stopped accepting the MAL-ID filter the importer relied on, so every lookup failed silently (which is why it wasn't fixed in v2.2.0).
It's properly sorted in v2.2.1: the importer now searches by title and only accepts a match when the MangaDex entry's MAL link lines up exactly, preventing any false matches.
You can update via:

pip install -U mangadex-sync

or grab the latest standalone release from GitHub.
Titles without an existing MAL link on MangaDex will still be skipped and listed, but everything else should import smoothly now. Let me know how it goes!
 
Last edited:

Users who are viewing this thread

Top