Security
Getting your notes out, whatever happens
An encrypted export and your recovery key are all you need to turn your notes back into Markdown files.
Your notes are yours. Even if the server is gone, the apps stop working or you simply want to leave, you can turn everything you could read back into ordinary Markdown files — offline, with nothing but your recovery key (or a device that is still signed in) and an encrypted export.
The pieces
- Encrypted export — one JSON file with everything you can read, exactly as the server stores it: encrypted notes (the latest snapshot of each and the changes made after it — not their older revisions), attachments, and your copies of the keys, themselves encrypted. Nobody can read it without your keys, so it is safe to keep in a backup.
- Recovery key — shown once when you set up your account (11 groups of five letters and digits). It unlocks your account key, which unlocks the vault keys in the export.
notekpr recover— the CLI command that puts the two together. It needs no server and no network.
Keep an encrypted export (recommended)
From a signed-in CLI, now and then:
notekpr export-encrypted --out ~/Backups/notekpr-$(date +%F).json
or download it from the server's API as yourself (GET /api/v1/me/export).
Recover
With your recovery key and an export (no server needed):
notekpr recover --from notekpr-2026-10-19.json --out ~/Recovered
# asks for the recovery key; or --recovery-key-file FILE, or the
# NOTEKPR_RECOVERY_KEY environment variable
recover only needs the notekpr binary — no profile, no sign-in and no
network.
With a device that is still signed in (downloads the export and decrypts it with this device's keys):
notekpr recover --out ~/Recovered
If the server can't be reached (or this device is no longer signed in), the
same command recovers from the device's own encrypted copies instead, and says
so; --local does that without contacting the server at all. Those copies hold
the vaults this device keeps, as far as it synced them (with its unsent edits),
and the attachments it downloaded; others are listed as not recovered. Notes
shared with you one by one aren't kept on devices: only an export has them.
From a server backup (if you run the server, or can get its database file): first write your encrypted export from the backup with the server tool — it never decrypts anything — then recover as above.
notekpr-server export-user --backup notekpr-2026-10-01.db --user [email protected] --out you.json
notekpr recover --from you.json --out ~/Recovered
--user takes your e-mail address, display name or user id. The backup file
isn't changed (the tool works on a copy).
What you get
~/Recovered/
Family/ one folder per vault
Plans/Trip.md
assets/photo.jpg
_trash/Old note.md what was in the trash
_comments/Plans/Trip.md the comments on Plans/Trip.md
Garden.drawing drawings, as notekpr's .drawing files (pictures inside)
Quick notes/ your Personal storage
2026-10-19 14.32.md
Saved shapes.excalidrawlib your saved shapes, as Excalidraw's library file
Shared with me/ notes shared with you individually
Weekend trip.md
_comments/Weekend trip.md
A note's comments are a Markdown file of their own under _comments/:
each thread with the text it is about, its comment and replies, who wrote
them and when. An encrypted export names the people in it; recovering
from a device's own copies (--local) can't ask the server for names, so
there they are user ids.
--out must be a new or empty folder. Each note is written with its current
text (older revisions aren't recovered). Folders are private to you (mode
0700, files 0600) — the files are plain text now, so treat the folder like any
private document. Anything that couldn't be decrypted (for example content
written under a key you never received) is listed at the end; everything else
is still recovered.
Without any notekpr software
The formats are standard and documented, so an independent tool can do the
same: the export is JSON (EncryptedExport in
crates/core/src/protocol.rs), and the
encryption is described in protocol.md §2:
- Recovery key → account secret: decode the key (base32, 32 bytes + 2-byte
checksum) and open
recovery_envelope(XChaCha20-Poly1305 symmetric envelope, purposeRecovery, context = your user id). - Account secret → vault keys: open your
keys.envelopes(HPKE RFC 9180, X25519 / HKDF-SHA256 / ChaCha20-Poly1305) for each epoch; older epochs follow fromkeys.chain. Shared notes' own keys come fromkeys.objects(wrapped under the vault key) or, for notes shared with you, from your envelopes inshared_notes[].keys. - Decrypt each snapshot and update (
Snapshot/Updatepurposes) and apply them as Yjs/yrs v1 updates. The vault index (objectindex, aY.Mapnamedfiles) maps entry ids to paths and kinds; each note's text is aY.Textnamedcontent. Attachments are single symmetric envelopes (purposeAttachment, context = vault id and attachment id).