Privacy charter & threat model
Most period apps promise "we take your privacy seriously" and then send your cycle data to their servers, their analytics provider, and — in the cases that made the news — to advertisers. LunaLocal's promise is architectural instead of contractual: there is no server to send your data to. This page says exactly what that protects you from, what it doesn't, and how to check our work.
1. The architecture
- Your data lives in your browser's storage (IndexedDB, with a localStorage fallback) on your device. There is no account, no login, no user ID.
- There is no backend. LunaLocal is static files — HTML, CSS, JavaScript. There is no API endpoint that accepts health data, because none exists.
- Your data never leaves your device; the only network requests on this page are the site's own analytics (Google Analytics and a Cloudflare beacon), which load when the page opens and never see your files. The app itself makes no network requests at all — no fetch, no XHR, no beacons — so no cycle data, symptom, mood, or note is ever transmitted. There is no crash reporting, no fonts, no CDNs, and no other third-party scripts.
- Encrypted backups are yours. Export uses AES-256-GCM with a passphrase-derived key (PBKDF2-SHA256, 600,000 iterations). The passphrase never leaves your device and is never stored — forget it and the backup is unrecoverable, even by us.
2. What this protects you from
| Threat | Protected? | Why |
|---|---|---|
| App company selling or sharing cycle data | Yes | We never receive your data. There is no database of users to sell, breach, or subpoena. |
| Data breach at a tracker company | Yes | Nothing of yours exists on our systems to be breached. |
| Ad networks / analytics SDKs profiling you | Yes | Your cycle data is never sent to any third party. The only third-party requests are the site’s own analytics (Google Analytics and a Cloudflare beacon), which load when the page opens and never see your data — they receive no cycle data, no identifiers, and no account information (there is no account). |
| Legal request to the app maker for your records | Yes | We hold no records. We cannot produce what we never had. |
| Accidental cloud sync of your health data to a vendor | Yes | Cloud sync is permanently out of scope — adding it later would destroy this promise, so it will never be added. |
3. What it honestly cannot protect you from
We will not call LunaLocal "unhackable" or "100% private", because that would be a lie. Read these limits before trusting any local-only tool — including ours:
| Limitation | What it means for you |
|---|---|
| Physical access to your unlocked device | Anyone who can open your browser profile — a partner, family member, border agent, thief — can open LunaLocal and see your data. Use your device's lock screen, and consider your browser's own profile protections. |
| Browser sync features | If you use Chrome/Firefox/Edge profile sync, your browser vendor may copy local site data (including IndexedDB) to their cloud. LunaLocal can't stop your browser from syncing — check your browser's sync settings if this matters to you. |
| Device backups | OS-level backups (iCloud, Google backup) may include browser data. Encrypted device backups mitigate this. |
| Malware / spyware on your device | Keyloggers, screen scrapers, or a compromised browser see everything you type and see. No web app can defend against a compromised device. |
| Shoulder surfing & screenshots | As with any app, someone watching your screen sees your screen. |
| Your own backups | An unencrypted JSON export is readable by anyone who gets the file. Prefer the encrypted backup, and guard the file. |
The bottom line: LunaLocal removes the company from your threat model. It does not remove your device from it. If your threat model includes someone with access to your unlocked phone, no period app — local or otherwise — solves that; a paper calendar in a locked drawer might.
4. Verify it yourself: your data stays on your device
Don't take our word for it. Your browser has a built-in lie detector — the Network tab:
- Open DevTools. Press
F12(Windows/Linux) orCmd+Opt+I(Mac), then click the Network tab. - Reload the tracker page. You'll see requests for
index.html,style.css, and the.mjsscripts — that's the page loading its own files — plus the site’s own analytics (Google Analytics and a Cloudflare beacon), which load once when the page opens. That's expected: a page has to load something. - Now use the app. Log a period, switch months, check history, export a backup. Watch the Network tab.
- What you should see: nothing new while you use the app. No API calls, no requests carrying your data — the request list stays frozen after the initial load. Every feature works with the network cable conceptually unplugged (try it: DevTools → Network → Offline checkbox — the app keeps working).
Live self-check on this page
The script below runs entirely in your browser and counts the third-party sub-resources this page requested from the network (excluding the page document itself). The only third-party requests this page should ever make are the site’s own analytics (Google Analytics and a Cloudflare beacon), which load when the page opens and never see your data:
checking…
Note: the favicon is an inline data: URI, not a network request.
5. Backup file format (documented, open)
Your backups are yours — no proprietary lock-in. Two formats:
Encrypted backup (.lunalocal.json)
{
"format": "lunalocal-backup",
"version": 1,
"encrypted": true,
"algorithm": "AES-256-GCM / PBKDF2-SHA256",
"kdfIterations": 600000,
"salt": "<base64, 16 bytes>",
"iv": "<base64, 12 bytes>",
"data": "<base64, AES-GCM ciphertext of the JSON payload below>"
}
The ciphertext decrypts (AES-256-GCM, key = PBKDF2-SHA256(passphrase, salt, 600,000 iterations)) to:
{
"app": "lunalocal",
"version": 1,
"exportedAt": "<ISO timestamp>",
"days": {
"2026-10-01": {
"date": "2026-10-01",
"flow": "medium", // none | spotting | light | medium | heavy
"symptoms": ["cramps"], // from the fixed symptom list
"mood": "calm", // from the fixed mood list, or null
"notes": "…"
}
}
}
Plain export
Same days structure wrapped in {"format": "lunalocal-export-plain", "encrypted": false, …} — unencrypted, clearly labeled in the file itself.
6. Predictions & medical honesty
LunaLocal predicts your next period and fertile window with the standard calendar method (average of your recent cycle lengths, ovulation estimated at 14 days before the next predicted period). Every prediction in the app is labeled an estimate. LunaLocal is a personal tracking tool, not a medical device: it is not a diagnostic tool, not medical advice, and its estimates must never be used for contraception decisions. If something about your cycle worries you, talk to a clinician.
7. Why local-only, why now
Period apps have faced major privacy settlements and verdicts over sharing intimate health data with third parties — and research keeps finding that deleting period apps is people's most common privacy self-defense. The industry's answer has been longer privacy policies. Ours is a different architecture: a period tracker that can't leak — because there's nowhere to leak to. No account. No servers. Your cycle data never leaves your device. Free forever.