Skip to content
Privacy · Policy 2026-09-01

What we keep, and what we cannot keep.

Most privacy policies are written to survive a lawyer. This one is written against the database schema, which is published, so every claim below can be checked against server/src/db/schema/pg.ts rather than taken on trust. Where the honest answer is "we have not built that yet", it says so.

Policy version
2026-09-01 — the version your extension recorded
Applies to
cypherkey.io, the extension, and api.cypherkey.io
Data controller
Irietek Corporation
Questions
hello@cypherkey.io
The short version

Four sentences, then the detail.

Your vault

We cannot read it

It reaches us already encrypted, and the key is derived on your device from a passphrase we never receive. A full copy of our database is a pile of ciphertext.

Your rhythm

Statistics, not recordings

We keep per-feature means and standard deviations. We do not keep your keystrokes, and after enrolment finishes we do not keep the measurements they came from.

Your identity

A username and an email

That is the whole of it. No name, no phone number, no address, no payment details — there is nothing to pay for yet.

This website

Google Analytics, disclosed

The marketing pages carry GA4 and it sets cookies. The Rhythm Trial deliberately carries none, because that page's whole claim is that nothing leaves your browser.

Every table, named

The server has fourteen tables. Here is what is in the ones about you.

The remaining tables hold nonces, token buckets and lockout counters — mechanical state with no content of yours in it. Everything keyed to your account goes when the account goes, and the audit row below says precisely what that leaves behind, because "we delete everything" is the kind of sentence a policy says and a schema quietly contradicts.

Table What is actually in it Can we read it?
vault_items Ciphertext and a nonce, per item. A version number and a cursor so your devices can sync. Nothing else — not the site, not the username, not the title. No
users Your username and email in the clear. A salt, the Argon2id cost parameters, and a hash we compare against — never your passphrase. Your vault key, wrapped. The timestamp of your consent and the policy version you consented to. Username and email, yes
biometric_profiles Per-feature means, standard deviations and weights. The length of your script, the number of samples it was built from, and commitments that let us check you typed the same phrase — not what the phrase is. Yes, and it is not reversible
enrollment_samples The eight measurement vectors, and only while you are enrolling. The moment the profile is built they are deleted. This is the one table in the schema permitted to hold a feature vector, and a test enforces that. Briefly, then gone
auth_score_history One row per unlock: a similarity score, the band it fell in, which device, and when. This is how thresholds will adapt to you rather than to an average stranger. It is a number about a comparison, not a recording of typing. Yes
devices A public key, the name you gave the device, its platform, and when it was last seen. You can see this list and revoke any row in it from settings. Yes
backup_codes One-way hashes of your ten codes, and whether each has been used. The codes themselves are not recoverable from this table, by us or by anyone who steals it. No
audit_log Security events — logins, device changes, step-ups. The IP address is hashed, never stored in the clear. Deleting your account removes every row that named you. What is left is the row recording the deletion itself, and rows from signup and login, which were written with no account on them at all because there was no session yet to name one. Event and timestamp, yes

Two things are deliberately absent from that list and from the schema: any column for raw keystroke events, and any column for a passphrase. A test asserts their absence by pattern, so adding one is a build failure rather than an oversight.

Biometric data

The rhythm is biometric data, so we treat it the way the strictest law would.

How you type is information about your body. Several jurisdictions — Illinois' BIPA, the GDPR's Article 9, Texas and Washington — treat that as a special category needing explicit, informed, opt-in consent rather than a checkbox buried in terms. We assume the strictest of them applies to everyone, because sorting users by jurisdiction to decide who deserves consent is not a thing we want to build.

Consent is explicit and versioned. You tick a box that names this policy by version before anything is captured, and the version you agreed to is stored on your account. If this document changes materially, that number changes, and you will be asked again rather than deemed to have agreed retroactively.

There is always a visible indicator. The Rhythm Light is on screen whenever a field is measuring, and it is the only time a field is measuring. It is not a decoration we could quietly stop honouring — the capture component and the light are the same component.

What a login does with your timings. Your browser turns the keystrokes into a vector of numbers and sends that. The server compares it to your profile, returns a band — pass, grey or fail — and discards the vector in the same request. It is never written to a table. The server also never returns the score itself, which is a security property rather than a privacy one, and the technology page explains why.

