Skip to content

Cookie & Local Storage Notice

Effective 2026-09-13 · Version 3.7

This notice explains what Lonzo stores on your device and why. Every single thing we store on your device is strictly necessary to sign you in and run the app. There is no preference storage, because there is nothing we keep on your device that you could set. We do not use advertising cookies, and we do not embed third-party analytics or tracking software.

This notice applies to the Lonzo web app and our native mobile app(s), and the two are genuinely different — so they have a section each. The web app stores eight small values in your browser and nothing else (Section 1). The mobile app is local-first: it does the work on your device, which means it keeps your own content there too (Section 1A). Neither stores anything for tracking.

Cookies, local storage, and IndexedDB — the plain version. A cookie is a small piece of text a website stores in your browser and sends back to the server on each visit, while local storage and IndexedDB are browser databases that keep data on your device and are not automatically sent to any server. In the browser Lonzo relies on IndexedDB, local storage, and session storage — data that stays on your device to sign you in and to hold your device's identity key — and on no tracking cookies at all. We set no cookies of any kind. The mobile app uses none of these browser mechanisms; it stores files in its own app-private storage, which Section 1A lists.


1. What we store in your browser, and why

This is the complete set of what the Lonzo web app stores in your browser. The mobile app stores more than this, and on disk rather than in a browser — Section 1A lists that separately and in full. The key names below begin with tλnk: — an internal system prefix from our underlying platform, not a separate service or a third party; they are listed exactly as they appear on your device so you can find and verify them yourself:

KeyWhereCategoryPurposeRetention / Expiry
tλnk:auth:credentialsBrowser localStorageStrictly necessaryYour session/auth credential — keeps you signed in without re-entering credentials each time. What is inside it, because this notice used to say only "your credential" and leave you to guess (corrected 2026-09-06): the certificate that proves this browser is you, and the token used to renew it; the identifier you signed in with — which on a password sign-in is your email address, kept in a field named username, and on a "Continue with Google" sign-in is the short handle we build from that address instead; your account identifier (account_id); the internal identifiers of your account and of this browser; and the public key our platform's certificates are checked against. There is nothing in it about what you do in Lonzo — no mail, no calendar events, no contacts, no drafts. If you sign more than one account in on this browser, this key holds one credential per account, so that each tab comes back to the account it was showing rather than to whichever account signed in last — which also means this one key shows how many of your accounts are signed in on this browser, and which.Cleared when you sign out — the entry for the account you signed out of, and the whole key once no signed-in account is left. The credential is issued for 14 days and the app renews it in the background while Lonzo is open; once it has expired, signing in again is required, and the app clears the old value the next time you open it.
tλnk:auth:signin:claimBrowser localStorageStrictly necessaryA one-time value used only while you are signing in with Google, and only in the browser. Google returns you to a different tab from the one you started in, so that page leaves this value behind for your original tab to pick up and finish the sign-in with. Holding it is what shows the sign-in belongs to the browser that actually completed it, rather than to whoever started it — without it, someone who began a sign-in could collect the session you completed. Nothing else is stored under it, and no other page writes it.Removed as soon as your original tab finishes the sign-in, and on sign-out. It also stops working five minutes after it is written, whether or not that happens.
tλnk:shell:keysBrowser IndexedDBStrictly necessaryYour device identity keypair. In the browser the private key is non-extractable — generated inside the browser's own key store, it cannot be read out or exported by us or by the page, and never leaves your device. This is security storage, not tracking. (The mobile app cannot use a non-extractable key; Section 1A says what it does instead.)Persists until account deletion or until you clear site/app data.
tλnk:shell:session_urnBrowser sessionStorageStrictly necessaryThe identifier of your current session in the app.Cleared on tab close.
tλnk:shell:session_urn:support-panelBrowser sessionStorageStrictly necessaryThe identifier of the session behind the support question panel on our public pages (the "Questions about Lonzo" panel on the home, pricing and help pages). It is a separate key from the one above on purpose: the panel and the app are two different things that can be open in one tab, and neither should be handed the other's session. It is written only by that panel, and only on a page that offers it.Cleared on tab close.
tλnk:shell:accountBrowser sessionStorageStrictly necessaryWhich account this tab is signed into — nothing more than the identifier of the account, and only for tabs that have signed in. It exists so that a tab you reload comes back to the account it was showing, rather than to whichever of your accounts signed in or renewed most recently. Before this key existed, reloading one of several signed-in tabs could return you to a different account than the one on screen. It is written only in the app, never by the support question panel above — that panel does not sign anyone in, so it has no account to record.Cleared on tab close, and when you sign out in that tab.
tλnk:reload:attemptsBrowser sessionStorageStrictly necessaryA reload-loop guard, and since 2026-08-23 the app writes it again: when we publish a new version of the app while you have a tab open, that tab can end up holding a mixture of the old and the new and stop working until it is reloaded. It reloads itself once to fix that, and this key is how it counts — one small number, and the count is the only thing stored under it. The count is what makes it once: a tab that reloads and lands in the same trouble stops and tells you instead of reloading over and over.Cleared as soon as the app connects, and on tab close.
tλnk:debugBrowser localStorageDiagnostic, off unless you turn it onA troubleshooting flag. You create it and the app never does — it exists so that a developer, or you at our request, can switch on verbose console logging by setting it by hand, and the app never writes a value into it. If you have not set it, it does not exist. It enables logging to your own browser console only; nothing is sent to us. The app does one thing to it: it removes it when you sign out, and this notice said the opposite until 2026-09-06. Verbose logging switched on for one person used to outlive their sign-out, and because signing out does not reload the page, the next person to sign in on the same browser had their own message subjects — and the values they typed into the sign-in form — written to a console they never opened. Switching it back on after a sign-out means setting it again.Removed when you sign out. Otherwise it stays until you remove it; nothing else expires it.

