Kobo highlights into Readwise — no desktop app, just the browserKobo-aantekeningen naar Readwise — zonder desktop-app, gewoon in de browser
Visit the site ↗Bekijk de site ↗ view on githubbekijk op github
I borrow my books from the online library and read them on my Kobo. While reading I highlight a lot — lines that stick, things I want to keep. I want those annotations in Readwise, where the rest of my highlights already live. Except that doesn’t happen by itself.
Books from the Kobo store, Kobo Plus, and library loans already sync through Readwise’s
own integration. But sideloaded books — EPUBs you put on the device yourself via
Calibre, email, or USB, or a loan from the
online library that you transfer to your Kobo
with Adobe Digital Editions — are a different story. Their highlights live only in the local
KoboReader.sqlite on the e-reader and never reach the Kobo cloud, so Readwise can’t get
at them.
The existing fix is a desktop app
For exactly this problem there’s October: a tidy, open-source desktop app that detects your Kobo the moment you plug it in, reads the database, and uploads the highlights to Readwise. It works well. But it’s still something you install, per operating system, and keep around.
I figured this can just run in the browser now. Chrome and Edge can read a file on your disk without uploading it via the File System Access API, and sql.js runs SQLite as WebAssembly right inside the tab. Together that’s everything you need: no install, one URL.
How it works
The flow is short:
pick the file → read SQLite in the browser → forward highlights to Readwise.
You choose your KoboReader.sqlite, sql.js reads it locally (the file never leaves your
computer), and the app shows, per book, which highlights it will send. A thin proxy takes
that batch and forwards it to the Readwise API — that’s all the server does.
The trust model: the token is forgotten
There is one thing the server does touch: your Readwise token, because it has to go into
the Authorization header to Readwise. So the whole design is built around it — the proxy
forwards your token and then immediately forgets it. No request-body logging, no
persistence, no database. The token lives only in memory for the duration of a single
request. That’s the entire point of the app, and it’s stated as an explicit promise at the
top of app.py.
For the same reason sql.js is self-hosted rather than loaded from a CDN: on the page that briefly holds your token, you don’t want any third-party script running.
Finding the file: showing hidden folders
The KoboReader.sqlite sits in a hidden folder called .kobo, at the root of your
e-reader when you mount it over USB. Hidden folders — anything starting with a dot — don’t
show by default in Finder or in the macOS file dialog.
The trick: in Finder or the “Choose file” dialog, press Shift + Command + . (period).
That toggles hidden files on and off; now the .kobo folder appears and you can navigate
into it to KoboReader.sqlite. The same shortcut again hides them.
Why Chromium-only, desktop-only
The File System Access API today only works in Chrome or Edge on desktop. Firefox, Safari, and mobile browsers don’t support it. Rather than failing cryptically, the app shows a clear notice in those cases: this is a Chromium desktop tool. That’s the cost of installing nothing — and for me a fine trade.
Hosting
Runs on Fly.io as a single scale-to-zero app at kobo2readwise.fly.dev. Because every user enters their own token in the browser, the server needs no Readwise secret at all. Deploys go through release-please: a real version bump (merging the release PR) triggers a production deploy; ordinary feature merges don’t.
The stack, in one line: Python 3.14+, FastAPI for the proxy, sql.js (SQLite as WASM) and the File System Access API for reading in the browser, vanilla JS for the UI, and uv for packaging.
Ik leen mijn boeken uit de online bibliotheek en lees ze op mijn Kobo. Tijdens het lezen markeer ik van alles — zinnen die blijven hangen, dingen die ik wil onthouden. Die aantekeningen wil ik in Readwise hebben, waar de rest van mijn highlights ook staat. Alleen: dat gaat niet vanzelf.
Boeken uit de Kobo-winkel, Kobo Plus en bibliotheekleningen synct Readwise zelf al. Maar
zelf-geüploade boeken — EPUB’s die je via Calibre, mail of USB op het apparaat zet,
of bijvoorbeeld een lening uit de online bibliotheek
die je met Adobe Digital Editions op je Kobo zet — zijn een ander verhaal. Hun highlights leven alleen in de lokale KoboReader.sqlite op
de e-reader en bereiken de Kobo-cloud nooit, dus Readwise kan er niet bij.
De bestaande oplossing is een desktop-app
Voor precies dit probleem bestaat October: een keurige, open-source desktop-app die je Kobo herkent zodra je ’m inplugt, de database uitleest en de highlights naar Readwise uploadt. Werkt prima. Maar het is wél iets dat je installeert, per besturingssysteem, en bijhoudt.
Ik dacht: dat kan tegenwoordig ook gewoon in de browser. Chrome en Edge kunnen met de File System Access API een bestand op je schijf lezen zónder het te uploaden, en sql.js draait SQLite als WebAssembly ín het tabblad. Samen is dat alles wat je nodig hebt: geen installatie, één URL.
Hoe het werkt
De flow is kort:
bestand kiezen → SQLite lezen in de browser → highlights doorsturen naar Readwise.
Je kiest je KoboReader.sqlite, sql.js leest ’m lokaal uit (het bestand verlaat je
computer nooit), en de app laat per boek zien welke highlights ze gaat sturen. Een dunne
proxy neemt die batch aan en zet ’m door naar de Readwise-API — meer doet de server niet.
Het vertrouwensmodel: de token wordt vergeten
Er is één ding dat de server wél aanraakt: je Readwise-token, want dat moet in de
Authorization-header naar Readwise. Dus daar is de hele opzet omheen gebouwd: de proxy
stuurt je token door en vergeet ’m daarna meteen. Geen logging van request-bodies, geen
opslag, geen database. De token leeft alleen in het geheugen voor de duur van één
verzoek. Dat is het hele punt van de app — en het staat als expliciete belofte boven in
app.py.
Om diezelfde reden is sql.js self-hosted in plaats van van een CDN geladen: op de pagina die tijdelijk je token vasthoudt, wil je geen script van derden laten draaien.
Het bestand vinden: verborgen mappen tonen
De KoboReader.sqlite zit in een verborgen map genaamd .kobo, in de root van je
e-reader wanneer je ’m via USB aankoppelt. Verborgen mappen — alles wat met een punt
begint — zie je standaard niet in Finder of het bestandsdialoog van macOS.
De truc: druk in Finder of in het “Kies bestand”-venster op Shift + Command + .
(punt). Dat schakelt verborgen bestanden aan en uit; nu verschijnt de .kobo-map en kun
je erin naar KoboReader.sqlite navigeren. Nog een keer dezelfde toetscombinatie
verbergt ze weer.
Waarom alleen Chromium, alleen desktop
De File System Access API werkt vandaag alleen in Chrome of Edge op desktop. Firefox, Safari en mobiele browsers ondersteunen ’m niet. In plaats van cryptisch te falen toont de app in die gevallen een duidelijke melding: dit is een Chromium-desktop-tool. Dat is de prijs van geen-app-installeren — en voor mij een prima ruil.
Hosting
Draait op Fly.io als één scale-to-zero-app op kobo2readwise.fly.dev. Omdat elke gebruiker z’n eigen token in de browser invoert, heeft de server geen enkel Readwise-geheim nodig. Deploys gaan via release-please: een echte versiebump (het mergen van de release-PR) triggert een productie-deploy, gewone feature-merges niet.
De stack, in één regel: Python 3.14+, FastAPI voor de proxy, sql.js (SQLite als WASM) en de File System Access API voor het lezen in de browser, vanilla JS voor de UI, en uv voor packaging.
Visit the site ↗Bekijk de site ↗ view on githubbekijk op github