Cookie & Local Storage Notice
Effective 2026-08-24 · Version 3.2This 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 seven 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:
| Key | Where | Category | Purpose | Retention / Expiry |
|---|---|---|---|---|
tλnk:auth:credentials | Browser localStorage | Strictly necessary | Your session/auth credential — keeps you signed in without re-entering credentials each time. | Cleared on logout. 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:claim | Browser localStorage | Strictly necessary | A 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:keys | Browser IndexedDB | Strictly necessary | Your 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_urn | Browser sessionStorage | Strictly necessary | The identifier of your current session in the app. | Cleared on tab close. |
tλnk:shell:session_urn:support-panel | Browser sessionStorage | Strictly necessary | The 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:reload:attempts | Browser sessionStorage | Strictly necessary | A 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:debug | Browser localStorage | Diagnostic, off unless you turn it on | A troubleshooting flag. The app only reads it and never writes it — it exists so that a developer, or you at our request, can switch on verbose console logging by setting it by hand. If you have not set it, it does not exist. It enables logging to your own browser console only; nothing is sent to us. | Until you remove 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 seven 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. Two of the seven were themselves missing from the table below until 2026-08-24 — the copy of your last screen, and the key that protects it — and Section 3 says why the check that reads the app's own source did not catch them.
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. Everything below is on your device only; what we hold on our servers is covered by the Privacy Policy and the Data Retention & Deletion Policy.
| What | Where | Category | Purpose | Retention / Expiry |
|---|---|---|---|---|
| Credentials and device key | App preferences file (FabricShellKeys) | Strictly necessary | The 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 under a key held by the Android Keystore — in hardware, on any device with a secure element — and 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. |
| Your local-first data | App files (local-store) | Strictly necessary | What 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. | 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. |
| Read cache | App cache (vault-bytes, pin-heads) | Strictly necessary | A cache of content and pointers already fetched, so a cold start does not re-download everything and works with the radio off. Cached copies of your own content are held in the same encrypted form our servers hold — the app decrypts them only in memory, when it needs them. | Cleared when you sign out. Android may also reclaim it at any time under storage pressure; losing it costs speed only. A third directory (compiled-lambdas) is configured but nothing is written to it on the current build. |
| What was on your screen last time | App cache (mount-snapshot, session-snapshot) | Strictly necessary | So that reopening the app shows your own content straight away instead of a blank screen and a wait, it keeps a copy of the last screen it drew for you and of the structure behind that screen. This is your content — message subjects, event titles, whatever was on the screen. Both are encrypted at rest with AES-256-GCM — the copy of the screen under the same Android Keystore key as the first row (in hardware, on any device with a secure element), and the structure behind it under the key in the row below — and the app opens either of them only in memory, while it is redrawing. If it cannot open one, it simply draws the screen from scratch instead. | Cleared when you sign out. Android may also reclaim it at any time under storage pressure; losing it costs only the wait it exists to remove. |
| The key that protects your last screen | App files (session-snapshot.key) | Strictly necessary | One 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, and it never leaves your device — so the saved screen cannot be opened on any other device, or by us. | 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 certificates | App files (certs) | Strictly necessary | The certificate files that the app's encrypted connection to our servers reads at connect time. | Cleared when you sign out. |
| The app's own code | App files (lambdas) | Strictly necessary | The 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. | Replaced on app update; removed on uninstall. |
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), 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 remaining row in that table is there for completeness and does not change that conclusion: tλnk:debug is a diagnostic flag the app only ever reads — it does not exist unless you create it yourself, and it sends nothing anywhere.
The same conclusion holds for the mobile app's seven stores (Section 1A), and it is worth saying why rather than asserting it. Two are credentials and certificates, without which the app cannot connect or sign you in, and a third is only the key that protects the saved screen. One is the app's own code. The read cache 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 is the app working — a local-first app that could not keep your writes on the device would simply fail whenever the network did. None of the seven 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 sentence that describes our code rather than our storage — that
tλnk:debugis only ever read — is checked as written, so a build that started writing it would fail before it shipped. Until this version 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 Android app's own source for the directories and files it creates, and holds Section 1A's table to that list in both directions. It is the check that did not exist while Section 1A's contents went undisclosed, and it exists because of that. It missed three stores anyway, and that is 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. Since then the check searches the app's source for the directories and files it names, so a store added the ordinary way and left out of Section 1A now fails on its own.
- 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/httpsaddress 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 at runtime would escape them. 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. One thing is deliberately kept: writes that had not yet reached our servers, because on a device that is offline they are the only copy 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.
- Mobile — clearing app data. Clearing the app's data through your device's operating-system settings removes everything in Section 1A, including any un-sent writes 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.
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