How long staying signed in actually lasts, stated precisely. This notice said "30 days of inactivity" until 2026-08-17, and both halves of that were wrong: the credential is issued for 14 days, and the clock is not an inactivity timer. Renewal happens in the background when the credential comes due and Lonzo is open at that moment — so a browser tab left open renews indefinitely, while opening Lonzo briefly every few days does not by itself extend anything. In practice, expect to sign in again roughly every two weeks. We would rather describe the mechanism than round it into a friendlier number, because the number is also how long a copy of the credential is any use to anyone who takes it.

Vista del Lago Software LLC sets no server cookies. All of the storage above is client-side (localStorage, IndexedDB, and sessionStorage); none of it is a cookie sent to our servers on each request, and none of it is used for tracking.

We do not store more than we need to run the Service for you.

Third-party functional requests: there are none. The web app fetches every file it needs — code, styles, icons, and the typeface it is set in — from our own servers. No third party receives your IP address when you use the web app. Two separate things have to be true for that, and until 2026-08-18 the reason we gave covered only one of them: your browser is never asked to contact a third party, and the server it does contact is ours rather than a shared cache standing in front of ours. A content-delivery network placed in front of lonzo.ai would receive the address of every visitor to every page, while leaving the reason we used to give perfectly true — your browser would still be asked to contact lonzo.ai and nothing else, and none of the checks in Section 3 would have anything new to read. There is no such network in front of us today. If we put one there it is a sub-processor: it goes on the Sub-processors page, with the thirty days' advance notice that page describes, before it carries a single request.

