Daniel Parker

X3 and Koreader syncing

12 Aug 2026

    I had a very confused evening debugging my new XTEINK X3 when trying to use Koreader Sync. It appeared to complete the sync process successfully, but no progress ever got synced.

    By the way the XTEINK X3 is wonderful little device. It’s so small and does what it does (just reading) really well.

    When I got it I naturally immediately installed Crosspoint to get some extra features. One of those new features is the ability to connect to a Koreader Sync Server so that reading progress can be synced to KOReader (in my case, a jailbroken Kindle).

    But how does this actually work? Well the answer is really simple. There’s basically two non user admin endpoints.

    PUT /syncs/progress (update progress)

    GET /syncs/progress/:hash (get progress)

    Each book is identified by either a hash of the file’s name or a hash of the binary content of the ebook.

    GET /syncs/progress/:hash returns something like:

    {
      "device_id": "device-name",
      "progress": "/body/DocFragment[1]/body/h1/text().0",
      "document": "<book hash>",
      "percentage": 0.23,
      "device": "device",
      "timestamp": 123456789
    }
    

    The idea is you do the GET, compare your progress, if the server is ahead of you, you pull the server and if you are ahead of the server, push your progress.

    My test was to sync some reading I’d done on the X3 back to the book in Koreader. I activated the sync function in the menu and it appeared to work correctly, at least the UI reported success.

    The issue was that in Koreader, it also said it successfully synced, but it move forwards to the new page!

    It turns out that Koreader auto sync just pushes without looking first, which kind of defeats the point. So every time I turned my Kindle back on, to test if the sync worked, it silently pushed its own progress. It took a while to realise this was what was going on.

    I turned off auto sync and this seemed to correct it.

    Also, Crosspoint does a weird thing where despite setting ‘filename’ matching for the Koreader sync, it also checks the binary hash as well. I happened to have a record on the server for both kinds of syncing, because I was testing which method to use. This took a long time to figure out, but once I’d found it, I now know to stay on filename matching and not change.

    So, while it’s not 100% easy and simple syncing, it does work pretty nicely. I tend to know which device I last used when reading something, so knowing to push or pull on Koreader isn’t a complete pain.