SigNoteSigNote
Documentation

Privacy 🔏

This page describes what SigNote stores, what it never stores, and who else sees any of it. It's written to be checkable: every claim here corresponds to code you can read, and the table at the bottom tells you where to look.

The short version:

  • Your notes are yours. Tiers 2 and 3 are encrypted in your browser; the server only ever holds ciphertext.
  • There is no password, anywhere. An email address is optional too — sign in with a wallet and SigNote never learns one. Nothing is sold or shared for advertising.
  • What is collected is small and boring: enough to sign you in, enough to show you your own devices, and product analytics that never contain note bodies.

⚠️ Placeholders. The controller entity, contact address, and governing jurisdiction below still need to be filled in before this page is treated as a published policy. Everything factual about data handling is accurate as of the current code.

Who this covers. These practices describe the hosted SigNote instance. If you run your own, you are the operator of your data and this page describes only the defaults you inherit from the code.


What SigNote stores 📦

Your account

FieldWhere it comes from
Internal user IDGenerated at first sign-in
Display nameYour wallet address, or your Google profile name
Provider identityOne row per linked method: a wallet address, a Google account ID, or an address
Email addressOnly once you prove you control it — an emailed code, or Google saying it is verified. A wallet-only account has none.
Passkey credentialPublic key, usage counter, device/sync metadata, and the nickname you give it. The private key never reaches SigNote.
Raw provider profileThe profile object Google returned, stored as-is
Sign-in codesA keyed hash of the live code, never the code — deleted once used or expired
Created / updated stampsTimestamps

There is no password field anywhere in the schema, because there is no password. → Sign in

Your notes

TierTitleBodyAlso stored
1 — NotesPlaintextPlaintextColour, pattern, pinned, archived, expiry, burn flag
2 — SecretsPlaintextCiphertext + IVSame metadata
3 — SealsPlaintextCiphertext + IVSame metadata, plus the wrapped per-note key

Three things are plaintext on every tier, and it's worth repeating:

  • Titles. Searchable by design, and never encrypted.
  • Tags. Names and colours, on all three tiers. → Tags
  • Metadata. Colour, pin state, timestamps, expiry.

Don't put a secret in a title or a tag name.

Tier 1 titles and bodies are additionally kept in a full-text search index so search can work server-side. Tier 2 and 3 search matches titles only, because the bodies are ciphertext.

Version history stores past revisions in the same shape as the current note — plaintext for Tier 1, ciphertext for Tiers 2 and 3.

Your files

File bytes live in S3-compatible object storage. For Secrets and Seals they are encrypted in your browser before upload; for Notes they are stored as-is. → File uploads

The metadata is always plaintext, on every tier: filename, byte size, MIME type, and which note it belongs to. A file called passport-scan.pdf announces itself by its name even when its contents are encrypted.

Your encryption profile

salt, the KDF parameters, serverShare, and keyCheck. None of these can decrypt anything on their own — that is the entire point of the two-share design. → Security

Your sessions

Each active sign-in gets a row so you can see and revoke your own devices:

FieldWhy
Session ID, providerIdentify the session
Client (web or desktop)Label it in your device list
IP addressShown to you; stored in full, not truncated
User agent, browser, OSHuman-readable device label
Created, last seen, expirySession lifetime

Sign-in nonces and desktop sign-in attempts also record an IP address for the few minutes they exist, to make replay harder.


What SigNote never stores 🚫

  • Your passphrase. It is processed in your browser and never transmitted.
  • Your deviceShare. It lives in sessionStorage on your device only.
  • Your Master Encryption Key. It exists in browser memory, briefly, and nowhere else.
  • Plaintext Secret or Seal bodies, or plaintext of the files attached to them.
  • Your wallet's private key. Signing happens in your wallet; SigNote sees a signature.
  • Payment details. There is nothing to pay for.

Because of the first three, nobody can reset your passphrase — not you, not an admin, not a court order served on the server. → Recovery


Analytics 📊

SigNote uses PostHog (US region) for product analytics. Requests are proxied through this site's own /ingest path rather than going to a third-party domain directly.

You are identified to PostHog by your internal user ID and display name. For a Google account that display name is the name Google gave; for a wallet, it's your address.

