Skip to main content

zotrm

CI PyPI Python License: MIT

Read your Zotero papers on a reMarkable Paper Pro, then get your handwritten notes back into Zotero — with one command.

Demo

zotrm in action: push papers, annotate on the tablet, pull them back

Recording the GIF: see how to record the demo.

What it does, in plain words:

  • push — sends the PDFs from one Zotero collection to your reMarkable tablet.
  • pull — brings the marked-up PDFs back and attaches them to the same Zotero papers.
  • status — shows which papers are waiting, on the tablet, or already done.
  • sync — does a pull and then a push, together.

You never push or pull the same paper twice by mistake — the tool remembers what it has done. It is safe to run again and again.

One honest limit (this is reMarkable's behavior, not a bug here): Your highlights and handwriting come back as part of the PDF image — "painted onto" the page. They do not come back as clickable Zotero highlights.

Why zotrm?

If you read research papers on a reMarkable, getting them on and off the tablet is fiddly: export each PDF, drag it into the reMarkable app, and later dig the annotated copy back out and re-file it in Zotero. zotrm makes that one command in each direction, driven by the collection you already curate in Zotero:

  • No manual file shuffling — it reads your Zotero collection and uploads the PDFs for you.
  • Folders match your library — Zotero sub-collections become nested folders on the tablet.
  • Nothing pushed or pulled twice — progress is tracked with Zotero tags, so it's safe to re-run or schedule with zotrm cron.
  • No extra database or account — just your Zotero API key and the rmapi tool.

It's a small, focused CLI — not a sync daemon or a cloud service.


Before you start (what you need)

  1. A Zotero account with some PDFs in it.
  2. A reMarkable tablet, turned on and connected to WiFi.
  3. A reMarkable Connect subscription — this is what lets files move to and from the tablet over the internet. Without it, push and pull may not work.
  4. A computer (Mac or Linux) where you can open a Terminal (a window where you type commands). On a Mac, open the app called Terminal.

You will copy and paste a few commands. That is all.


Setup (about 10 minutes)

Step 1 — Install uv

uv installs this tool for you. Paste this into the Terminal and press Enter:

curl -LsSf https://astral.sh/uv/install.sh | sh

Close the Terminal and open it again so the change takes effect.

Step 2 — Install rmapi and connect it to your tablet

rmapi is a separate program that talks to your reMarkable:

brew install rmapi

(No Homebrew? See https://github.com/ddvk/rmapi for other ways. Use the ddvk version — the original does not work with new tablets.)

Now connect it to your tablet one time:

rmapi

It shows a web address and asks for a code. Open https://my.remarkable.com/device/desktop, copy the code shown there, and paste it into the Terminal. Done — you won't do this again.

Step 3 — Install zotrm

uv tool install zotrm

Step 4 — Set up your account

A friendly wizard fills in your settings for you. First grab two things from Zotero, then run it.

4a. Get your Zotero details (about a minute)

Open https://www.zotero.org/settings/keys and log in. You need two things from this page:

  1. Your library ID — near the top it reads "Your userID for use in API calls is 1234567." That number is your library ID.
  2. An API key — click Create new private key, give it a name, tick Allow library access with both read and write (write lets zotrm save tags and attach your annotated PDFs), click Save Key, and copy the key — you can't see it again later.

4b. Make a collection to sync (recommended)

In the Zotero app, create a collection — say, named reMarkable — and drag in a few papers you want to read. zotrm only ever touches papers in this one collection. Start with a throwaway collection of 1–2 papers while you try things out.

4c. Run the wizard

zotrm config

Use the arrow keys ↑↓ to choose and Enter to confirm. Here is every question and what to put:

Question What to enter
Zotero library ID The userID number from step 4a.
Zotero API key The key from step 4a (hidden as you type/paste).
Library type user — choose group only for a shared group library.
Local Zotero storage dir (optional) Where the Zotero app keeps your PDFs, usually ~/Zotero/storage. Lets zotrm read files from disk instead of re-downloading. Press Enter to skip if unsure.
Zotero collection to sync The collection name from step 4b (e.g. reMarkable) — must match exactly, capitals included.
reMarkable folder Where papers land on the tablet, e.g. /Papers (created if missing).
Mirror sub-collections? Yes recreates your Zotero sub-collections as nested folders on the tablet; No puts everything in one folder.
Where to save annotated PDFs A folder on your computer for the marked-up copies, e.g. ~/Zotero/annotated.
Re-attach annotated PDF? Yes adds the annotated copy back onto the paper in Zotero.

When you finish, it checks your details (you'll see ✓ Zotero connection OK), warns if rmapi is missing, and saves everything to ~/.config/zotrm/config.ini.

The wizard also starts on its own the first time you run any command before setting up. To change settings later, run zotrm config again; to see what's saved (API key masked), run zotrm config --show.

Step 5 — Use it

Send your papers to the tablet:

zotrm push

Read and annotate them on the reMarkable. When you're done, bring them back:

zotrm pull

That's the whole loop. 🎉

Step 6 (optional) — Make it automatic

Want it to sync by itself on a schedule? Run:

zotrm cron

Pick how often (every hour, daily, etc.) and it sets everything up for you. Remove it later with zotrm cron --remove.


Everyday commands

zotrm push      # send waiting papers to the tablet
zotrm pull      # bring marked-up papers back into Zotero
zotrm status    # see what is waiting / on the tablet / done
zotrm sync      # pull, then push, in one step

zotrm config    # change your settings any time
zotrm cron      # set up (or change) automatic syncing

Not sure what a command will do? Add --dry-run to see without changing anything:

zotrm --dry-run push

If something goes wrong

  • "rmapi not found" → Step 2 was missed, or reopen the Terminal.
  • "config not found" → Run zotrm config to set up your account.
  • "no Zotero collection named ..." → The collection name in your settings doesn't exactly match a collection in Zotero. Check spelling and capital letters (zotrm config --show prints your current settings).
  • Pull finds nothing → Make sure the tablet is online and finished syncing, and that you have a reMarkable Connect subscription.

Run any command with --dry-run first if you're unsure — it changes nothing.


FAQ

Do I need a reMarkable Connect subscription? Yes, in practice. zotrm talks to the reMarkable cloud through rmapi, and two-way document sync (uploading PDFs and downloading annotated ones) needs Connect.

Why don't my highlights come back as real Zotero highlights? The reMarkable returns a flattened PDF — your marks are baked into the page image. That's a reMarkable limitation, not something zotrm can change. You get a faithful annotated PDF re-attached to the item, just not editable highlight objects.

Does it duplicate files if I run it again? No. It tags items rm:synced once pushed and rm:annotated once pulled back, and skips anything already done. Re-run it (or schedule it) freely.

Can I use it with more than one Zotero library? Yes — keep separate config files and pass --config. See advanced usage.

Does it work on Windows? Not currently. zotrm targets macOS and Linux (the cron scheduler is Unix-only).

Is my Zotero API key safe? It's stored only in your local config file (~/.config/zotrm/config.ini) and never sent anywhere except Zotero's own API. zotrm config --show masks it.


More

  • Advanced usage — editing the config file by hand, the full settings reference, how the scheduled sync works, multiple configs, and deeper troubleshooting.
  • Contributing — set up the project for development and run the tests.

License

MIT — see LICENSE.

Release files for zotrm 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zotrm 0.1.1
File Size Uploaded
zotrm-0.1.1.tar.gz 2.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for zotrm 0.1.1
File Interpreter ABI Platform
zotrm-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 2.0 MB

Release files / zotrm-0.1.1.tar.gz

Download URL zotrm-0.1.1.tar.gz
Size 2.0 MB
Tags Source
SHA-256 checksum
How to use checksums
7afd3de17a2163a1dcde8285e847cc990baa7b0f01739a7288063248d8a8a2f1
BLAKE2b-256 checksum
How to use checksums
eb37003837ab0083af28b67455559d2f2ebfbf372abb0e26ee840a38fe5e4c20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 24, 2026.

Transparency log

Release files / zotrm-0.1.1-py3-none-any.whl

Download URL zotrm-0.1.1-py3-none-any.whl
Size 17.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9efc7696ac2544783bcd329d4c5c76e6d23e148611e4ba3ad5d3f7b129c99250
BLAKE2b-256 checksum
How to use checksums
2a9c20eabb8b5df24486925cac6f6b3317238b9d9769805a9367433aa7e3b119
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page