The Play Console Data safety form said "App doesn't collect or share data" and "Data isn't encrypted". Both are wrong, and the pair contradicts itself: with nothing collected there is no encryption answer to give. The error was reading "collect" as "the developer receives it". Google defines it as transmitting data off the user's device, including by any SDK the app controls - and PRIVACY.md already lists six categories that do. An app requesting seven android.permission.health.* permissions while its public label reads "doesn't collect or share data" is the same kind of contradiction that got the Health Connect declaration rejected twice, and Google cross-checks the two forms against each other. The trap worth writing down: the user-initiated transfer and service provider carve-outs are exceptions to *sharing*, not to *collection*. Publishing a post is a transfer the user expects, so it need not be declared as sharing - but it is still collection. Two exemptions Amethyst genuinely earns and should claim: private DMs under the end-to-end encryption exception (NIP-17/NIP-44), and the My Fitness dashboard under the on-device-only exception, since it computes locally and transmits nothing. Only a workout the user publishes is collected. Verified against the code rather than assumed: no analytics, crash reporting, advertising or attribution SDK exists in any module, so the Analytics and Advertising purposes are never ticked; location is ACCESS_COARSE_LOCATION only; audio covers voice notes and NIP-53 rooms. Two items are left as explicit decisions rather than answered here, because neither is a form-filling choice: - Whether the push notification proxy processes on the developer's behalf (service provider, not shared) or is an independent operator (shared), which decides the Device or other IDs row. - Whether to narrow network_security_config.xml to loopback and .onion so "encrypted in transit" can truthfully be Yes. Today the global cleartextTrafficPermitted="true" keeps user-configured ws:// relays working, so the claim cannot be made unconditionally - but leaving it means the public label reads "Data isn't encrypted" beside a health permission request. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPShPiTfg16yesupcLgyqf
7.9 KiB
Play Console — Data safety form
Source text for the Data safety form (Play Console → Monitor and improve → Policy and
programs → App content → Data safety). Keep this file and the form in sync, the same way
health-connect-play-declaration.md tracks the Health apps declaration. Google cross-checks the
two against each other and against PRIVACY.md; a disagreement between them is what a reviewer
finds first.
Why this file exists
The form previously said "App doesn't collect or share data" and "Data isn't encrypted". Both are wrong, and the pair is self-contradictory — if nothing is collected there is no encryption answer to give.
The error came from reading "collect" as "the developer receives it". Google does not define it that way:
"Collect" means transmitting data from your app off a user's device. This includes data transmitted by libraries/SDKs and webviews controlled by your app.
Amethyst has no server, and that remains true and worth saying in the listing — but the test is
whether data leaves the phone, not who receives it. PRIVACY.md § "Data sent off-device"
already lists six categories that do.
The trap: Google's user-initiated transfer and service provider carve-outs are exceptions to sharing, not to collection. A user tapping Post is a transfer they expect, so it need not be declared as sharing — but it is still collection and must be declared.
Two exemptions Amethyst genuinely earns
- Private DMs — end-to-end encryption. "User data that is sent off device, but that is unreadable by you or anyone other than the sender and recipient as a result of end-to-end encryption does not need to be disclosed." NIP-17/NIP-44 qualifies. Do not declare DM contents.
- The My Fitness dashboard — on-device only. "User data accessed by your app that is only processed locally on the user's device and not sent off device does not need to be disclosed." The dashboard reads Health Connect, computes on device, displays, and transmits nothing. Only a workout the user publishes is collected.
1. Overall questions
| Question | Answer |
|---|---|
| Does your app collect or share any of the required user data types? | Yes |
| Is all of the user data collected by your app encrypted in transit? | See § 4 — decide before submitting |
| Do you provide a way for users to request that their data is deleted? | Yes — see § 5 |
2. Data types — collected
Everything below is optional (the user chooses to post, to upload, to enable push, to connect
Health Connect) and its purpose is App functionality only. Amethyst ships no analytics, crash
reporting, advertising or attribution SDK — verified: no Crashlytics, Firebase Analytics, AppsFlyer,
Adjust, Sentry or Bugsnag anywhere in libs.versions.toml or any module's build.gradle.kts. So
never tick Analytics, Advertising or marketing, Fraud prevention, or Personalization.
| Category | Type | Collected | Shared | Why |
|---|---|---|---|---|
| Location | Approximate location | Yes | No | A geohash the user attaches to a post or a location chat. ACCESS_COARSE_LOCATION only — never precise. |
| Personal info | Name | Yes | No | Display name in the user's published kind-0 profile, if they set one. |
| Personal info | User IDs | Yes | No | The Nostr public key accompanies every published event and the push registration. |
| Personal info | Other info | Yes | No | Profile bio, picture and website, if set. |
| Financial info | Other financial info | Yes | No | Zap amounts appear in published zap events; NWC relays payment instructions to the user's own wallet. |
| Health and fitness | Health info | Yes | No | Heart rate, only in a workout the user chooses to publish. |
| Health and fitness | Fitness info | Yes | No | Exercise, distance, steps, calories, elevation, only in a published workout. |
| Messages | Other in-app messages | Yes | No | Public posts, replies, articles. Private DMs are excluded — E2EE exemption. |
| Photos and videos | Photos / Videos | Yes | No | Uploads to the media server the user selects. |
| Audio | Voice or sound recordings | Yes | No | Voice notes, and speaking in a NIP-53 audio room. |
| Calendar | Calendar events | Yes | No | NIP-52 calendar events the user publishes. |
| Device or other IDs | Device or other IDs | Yes | See § 3 | (Play build, push enabled) FCM registration token. |
3. Data types — not collected
Contacts (follow lists are Nostr public keys, not device contacts) · Web browsing history · App info and performance (no crash or analytics SDK) · Files and docs (covered by photos, videos and audio) · Personal info → Email address · Financial info → payment info or purchase history · Precise location · App activity.
The one item needing your decision
The push token path is the only place a third party plausibly receives data outside a
user-initiated publish: PRIVACY.md says the token, public key and a preferred relay are
"registered with Google Firebase Cloud Messaging so a notification proxy can wake the app."
- If that proxy processes the data on your behalf, the service provider exception applies → Shared: No.
- If it is an independent operator, it is a third party → Shared: Yes for Device or other IDs.
Decide this from how the proxy is actually operated. Everything else in the table is No because publishing to relays is a user-initiated transfer the user reasonably expects.
This is the judgment call in the whole form. Answering "shared with third parties" for Health and fitness would make the public label read that Amethyst shares health data with third parties — which is precisely the prohibited use the Health Connect policy names, and would undercut the declaration. "Collected, not shared" is both accurate under Google's definition and the answer to defend. Be ready to defend it: the user takes a deliberate action, sees the post, and confirms it.
4. Encrypted in transit — resolve before submitting
Relays are wss://, media is HTTPS, DMs are NIP-44. But amethyst/src/main/res/xml/network_security_config.xml
sets cleartextTrafficPermitted="true" on the global base-config so user-configured ws://
relays keep working. Google allows "yes" only when encryption covers all collected data, so as
the app stands today that cannot be claimed unconditionally.
Two honest ways forward:
- Narrow the config to loopback and
.oniononly, and drop the global permit. Loopback never leaves the device and.onionis encrypted by Tor, so "encrypted in transit" becomes truthfully Yes — and it is a real security improvement. Cost: a user with a plainws://relay breaks. - Leave it and answer No. Accurate, but the public label then reads "Data isn't encrypted" next to a health-permission request — the same contradiction that has already cost two submissions.
Option 1 is the better outcome. It is a behaviour change for ws:// relay users, so it is a
maintainer's decision, not a form-filling one.
5. Data deletion
The developer runs no server and holds nothing, so there is no developer-held copy to request deletion of. Users can:
- wipe everything local by clearing app storage or uninstalling (
PRIVACY.md§ "Data stored on your device"); - delete an account's data in-app;
- request deletion of published events with NIP-09 — noting, as
PRIVACY.mdalready says, that relays may not honour it and public content should be assumed permanent.
Say this plainly rather than claiming deletion guarantees the protocol cannot give.
6. Keep these three in sync
The Health apps declaration, this form, and PRIVACY.md are one statement split across three
places. A reviewer reads all three. Before any resubmission, check that each data type here also
appears in PRIVACY.md, and that nothing here contradicts
health-connect-play-declaration.md § 4.