What we cannot do with the profile. Means and standard deviations are not a recording. You cannot reconstruct a passphrase from them, and you cannot replay them at a login — ours or anyone else's. That is the point of storing statistics: a stolen profile is not a usable impersonation of your hands.

You can turn it off. Settings has a pause, and disabling the rhythm factor entirely is supported — it falls back to passphrase plus step-up. Deleting the profile deletes the statistics; nothing derived from them is kept elsewhere.

Never in the clear

Four things the server refuses to hold.

Your passphrase

It never leaves your device. What crosses the network is a value derived from it through Argon2id and HKDF, and what we store is a hash of that.

Your IP address

The audit log stores a hash of it. Rate limiting stores an HMAC of it under a server secret. Neither table can be read backwards into an address.

Your keystrokes

No key names, no key codes, no per-key timings after enrolment. The schema has no column that could hold them.

Your vault, in plaintext

Encryption and decryption happen on your device. The server has never seen a decrypted item and has no code path that could.

Analytics, plainly

This site runs Google Analytics. That sets cookies.

We would rather tell you than have you find it in devtools. The marketing pages — this one, the landing page, technology, compare, pricing, beta, founder — load Google Analytics 4, property G-J20MXLEEJV. It sets _ga and _ga_* cookies in your browser and reports page views to Google LLC in the United States, who process it on our behalf.

We use it for one thing: which pages people read before they ask for a beta seat. We do not send it anything about your typing, and there is nothing about your account to send, because these pages have no account.

The Rhythm Trial carries none of it. /demo.html tells you in its own rail that it has made zero network requests, and that claim has to be true on the one page a sceptical visitor is most likely to check. A test in the repository fails the build if analytics ever reaches that page, including indirectly through a shared bundle.

How to refuse it. Google publishes a browser opt-out add-on, and any content blocker stops it. Nothing on this site breaks without it.

What we owe you here, and have not yet built. Under EU and UK ePrivacy rules, analytics cookies want consent before they are set, not disclosure afterwards. We do not yet show a consent banner. That is a gap, it is named in our own roadmap, and it will be closed before public launch — either with a banner or by replacing GA with something that sets no cookies at all. Until then, this paragraph is the honest version of a notice you should have been given first.

Who else is involved

Three companies, and what each one can see.

Who What for What they can see
Google Cloud Hosting — Cloud Run, Cloud SQL and the CDN, in us-central1 The database as it sits on their disks, which is the encrypted vault and the tables above. Same view we have, and no more.
Google Analytics Page views on the marketing pages Which page, from roughly where, on what kind of device. Never the trial.
MXroute Mail for @cypherkey.io Email you send us, because that is what a mail host is.

No advertising networks, no session recording, no heatmaps, no chat widget, no A/B testing service, no CDN for fonts — the fonts are served from this origin precisely so that loading a page tells nobody else you did. The site's Content-Security-Policy is what enforces most of that, and it is the reason adding a tracker here is a deliberate act rather than a paste.

Getting your data out, or gone

What you can ask for, and what happens when you do.

Export. Your vault is already yours — the extension exports it, decrypted, on your device, without asking us. That is the only copy that is readable anywhere.

Deletion. Email hello@cypherkey.io from your account address and we will delete the account. It is one operation and it is immediate: the database removes your vault, your rhythm profile, your devices, your tokens and your Backup Codes in the same statement, because every one of those tables is keyed to your account and set to go with it. Your audit rows are deleted alongside them. Nothing is queued, and there is no thirty-day window in which we still hold it.

This should be a button, and it is not one yet. The server can do it — the endpoint exists, and it requires your passphrase in the request rather than merely an unlocked session, so a borrowed laptop cannot destroy a vault. What is missing is the control on the settings screen, which is why the email above is the real mechanism today rather than a fallback we mention politely. The screen ships before public launch.

Correction and access. The settings screen shows your devices, your rhythm profile's summary and your account details. Anything it does not show, ask us for.

Self-hosting. The whole server is AGPL and runs with docker compose up. Run it yourself and none of this section is about you — there is no account with us to delete, and no third party in the list above except the ones you choose.

When this changes

A version number, not a quiet edit.

This policy is version 2026-09-01. Your account stores the version you consented to, so we can tell the difference between someone who agreed to this text and someone who agreed to an older one. A material change gets a new version and a fresh ask — not a "last updated" line at the bottom and an assumption you re-read it.

Security disclosure has its own address and its own policy: security@cypherkey.io, and SECURITY.md in the repository.