Draft. This document is being finalised before Breza launches and may change.
Breza Privacy Policy
Last updated: [effective date]
Applies to: the Breza mobile app (Android and iOS), package
com.erikp.breza.
Who we are
Breza is made by an independent developer in Slovenia, who is the data controller for everything described here ("we", "us").
- Email: support@breza-app.com
[verify] GDPR Art. 13 asks for the controller's identity, and Slovenia's e-commerce act (ZEPT art. 5) asks a business for its name and seat. Before selling subscriptions, add the registered business name and seat (the stores will display the seller's name anyway).
If you have a question about your data, that email reaches a person. [verify] Add an EU or UK representative here if one is required for your business. That depends on where you are established, and it is a question for your lawyer.
The short version
- Everything you record in Breza stays on your phone by default. Trackers, resets, check-ins, cravings, journal entries, milestones, settings, and companion conversations all live in a database on the device. If you turn on Plus's cloud backup, an encrypted copy of that database also goes to our server — see (d) below.
- There is no account. You never give us an email, a name, or a password.
- Four things can leave your phone, and only four: your messages to the AI companion (after you say yes), anonymous app-usage counts (which you can switch off), a referral code with an anonymous billing id (only if you use the referral programme), and — only if you turn on Plus's cloud backup — an encrypted copy of your data that we cannot read.
- We never send what you write in a form we can read. Not your journal, not your check-in notes, not your craving notes. The one exception is the companion, which needs your chat messages to reply, and you turn that on yourself. Cloud backup also copies this content off your phone if you turn it on, but scrambled by a passphrase only you know, so we still cannot read it.
- You can export everything, or erase everything, at any time, from inside the app.
What stays on your device
Breza stores your data in a local SQLite database on the phone. Nothing leaves your device unencrypted, and nothing leaves at all unless you turn something on yourself. That database holds:
- Trackers. What you are stepping away from, when you started, and the cost figures you entered.
- Resets. Each time you logged a slip, with the length of the run before it. Nothing is deleted when you reset.
- Check-ins. Your mood rating and any note you added.
- Cravings. Intensity, the triggers you tagged, what helped, and any note.
- Journal entries. Whatever you wrote.
- Milestones. Which days you reached.
- Settings. Your pathway, your display name if you entered one, reminder times, language, your consent choices, and similar preferences.
- Companion conversations. Every message in every chat, stored on the phone.
None of that is uploaded anywhere unencrypted, and by default it is not uploaded at all. If you turn on Plus's cloud backup, an encrypted copy is stored on our server — see (d) below — and we hold ciphertext only; we still cannot read it. If you don't turn that on, and you lose the phone without making a local backup file, that data is gone, including for us.
Reminders are local notifications scheduled by the phone. They do not involve a server and we do not know whether you opened one.
The four things that can leave your device
(a) The AI companion, only after you say yes
The companion is off until you read a consent screen and tap "I understand". Before that, nothing is sent. The consent screen lists what is sent, and this is the same list.
When you send a message, the app sends this to our conversation service:
- The recent conversation. Up to the last 12 turns, what you typed and what the companion replied. Each turn is capped at 2,000 characters.
- Your pathway id, for example
alcohol. - A crisis flag. A single yes or no, decided on your phone by a word list, never by the model.
- Up to five short snippets from your own logs. These are quotes from things you wrote, for example what helped you in a past craving, clipped to roughly 300 characters each. They are picked on the phone by a plain keyword match, with no model involved.
- Up to six context lines, built on your phone. In practice: which day of your current run you are on, your longest run, whether you logged a reset in the last seven days (the fact only, never any detail), up to two of the reasons you wrote down when you started, the trigger label you tag most often, and whether your recent check-ins read as low, up and down, or fairly steady.
- Your display name, only if you switched that on. It is off by default and the app works the same without it.
- The companion you chose, as an id.
- The app's own greeting text, so the model does not greet you twice.
What is not sent: your full journal, your check-in notes, your conversation history beyond those recent turns, your database, and your name unless you turned that on.
What our server does. The service is a Cloudflare Worker that passes your message to an AI provider and streams the reply back. It stores:
- a hash of a random access token, minted for your install the first time you chat, so the service knows the request came from a Breza install;
- rate-limit counters, keyed by that token hash and by a hash of the IP address, so one install cannot flood the service.
That is all. The Worker keeps no copy of your messages, writes no message content to logs, has no account for you, and holds no user id. The token is random and is tied to nothing about you. Withdrawing consent in More deletes that token from the phone.
The AI provider. The reply is generated by [LLM provider], acting as our processor. The Worker is provider-configurable, so name the provider you actually deploy with, link their policy, and put a data processing agreement in place. [verify] Confirm the provider's retention and training terms, and state them here. Do not assert "they do not train on it" until you have that in writing.
Rate limits. [verify] Rate-limit counters currently have a 24-hour or 60-second expiry in KV depending on the counter; confirm the deployed values before publishing a retention figure for them.
(b) Analytics: on by default, disclosed, one switch away
[verify] Sections (b), (c) and (d) describe the analytics, referral, and cloud-backup features as built in
lib/analytics/,lib/referral/, andlib/backup/against the contracts inshared/analytics.ts,shared/referral.ts, andshared/backup.ts. Publish this policy with the release that ships each, not before. A policy that describes collection you are not doing is as wrong as one that hides collection you are.
Breza counts interactions so we can see where people get stuck. We never send what you write.
- New installs have this on, with the disclosure on the welcome screen.
- Installs that existed before this feature shipped default to off, and see a one-time notice explaining the change.
- The switch is in More → Privacy. When it is off, nothing is recorded and nothing is queued for later.
What each event is sent with: a random install id (a UUID generated on first launch, tied to nothing about you and regenerated if you erase your data), your platform, the app version, and, for some events, which experiment group your install landed in. No advertising identifier is used or collected. No IP-based profile is built.
The complete list of events. This is every event the app can send. Nothing outside this list is accepted by the server.
| Event | What it means |
|---|---|
app_installed |
First launch after install. Carries platform, app version, and language. |
app_opened |
You opened the app. Carries only a coarse bucket of how long since install (0, 1, 2-6, 7-29, 30+), at most once every 30 minutes. |
onboarding_step |
You reached a step of the setup wizard. Carries the step id and its position. |
onboarding_completed |
Setup finished. Carries the pathway, and yes or no for whether you entered a cost, entered a name, and turned on a reminder. |
first_action |
The first time you used one of check-in, craving log, journal, pledge, or an urge tool. Carries which of the five, never the content. |
paywall_viewed |
The Plus screen was shown. Carries where you came from. |
paywall_dismissed |
You closed the Plus screen. Carries where you came from. |
trial_started |
A free trial began. Carries monthly or annual. |
purchase_completed |
A subscription was bought without a trial. Carries monthly or annual. |
referral_shared |
You shared your invite code. |
referral_code_entered |
You submitted a code someone gave you. |
referral_redeemed |
A code was successfully redeemed. Carries whether you were the referrer or the friend. |
Every value in that table is a fixed choice, a number, or a yes or no. The event format has no free-text field at all, which is enforced by the code both the app and the server compile against, so an event physically cannot carry something you wrote. Nothing is recorded on the crisis screen, the crisis interstitial, or the reset flow.
We do not use analytics for advertising, we do not sell this data, and we do not share it with a third-party analytics company. It goes to our own Cloudflare service.
(c) Referral
If you use the invite feature, the app sends:
- your invite code, and
- an anonymous billing id generated by RevenueCat (it looks like
$RCAnonymousID:followed by random characters).
Nothing about your recovery is sent. No name, no streak, no notes. The server stores codes, the anonymous id that owns each code, and which anonymous ids have redeemed. It uses those ids to ask RevenueCat to grant a promotional month of Plus to both sides.
(d) Cloud backup (optional, Plus)
If you turn on cloud backup (Breza Plus, off by default), the app encrypts your data on your phone — the same encrypted envelope you already get from More → Your data → Backup, described under Security below — and sends that encrypted copy to our server so a new phone can restore it.
Where it lives. Cloudflare R2, in [processing region]. [verify] Fill in
the real bucket region once the bucket is created; see docs/SHIP.md.
Who can read it. Only someone who knows your passphrase. We cannot. The server stores your ciphertext under an opaque handle computed from your passphrase on your phone, so restoring on a new device is just typing the same passphrase — there is still no account. The server has no copy of your passphrase, no encryption key, and no way to open what it stores.
Deleting it. Turning cloud backup off deletes the stored copy, and so does erasing your data (More → Your data → Erase). We cannot delete a backup "by request" the way a support inbox usually can: without your passphrase we cannot tell which stored blob is yours, so there is no "email us to delete it" path. The two in-app actions above are the only way to remove it.
If a backup is never touched again. [verify] We intend to delete a cloud
backup that has gone 12 months with no new upload, using a Cloudflare R2
lifecycle rule the developer configures as an infrastructure step (tracked in
docs/SHIP.md). Until that rule is in place, an abandoned backup is not
automatically deleted, and this paragraph will be corrected to state the rule
as actually configured once it is.
If you forget your passphrase. Nobody can recover it and nobody can open the backup without it — not us, not the app, and there is no password reset, because there is no account to reset it on. This is the same trade-off as a local backup file, and it is deliberate.
Where the passphrase lives. Your passphrase lives only in your phone's secure keychain, never in the app's regular database, and it is never sent anywhere. What the app sends instead is a value derived from it (so a new phone with the same passphrase finds the same backup) and a small access token the server issues the first time you back up; that token stays in the keychain too.
Cloud backup requires an active Breza Plus subscription to turn on. See the Terms for what happens to an existing backup if Plus later lapses.
The website and waitlist
The website, breza-app.com, sets no cookies and runs no analytics or third-party scripts. Cloudflare, which hosts it, processes the connection (including your IP address) to deliver the page and stop abuse.
If you join the waitlist we store the email address you type, the version of the sentence that was under the form, and when. We use it for one thing: an email on launch day with the App Store and Google Play links. If the address is a Google account, we may also invite you to test the Android app early, by adding it to Google Play's tester list, which shares it with Google so the invite can reach you. Your IP address is used, hashed, to rate-limit sign-ups and is not stored with the email. The waitlist is separate from the app: nothing links it to an install or to anything you record.
Legal basis: your consent (GDPR Art. 6(1)(a)), which you can withdraw at any time by writing to support@breza-app.com; we then delete the address. We delete the whole waitlist once launch emails have gone out and the beta has ended. [verify] Set the date you will actually purge it.
Purchases
Breza Plus is sold through the app stores. Payment is processed by Apple or Google. We never see your card, your billing address, or your store account.
Subscriptions are managed with RevenueCat, which sits between the app and the stores. The app configures RevenueCat anonymously: we never pass it a name, an email, or an account id. RevenueCat receives the anonymous id it generates itself, your purchase and renewal events from the store, and the standard device and country information the store transaction carries. [verify] Confirm the exact field list against RevenueCat's current documentation before publishing.
- RevenueCat privacy policy: [RevenueCat policy URL]
- Apple privacy policy: [Apple policy URL]
- Google privacy policy: [Google policy URL]
Crisis resources
The crisis screen links to third-party directories, currently Find a Helpline and Befrienders Worldwide. They are links, nothing more. We send nothing to them. When you tap one, your browser opens their site, and from that point their privacy policy applies, not ours. We do not know that you tapped it, and no analytics event is recorded on that screen.
Children
Breza is not intended for anyone under 18 and we do not knowingly collect data from children. If you believe a child has used the app and sent us something, write to support@breza-app.com and we will delete it.
[verify] The app has no age gate today. Make sure the age statement here matches the content rating and target-audience answers in both stores.
Your rights, as buttons in the app
- Export. More → Your data → Export writes every table to a JSON file and hands it to the share sheet. It is complete: every row, every id, nothing held back.
- Encrypted backup. More → Your data → Backup writes the same content to an encrypted file you keep. It is a file. It is not uploaded anywhere.
- Erase. More → Your data → Erase deletes every row in every table on the device: trackers, resets, check-ins, cravings, triggers, journal, milestones, settings, and companion conversations. It is confirmed twice, it is immediate, and it cannot be undone. It also clears your install id, so analytics starts from a new random id if it is on.
- Analytics switch. More → Privacy. Off means nothing is recorded.
- Withdraw companion consent. More → Privacy → Withdraw companion consent. The app stops sending anything to the conversation service and asks again before any future chat. The access token is deleted from the phone. Conversations already on your phone stay on your phone.
Because there is no account, we usually cannot find "your" data on a server to give you a copy of, and that is the point. For analytics rows, the only handle is your install id, so a request has to include it if you want those rows found. [verify] Decide with your lawyer how you want to handle a request that names an install id, and whether you want to offer it at all. There is no route for this in the app today.
How long we keep things
- Data on your device: until you erase it or uninstall the app. We have no copy and no ability to delete it for you.
- Cloud backup (if you turn it on): until you delete it, by turning the
feature off or erasing your data. [verify] We also intend to delete a
backup that has had no new upload in 12 months, once the R2 lifecycle rule
in
docs/SHIP.mdis configured; see (d) above. - Analytics rows: [analytics retention period]. We recommend 13 months, which is enough for year-over-year comparison and is a common ceiling under EU guidance. [verify] Set this in the deployed database and then state it here honestly; there is no automatic deletion job in the code today.
- Referral rows: for as long as the code exists, so a code cannot be redeemed twice. [verify] Decide whether to expire codes and their rows.
- Companion access tokens and rate-limit counters: the counters expire automatically within a day. [verify] Confirm whether registration markers are given a TTL before publishing.
- Purchase records: held by Apple, Google, and RevenueCat under their own policies.
Security
- Your data sits in the app's private storage, protected by the operating system's app sandbox and by your device lock.
- Backups are encrypted before they are written, using scrypt to turn your passphrase into a key and XChaCha20-Poly1305 to encrypt the contents. We cannot recover your passphrase and we cannot open your backup. If you lose the passphrase, the backup is unreadable, by anyone, forever. That is deliberate, and it is true of a local backup file and of cloud backup (d) alike — the encryption is identical either way.
- Everything that leaves the device goes over HTTPS.
- The AI provider's key and the RevenueCat secret key live only on the server, never in the app.
No system is perfect, and we will not claim otherwise. [verify] Add your breach notification commitment here once your lawyer has advised on the applicable deadline.
International transfers
Our service runs on Cloudflare Workers, which executes at the edge location nearest the request, and stores data in [processing region]. That means data may be processed outside the country you are in.
[verify] Fill in the real region for the D1 database and KV namespace once deployed, name the transfer mechanism you rely on (for example the EU standard contractual clauses), and list the AI provider's processing regions. This section cannot be published with a placeholder in it.
If you are in the EU or the UK
Under the GDPR and UK GDPR you have the right to access, correct, delete, port, restrict, and object to processing of your personal data, and to complain to your data protection authority.
For almost everything, those rights are already in your hands: the data is on your device and the app gives you export and erase.
Lawful basis, flagged for legal review and not settled.
- The companion runs on your consent, given on a screen that lists exactly what is sent and is refusable without losing the rest of the app.
- Analytics is currently designed as opt-out, on by default with disclosure
and a visible switch. That posture assumes a legitimate interest basis.
This needs a lawyer's sign-off before launching in the EU. ePrivacy rules
generally want consent before non-essential information is stored on or read
from a device, whether or not the data is anonymous, and Breza is a
health-adjacent app, which raises the bar rather than lowering it. See
docs/BACKEND_OPTIONS.md§7. "Everyone else does it" is not a defence. - If the advice is that consent is required, the fix is a switch that starts off for EU users, not a change to this document.
Note that the on-device content is health-adjacent and would be special category data if it were ever processed by us. It is not, and that is a deliberate design choice, not an accident.
Controller: the developer of Breza (see "Who we are"), support@breza-app.com.
If you are in California
We do not sell your personal information and we do not share it for cross-context behavioural advertising. We have never done so.
In the last 12 months the only categories we have collected are identifiers (a random install id, an anonymous billing id) and internet activity (the interaction events listed above). We collect them to operate and improve the app. We do not collect your precise location, your contacts, or biometric data.
You have the right to know, delete, correct, and opt out. The app's erase button is the fastest route for on-device data. For anything else, write to support@breza-app.com. We will not discriminate against you for exercising a right.
[verify] Confirm with your lawyer whether your business meets the CCPA/CPRA thresholds at all. If it does not, you may still keep this section, but the wording should be checked.
Store commitments
- Google Play Health apps policy. Breza is a health and wellness app. We do not use health data for advertising, we do not sell it, and we do not share it with data brokers. What you record stays on your device.
- Apple App Store Review Guideline 5.1.1. We do not require an account, we request only what a feature actually needs, and we do not use health data for advertising or marketing.
- No advertising identifier. The app does not read the Android Advertising ID or Apple's IDFA, contains no advertising SDK, no crash reporter, and no third-party analytics SDK.
- Data Safety. Our Play Data Safety declaration says app interactions and a device id are collected, optional, not shared, encrypted in transit, and deletable in the app. [verify] Keep this section and the console form in sync whenever an event is added.
Changes to this policy
If we change what leaves your device, we will say so in the app before it happens, not only here. For anything that expands what is sent, existing users will be asked rather than switched over quietly. The "last updated" date at the top always reflects the current version.