What is captured:

KindExamples
Named product eventssign_in_started, vault_unlocked, vault_locked, search_opened, file_uploaded, passphrase_changed, recovery_completed, account_erased
ErrorsException messages and stack traces, so crashes get fixed

Page views, click/form autocapture, rage clicks, heatmaps, dead clicks, Session Replay, and network request body/header recording are disabled in the application code. Those local settings are fail-closed: a PostHog dashboard configuration cannot turn them back on. Every remaining event also has URL-derived properties removed before it is sent, so search terms and note route identifiers do not become analytics properties.

Note bodies, titles, tags, and Secret or Seal content (encrypted or decrypted) are never sent to analytics. Named event properties are deliberately coarse — file_uploaded, for instance, records only a MIME category and whether the file was encrypted.


What lives on your own device 💾

StoreWhat's in itCleared when
sessionStoragedeviceShareTab closes, hard lock, sign-out
Browser memoryThe MEK and any decrypted bodiesLock, tab close, 5 min idle
IndexedDBCached server responses plus the encrypted Authenticator cache and its non-extractable trusted-device keySign-out/session termination; response cache also expires after 7 days
CookiesThe session JWT (7 days) and PostHog's analytics cookiesExpiry or sign-out

Decrypted Secret and Seal bodies are held in memory only — they are never written to IndexedDB. → Threat model


Who else is involved 🤝

Running the hosted instance means a handful of other companies process some of this data:

ProviderWhat they handle
VercelHosting and request logs
SupabaseThe Postgres database
S3-compatible storageFile attachment bytes
PostHog (US)Product analytics
ResendDelivering email — sign-in codes and notifications
GoogleOAuth sign-in — only if you choose it
WalletConnectThe connection to your wallet — only if you use one

Nothing is sold, and nothing is shared with advertisers. There is no ad network in this app.


How long it's kept ⏳

DataRetention
Notes, secrets, sealsUntil you delete them
Deleted notesPurged about an hour after deletion by the cleanup sweep
Notes with an expiry or burn flagPurged about an hour after they expire or are read
Version historyA capped number of recent revisions per note
SessionsDeleted at expiry (7 days) or when you revoke them
Sign-in nonces, desktop attemptsMinutes
File attachmentsWith their note; orphans are collected by the same sweep
Analytics eventsPer PostHog's project retention — not removed by account erase

Your choices 🎛️

  • Pick the right tier. Anything you don't want the server to be able to read belongs in a Secret or a Seal, not a Note.
  • Sign in with a wallet if you'd rather not hand over an email address at all.
  • Turn off optional email. Product news and new-sign-in alerts are both switchable under Notifications. Sign-in codes are not optional — switching those off would lock you out.
  • Revoke a session from your devices list the moment something looks unfamiliar.
  • Erase selectively. You can erase your seals, secrets, notes, files, or your encryption profile independently — or the whole account, which deletes the user row and every linked identity.
  • Run your own instance if you'd rather not trust anyone else's. → Self-hosting guide

Account erase is immediate and irreversible. It does not reach into analytics events already collected, or into provider-side backups that exist for disaster recovery.


Children

SigNote is not directed at children and no account is knowingly created for anyone under the age required by local law.

Changes

Material changes to this page will be noted in the repository history, which is public — the file is src/docs/1.privacy.md and every revision to it is in the git log.

Contact

Placeholder: controller entity, postal address, and a contact email for privacy requests.

For anything about the code itself, open an issue: 👉 github.com/irondsd/signote


Verify it yourself 🔍

ClaimWhere to read the code
Exactly which columns exist, on every tablesrc/db/schema.ts
Passphrase, deviceShare and MEK never leave the browsersrc/lib/crypto.ts, src/contexts/EncryptionContext.tsx
Which analytics events are sent, and their propertiesSearch the repo for posthog.capture
Analytics configuration and privacy invariantsinstrumentation-client.ts
What the cleanup sweep deletes, and whensrc/controllers/cleanup.ts
What account erase actually deletessrc/controllers/erase.ts
What is persisted to IndexedDBsrc/providers/QueryPersister.tsx
Session fields shown in your device listsrc/controllers/authSessions.ts

Where to go next