What used to be here, all three of them. Two of these were disclosed on this page and are no longer made. The third was never disclosed at all, which is the more serious of the two failures, so it is written up here in the same place rather than somewhere less prominent:

  • Your Google profile picture. If you signed in with Google, your Account panel showed the photo from your Google account — and it showed it by handing your browser, or your phone's image loader, the address of a Google server (lh3.googleusercontent.com) and letting it fetch the image directly. Google therefore received your IP address, and the fact that you had Lonzo open, every time that panel appeared. Until 2026-08-18 that request was live, undisclosed, and made by the same build in which this notice said there were no third-party requests of any kind. It is gone: the app no longer produces an off-origin image address for your avatar, and the web app and the mobile app now each refuse to load one even if something else produced it, so this cannot quietly come back through a different screen. What you will see instead: the picture you uploaded to Lonzo, if you uploaded one, and otherwise a plain avatar with your initial. Serving your Google photo without the request would mean copying it onto our own servers first, which we have not built; we would rather show you your initial than send Google a signal you did not ask for. This entry is here because we found it ourselves, in an audit of this page against the code, and telling you late is better than the alternative.
  • Google Fonts delivered the Inter typeface the interface is set in. Until 2026-08-17 your browser fetched it from Google, which meant Google received your IP address every time you opened the web app — including a visit that got no further than the sign-in screen, so before you had an account and before you had agreed to anything. (Pages like this one are plain documents and have never fetched anything from a third party; the font request was the app's.) This notice said we intended to self-host the font and eliminate the call. That is done: the font files are served from our own storage, and we removed the disclosure only after removing the request.
  • The jsDelivr CDN delivered the KaTeX, highlight.js, and Mermaid rendering libraries. Since 2026-08-15 those are committed copies served from our own origin. That change was made for security, not privacy — a script fetched from another origin into the page holding your live session and your device key is an unacceptable amount of trust to place in someone else's infrastructure — but it also meant one fewer third party ever saw your IP address.

We are keeping all three entries rather than deleting them, so that a reader comparing this notice with an earlier copy can see what changed and when, instead of finding a paragraph simply gone.


1A. What the mobile app stores on your device, and why

The mobile app stores more than the web app does, and this notice used to say otherwise. Until 2026-08-17 Section 1's table was the whole of it, with "secure app storage (mobile)" written into two of its rows as though the app kept the same two values and nothing else. It keeps fourteen things, in files rather than in a browser, and the largest of them holds your own content. The reason is the app's design and not an oversight: the mobile app is local-first — it does the work on your device so it opens and stays usable with no network — and something that works offline is something that keeps data on your device.

Three corrections to this list, and one of them is ours to explain twice. Two stores were missing from the table below until 2026-08-24 — the copy of your last screen and the key that protects it. One arrived on 2026-08-28 and was the first the automated check in Section 3 caught by itself: the app gained the file, the check refused the change for putting something on your device that was not on this page, and its row was written as the answer to that refusal rather than after somebody noticed. And two more were missing until version 3.5, on 2026-09-02 — the copy of your waiting writes (outbox-mirror), and the spare sealing key (secretbox_v1.key) — which is a worse failure than the first, because by then a check existed whose whole purpose was to prevent it and it reported the list as complete. Section 3's third bullet says exactly why it could not see them, in place of the sentence it used to carry claiming it could.

None of it is tracking, none of it is shared with anyone, and all of it is in app-private storage, which the operating system does not let other apps read. Eleven of the fourteen are on your device and nowhere else. The other three are also copied into Android's own backup and device-transfer, which means into your own Google account, or onto a new phone when you move one — the copy of your waiting writes (outbox-mirror), the key that protects your saved screen (session-snapshot.key), and the withdrawn-version notice (FabricBuildRetraction). Each of those three rows says so, and says what a copy of it is worth to anyone who has it; Section 5 says what you can and cannot reach when you clear the app's data. What we hold on our servers is covered by the Privacy Policy and the Data Retention & Deletion Policy.

WhatWhereCategoryPurposeRetention / Expiry
Credentials and device keyApp preferences file (FabricShellKeys)Strictly necessaryThe mobile equivalent of the first two rows in Section 1: your session credential, the token that renews it, and this device's identity keypair. Encrypted at rest with AES-256-GCM, normally under a key held by the Android Keystore — in hardware, on any device with a secure element. On a device whose keystore the app cannot use, that key lives in the file in the next row instead, which is weaker; the next row is there to say so rather than let one phrase cover both cases. This file is excluded from Android backup and from device-to-device transfer, so a restored phone re-enrolls rather than cloning your device's identity.The session credential and renewal token are cleared when you sign out. The device keypair deliberately survives sign-out — it is this device's identity, not your session — and goes when you clear app data or uninstall.
The spare sealing keyApp files (secretbox_v1.key)Strictly necessaryThe key that encrypts the row above, and the copy of your last screen further down, in the one case where your device will not hold that key for us. Normally it lives inside the Android Keystore, where nothing — including our own code — can read it out, and this file does not exist at all. Where the app cannot use the keystore (an unusual device, a keystore the operating system has broken or withdrawn) the key has to live somewhere, and it lives here, beside the files it opens. It contains nothing of yours. That is materially weaker than the hardware case, because anyone who can read the app's private files can read both the key and what it protects, and we would rather name the difference than let "encrypted at rest" stand for both. Excluded from Android backup and from device-to-device transfer.Created only if it is ever needed, and then kept: it is this device's sealing key, so it survives signing out for the same reason the device keypair does — deleting it would make the files it protects unreadable rather than protect anything. Removed when you clear app data or uninstall.
Your local-first dataApp files (local-store)Strictly necessaryWhat you write in the app — reminders, replies, edits — is written here first and sent to our servers when the network allows. For anything you write while offline, this is the only copy until it is sent. It also holds this device's own copy of what it authored, which is what lets the app open and work with no signal. Content is encrypted at rest; the list of what the directory holds is not, which is why the whole directory is excluded from Android backup and from device-to-device transfer — that list would otherwise disclose the shape and timing of your mail and calendar to anyone holding a copy of it, and it needs no key to read.Cleared when you sign out, with one deliberate exception: writes that have not yet reached our servers are kept, because deleting them would destroy something you made. They are sent and then dropped the next time the app has both your sign-in and a network. Clearing app data removes them without sending them.
A copy of your waiting writesApp files (outbox-mirror)Strictly necessaryA second copy of only the writes that have not yet reached our servers — the exception named in the row above. It exists for one situation: a phone lost, broken or replaced while something you wrote is still nowhere else. Because the row above is kept out of Android's backup, a restored phone would otherwise come back without those writes, and they are the only copies there are. The content is encrypted at rest as above, and the directory is capped at a small fraction of the store (16 MB) so it cannot grow into a second full copy. This directory is deliberately included in Android backup and in device-to-device transfer — that is the entire reason it exists — so a copy of it can sit in your own Google account, or arrive on a new phone with everything else you moved. What that discloses to whoever holds such a copy, stated rather than glossed: its index (__manifest__) is not encrypted, so it reveals how many writes were waiting, how large each was, and each one's internal identifier — not the content, which stays encrypted. And a restore recovers less than it appears to: writes tied to your account reopen when you sign in, while anything sealed to the old phone's own identity comes back permanently unreadable, by us as much as by anyone.Deliberately survives signing out, for the same reason the un-sent writes themselves do. Each entry is deleted as soon as our servers confirm that write, so in normal use this directory is empty. Removed entirely when you clear app data or uninstall — see Section 5 for the copy that clearing app data cannot reach.
Cached contentApp cache (vault-bytes)Strictly necessaryA cache of content already fetched — the bodies of your mail, events and threads — so that a cold start does not re-download everything and the app works with the radio off. Cached copies of your own content are held in the same encrypted form our servers hold, and the app decrypts them only in memory, when it needs them. Android does not include an app's cache in backup or device transfer, so this never leaves your device.Cleared when you sign out. Android may also reclaim it at any time under storage pressure; losing it costs speed only.
Cached pointersApp cache (pin-heads)Strictly necessaryThe index that names the row above — which item is current, and which version of it. Pointers rather than content: this is the part that lets the app find what it already has without asking us.Cleared when you sign out, and reclaimable by Android at any time, exactly as above. Never included in backup or device transfer.
A cache the app does not useApp cache (compiled-lambdas)Strictly necessaryThe directory is created for a cache of prepared program code, and nothing is written to it on the current build — the part of the app that would fill it never opens it. It is listed because the app creates the directory, not because it holds anything; if that ever changes, this row changes with it.Cleared when you sign out, and reclaimable by Android at any time. Never included in backup or device transfer.
The copy of your last screenApp cache (mount-snapshot)Strictly necessarySo that reopening the app shows your own content straight away instead of a blank screen and a wait, it keeps the last screen it drew for you. This is your content — message subjects, event titles, whatever was on the screen. Encrypted at rest with AES-256-GCM under the same key as the first row, and opened only in memory, while the app is redrawing; if it cannot be opened, the app simply draws the screen from scratch.Cleared when you sign out, and discarded whenever you install a new version of the app. Android may also reclaim it at any time under storage pressure; losing it costs only the wait it exists to remove. Never included in backup or device transfer.
The structure behind that screenApp cache (session-snapshot)Strictly necessaryThe shape of the screen the row above is a picture of, and — this is the part worth being plain about — the content each piece of that screen was displaying. So it holds your content too, not merely a layout. Encrypted at rest with AES-256-GCM under the key in the next row. Until 2026-08-23 it was not encrypted at all, only checked for tampering, and this row said nothing about it; that is fixed and recorded here rather than quietly corrected.Cleared when you sign out, discarded on a new app version, and reclaimable by Android at any time. Never included in backup or device transfer.
What the app has already worked outApp cache (memo)Strictly necessaryResults the app has computed from your content and kept — the screens it has drawn for you and the lists and summaries behind them — so that opening a screen again shows it at once and the app refreshes it in the background rather than making you wait. This is your content, in the same sense as the two rows above: message subjects, event titles, whatever those screens showed. Each result is stored with a record of what it was computed from, so the app can tell whether it is still current before showing it as such, and marks it as a saved copy when it cannot tell. Encrypted at rest with AES-256-GCM and checked for tampering, under the same key as the row below, and opened only in memory. Added 2026-09-13.Cleared when you sign out, discarded on a new app version, and kept within a fixed size — the app drops what you have used least recently when it fills, and Android may reclaim it at any time; losing it costs only the wait it exists to remove. Never included in backup or device transfer.
The key that protects your last screenApp files (session-snapshot.key)Strictly necessaryOne key, and what this file holds is that key encrypted under the same Android Keystore key as the first row; while the app is running it is unsealed in the app's own memory, and it is used for nothing but opening and writing the row above. It contains nothing of yours. This file is included in Android backup and device transfer — we have not excluded it, and this notice said the opposite until 2026-09-02. What a copy of it is worth is nevertheless nothing: it is sealed under a key the Android Keystore holds and will not release to a backup or to a different phone, and the saved screen it opens lives in the app's cache, which Android never backs up. So the saved screen still cannot be opened on another device, or by us — but that is because of how it is sealed and where the screen is kept, not because this file stays put, and the earlier wording claimed the wrong one of those.Deleted when you sign out, and a fresh key is minted the next time the app starts — so that a saved-screen file the sign-out clean-up could not delete stops being readable rather than merely being left behind. Also removed when you clear app data or uninstall. If the device invalidates its own Keystore key — a factory reset does, and some lock-screen changes do — the app mints a new key, the saved screen no longer opens, and the app draws the screen from scratch instead.
Connection certificatesApp files (certs)Strictly necessaryThe certificate files that the app's encrypted connection to our servers reads at connect time. The app also mints a short-lived certificate of its own here at start (ephemeral.crt and its private key), for a listening address that nothing on a phone connects to. It holds nothing of yours, and it is disclosed here because the app writes it, not because it is useful — whether the app should be writing it at all is under review. Excluded from Android backup and from device-to-device transfer.Cleared when you sign out.
The app's own codeApp files (lambdas)Strictly necessaryThe app's program definitions, unpacked from the installed app the first time it connects. It contains no data of yours — it is the same for every install. Excluded from Android backup and from device-to-device transfer, because a fresh install already contains it.Replaced on app update; removed on uninstall.
Whether this version of the app has been withdrawnApp preferences file (FabricBuildRetraction)Strictly necessaryIf we have to withdraw a released version of the app — a defect, a security fix — we publish that on a page anyone can read, and the app checks it at launch and shows you a banner. This file is the app remembering the answer, so a phone with no signal still tells you. It holds one line of that public page, for the version you have installed: the version number, when it was withdrawn, which version replaces it, and the reason we gave. Nothing in it is yours and none of it is secret — every word of it was published to anyone who asked.Kept until you clear app data or uninstall. It deliberately survives signing out, because it is a fact about the app you installed and not about your account: signing out does not make a withdrawn version safe, and a phone that forgot at sign-out could not warn you on a launch with no signal. It is included in Android backup and device transfer for the same reason, which can only ever mean a restored phone warns you sooner.

Why the device key is handled differently on mobile, stated plainly. In the browser the private key is generated inside the browser's own key store and is non-extractable — nothing, including our own code, can read it out. On mobile that is not available to us: the app's encrypted connection to our servers needs the key in a readable form at the moment it connects, so the key cannot be sealed inside the hardware keystore as an unreadable key. What we do instead is encrypt the stored copy under a key that is held by the hardware keystore, and open it in memory only when a connection needs it. That is a weaker guarantee than the browser's and we would rather name the difference than let one sentence cover both.


2. Essential vs. non-essential

Every key the web app writes is strictly necessary — the auth credential, the device identity keypair, the current session identifier, of which there is one per surface: the app's own, and the support panel's (see the Section 1 table), the record of which account a tab is signed into, and the reload counter, which is how a tab left open across one of our releases repairs itself once instead of sitting broken. These are required for login, security, and running the app, and they cannot be turned off without breaking sign-in and the Service. Under ePrivacy rules, strictly-necessary storage does not require consent, which is why this notice informs you rather than asking you.

The account record is part of signing in, not a preference of yours, and the distinction is worth being plain about — because this notice says twice that we keep no preference storage. It is not something you can set and we do not offer it as a choice: it is written when a tab signs in, says only which of your own accounts that was, and is gone when the tab closes. Without it, a tab that reloads cannot tell which of several signed-in accounts it was showing, and coming back to the right one is exactly what staying signed in means when you use more than one account.

The remaining row in that table is there for completeness and does not change that conclusion: tλnk:debug is a diagnostic flag you create — the app never writes a value into it, it does not exist unless you set it yourself, and it sends nothing anywhere. The app deletes it when you sign out, which is the one thing it does to it, and deleting is not storing: the row exists so that verbose logging one person switched on cannot outlive their sign-out onto whoever signs in next on the same browser.

The same conclusion holds for the mobile app's fourteen stores (Section 1A), and it is worth saying why rather than asserting it. Four are credentials, certificates and the two keys that protect the rest, without which the app cannot connect, sign you in, or encrypt anything it keeps. One is the app's own code, one is a directory nothing writes to, and one is a safety notice about the app itself — whether the version you installed has been withdrawn. The caches and the saved screen carry nothing that is not already yours and already on our servers — they are there so the app opens fast and works with the radio off. And the local-first store, with the copy of your waiting writes beside it, is the app working — a local-first app that could not keep your writes on the device would simply fail whenever the network did, and one that discarded the writes it had not yet sent would lose them. None of the fourteen is analytics, advertising, personalization, or a profile: there is nothing there that is kept in order to learn something about you.

We have no advertising, analytics, or performance-tracking storage, and no preference storage — there is no setting of yours that we keep on your device.


3. What we do NOT do

To be explicit:

  • No advertising cookies, pixels, or ad SDKs.

  • No third-party analytics or tracking software embedded in the web or mobile app.

  • No cross-site or cross-app tracking, and no building of advertising profiles.

  • No "sale" or "share" of personal information through cookies or similar technologies, as those terms are used under US state privacy laws (e.g., CCPA/CPRA).

  • No third-party network requests at all, as of 2026-08-17. This used to read "the only third-party request is the functional font request disclosed in Section 1", and that sentence is gone because the request is: the typeface is now served from our own storage (Section 1 records what changed). There is nothing left to disclose in this line — not a tracker, and not a functional asset either.

Because we do not sell or share personal information and do not track you, the opt-out-of-sale/share mechanisms that heavier services carry are not applicable to us.

As of this notice, the web and mobile builds set no CAPTCHA / bot-protection cookies (reCAPTCHA, hCaptcha, Turnstile, or similar), no CDN / WAF / edge-provider tracking cookies, and no crash-reporting or diagnostics SDK that attaches device identifiers (Sentry, Crashlytics, or similar). The web app makes no third-party requests of any kind — see Section 1. No content-delivery network, WAF, or other shared cache stands in front of our origin, so there is no edge provider between you and us to set a cookie or log your address in the first place.

How we know that, and how far the assurance goes. One part of this is now enforced automatically, and the rest is still a human assurance. We would rather tell you which is which than let the stronger half cover for the weaker one.

Enforced. Seven automated checks run on every change to our code, and each fails the change rather than filing a note for someone to read later.

  • Third-party hosts (web app). A check reads the web shell's served code and fails it if any third-party host appears that is not disclosed on this page. It runs in both directions: a host the code reaches and this page does not name fails, and a host this page names and the code no longer reaches fails too — the second is how the jsDelivr disclosure above came to be corrected rather than left standing. So a tracker cannot be added to the web app and leave this section quietly untrue. Since 2026-08-17 the set it is holding the code to is empty, which is a stronger thing to enforce than a list: any third-party host at all now fails the check, and someone has to come back to this page before it can pass.
  • Browser storage keys (web app). Since 2026-08-17 a second check reads the same served code for every use of local storage, session storage and IndexedDB, and holds Section 1's table to what it finds — both ways, and down to the mechanism each row names. A key the app touches and this page does not list fails; a key this page lists and the app no longer touches fails too; a row that says session storage over code using local storage fails, because that is the part of the row that tells you when the value goes away. Section 1's sentences that describe our code rather than our storage are checked as written, and since 2026-09-06 there are two of them about tλnk:debug: that the app never writes a value into it, so a build that started writing it would fail before it shipped, and that the app removes it when you sign out. The second is checked from both ends on purpose — against the code that clears it, and against Section 1's own row — because a build that stopped clearing and a page that stopped saying it clears are different failures, each of which leaves the other looking correct. Until 2026-08-23 the reload guard carried a sentence of the same kind, saying the app only ever cleared it; that check is what stopped the row and the code drifting apart when the app began writing the key again on 2026-08-23, and the row was rewritten in the same change rather than after someone noticed. Assigning a cookie fails; so does reaching for a storage mechanism this notice does not mention at all, such as a service worker's cache. That is only half of what stands behind "no cookies of any kind" — the check reads the app's own code, and a cookie can also be set by our server, in a place this check does not look; the seventh bullet below is the half that closes that, and it exists because on 2026-08-19 server code that set one was written and every check above stayed green.
  • On-device stores (mobile app). A check reads the app's own source for the directories and files it creates, and holds Section 1A's table to what it finds, in both directions: a store the code creates and this page does not name fails the change, and a name this page carries that the code no longer creates fails it too. It is the check that did not exist while Section 1A's contents went undisclosed, and it exists because of that. It has now missed five stores, in two separate ways, and both are worth stating rather than quietly fixing. Until 2026-08-24 the list of names it held the table to was kept by hand, so three stores added to the app after it was written — the two that make up the saved screen, and its key — were missing from the check and from the table at the same time, for the same reason. Searching the source instead of keeping a list fixed that, and then missed two more, which is the failure corrected in version 3.5. The mobile app is a thin shell around a shared engine written in a second programming language, and the check read only the first: a store whose name is declared in the engine was invisible to it, however plainly it was written there, and outbox-mirror is one — it appears nowhere in the part of the app the check was reading. The second miss needs no such excuse: secretbox_v1.key is declared in the language the check was reading, in a file it had already read, and it escaped because the check recognised only certain shapes of declaration and this was not one of them. Since 2026-09-02 the check reads both languages and resolves a name reached indirectly rather than only one written out on the spot, and it requires every name it finds to be either a row in Section 1A or recorded as living inside one. Both misses are named in the check itself, so that the next reader learns what it once could not see.
  • Software the mobile app is built from. Since 2026-08-17 a fourth check reads the Android app's dependency list, its imports, and its permission manifest, and requires every library that ships in the app to be recorded with the reason it is not tracking software. A library added to the app fails the build until someone writes that reason down; a library that names known analytics, advertising, attribution or crash-reporting software fails outright; a third-party package used in the app's code without such a record fails, which is what catches one arriving indirectly; and the app's permission set is held exactly as it is today — network access, network status, and the microphone for voice input — so a new permission, including an advertising identifier, fails until it is checked against this notice. An advertising or analytics entry in the manifest fails too, because those are the entries such an SDK cannot work without.
  • Images the apps are willing to load. Since 2026-08-18 a fifth check holds both apps to refusing an off-origin image address, and it exists because the four checks above all passed while your Google profile picture was being fetched from a Google server. It reads the code that produces your avatar and requires it to drop an http/https address at every step of the chain, and it reads the place each app loads an image and requires the same refusal there. The second half is the one that matters, because an address that arrives in data from our own servers, or is assembled while the app is running, is invisible to a check that can only read what is written in the code — which is exactly how this got through: the first bullet was enforcing an empty set of third-party hosts, truthfully, and the Google address was never written in our code for it to find.
  • Whether anything stands in front of our own servers. Since 2026-08-18 a sixth check reads our deployment configuration and fails it if anything there switches on the content-delivery-network integration our server code already contains, unless this notice and the Sub-processors page have been changed first. It exists because switching that on is a single line in a configuration file, and because the sentence it would falsify — Section 1's — was written with a reason that would have survived it: a fronted origin is still our own hostname, so the five checks above would have had nothing new to read and would all have stayed green. The check also holds in place the written instruction, in the file an operator edits, that the pages move before the cache does.
  • Cookies and browser storage set by our servers, not by the app. Since 2026-08-19 a seventh check reads the server code that builds the pages we serve you — not the app's code, which the second bullet already covers — and fails it if that code sets a cookie of any kind, or writes anything into your browser's storage that Section 1's table does not list. It exists because of a near miss of ours, on the day it was written: a change to how "Continue with Google" finishes a sign-in was written to set one cookie, for five minutes, and it passed every check above. No cookie was ever set on your browser — it was found and removed the same day, and the change had not been published, so nothing above was ever untrue in fact. We are telling you about it anyway, because the honest description of what protected you is that a publication step had not happened yet, and not that anything here caught it. The cookie would not have been a tracking cookie and would have carried nothing beyond the one-time sign-in value now listed in Section 1 — but this page says we set none of any kind, and that promise has to be kept by something better than timing. The second bullet could not have caught it: it reads the app, and this cookie was assembled by a server. This one reads the server, in both directions, exactly as the second reads the app.

Not enforced, and here is the honest boundary. These seven cover what the apps are built from, what they store, one specific thing they can be asked to fetch, and what our repository says about who serves them. The sixth and seventh read the repository, not the running machine: they cannot see a value an operator typed on the server itself, so for those the enforced part is the instruction and the human part is following it. They do not otherwise read what the mobile app sends: the web app's outbound requests are checked (the first bullet), and the mobile app's are not. Until 2026-08-18 this paragraph said that for the phone "no third-party requests" rested on nothing capable of making one being in the build — and that was wrong, plainly: the app ships an image loader, which is precisely such a thing, and it was being handed a Google address. The fifth bullet closes that one path; the general statement for the phone now rests on there being no analytics, advertising or reporting library in the build (the fourth bullet) plus human review of the code that reaches the network, and that is a human assurance, not an enforced one. None of the seven can judge purpose: they guarantee that no third-party host, no browser key, no on-device store and no shipped library arrives unnoticed, not that a disclosed one is harmless or that the reason we give for it is the real one. And they see only what is written literally in the code, so a host or a storage key assembled while the app is running would escape them. That limit is not hypothetical for the on-device check: inside the directories Section 1A names, individual file names are derived from what they hold rather than written down anywhere, so the table covers those as part of the store they sit in and not one by one — which is the right answer, but it is a weaker one than naming each. Nor does that check read every line of code we have: it reads the app and the four parts of the shared engine that touch a device's filesystem, so a store created somewhere neither of those covers would need a person to notice. What it does now guarantee is narrower and worth stating exactly: the count in Section 1A is not typed in. It is the number of stores the check found, so this page cannot say "thirteen" while the code creates fourteen, and the table cannot gain a row that the code does not create. Until 2026-08-17 the boundary sat one step further back — the tracking statements were checked for the web app only, and the mobile half was a human review of the source — and that is the same gap that once let the mobile app's five on-device stores (Section 1A) go undisclosed under a sentence claiming the browser list was complete for both.

What protects you beyond either is structural rather than procedural: we have no advertising business and no analytics vendor, so there is no commercial pressure toward the thing this section rules out. If any such tool is ever added for a non-essential purpose — including first-party analytics or crash reporting that uses device identifiers for anything beyond strictly-necessary security and reliability — we will update this notice and add consent controls before it ships (see Sections 4 and 7).


4. Do we need a consent banner?

Because we use only strictly-necessary storage and no advertising or tracking technology, EU/UK ePrivacy rules do not require a blocking consent banner — this informational notice is sufficient. We have deliberately chosen not to deploy consent-management infrastructure we do not need.

This conclusion holds only while our storage remains strictly necessary. If any non-essential technology (analytics, advertising, or crash reporting keyed to device identifiers) is later introduced, a consent banner becomes required in the EU and UK, and we will re-review this notice and its classifications before that technology ships.


5. How to control local storage

You can clear this storage at any time:

  • Web: clear your browser's site data / IndexedDB for Lonzo, or use your browser's privacy controls. Doing so removes the local keypair and logs you out — you can simply sign in again to generate a fresh key.
  • Mobile — signing out. Signing out of the app clears the credentials, deletes the read cache and the staged connection certificates, and asks the app to forget the local-first store for the account signing out. Five things are deliberately kept, and each row above says which and why: the writes that had not yet reached our servers and the second copy of them, because on a device that is offline they are the only copies and discarding them would destroy something you made — they are sent, and then dropped, the next time the app has both your sign-in and a network; this device's identity keypair and its sealing key, which are facts about the phone rather than about your account; and the note recording whether the version of the app you installed has been withdrawn, which stays true after you sign out. Nothing kept is your content except the un-sent writes themselves.
  • Mobile — clearing app data. Clearing the app's data through your device's operating-system settings removes everything in Section 1A from that phone — all fourteen, including any un-sent writes, both sealing keys, and this device's identity key. It will log you out, and the app enrolls a fresh device identity next time you open it. This is the option to use on a phone you are handing on or selling.
  • What clearing app data cannot reach, because it is no longer on the phone. Three of the fourteen are also copied into Android's own backup and device-transfer, as their rows say: the copy of your waiting writes, the key that protects your saved screen, and the withdrawn-version notice. A copy already taken sits in your own Google account, not with us, and nothing the app does can delete it — clearing app data cannot reach it and neither can we. Android's own settings are where that lives: on most phones, Settings → Google → Backup, which lets you see the backup for a device and delete it, and turn backup off so no further copy is made. Two of those three are worth almost nothing to whoever holds a copy (the key opens nothing without the phone's own hardware key, and the withdrawn-version notice was published to everyone); the copy of your waiting writes is the one that matters, and its row says exactly what it discloses. We would rather point you at the right setting than let "removes everything" stand for something it does not cover.

Clearing storage does not delete your account or your data on our servers; it only removes what is stored on your device. To delete the account itself, see Delete your Lonzo account.

Per-browser controls. Every major browser lets you view, block, and delete cookies and site data from its settings. For step-by-step instructions, see your browser's own help pages — for example, Google Chrome, Apple Safari, Mozilla Firefox, and Microsoft Edge each publish a "clear cookies and site data" / "manage cookies" help article in their respective support centers.


6. Do Not Track and Global Privacy Control

Because we do not track you across sites or apps and do not sell or share personal information, there is nothing for a Do Not Track (DNT) or Global Privacy Control (GPC) signal to opt out of. We honor such signals to the extent applicable law requires, but they do not change our behavior — which is already tracking-free.


7. Changes to this notice

We may update this notice from time to time. The version and date at the top will change, and we will flag material changes. If we ever introduce a new non-essential technology, we will update this notice and put appropriate consent controls in place first.


8. Contact

Questions about this notice: privacy@lonzo.ai · Vista del Lago Software LLC


All legal documents · Help · Lonzo home