Data safety and privacy
The Play Data safety declaration and the iOS privacy answers, derived from what the app actually transmits — every data type, where it goes, whether it is shared, and what account deletion does and does not remove.
Google Play requires a Data safety declaration and Apple requires App Privacy answers. Both are made by you, about your deployment, and both must match what the binary actually does — a declaration that understates collection is treated as a policy violation rather than a mistake.
This page is the raw material, traced from the app's own source. It is not a substitute for reading your own configuration: several answers below depend on which addons you have licensed.
Encryption in transit is yes only while baseUrl is https://. The app
does not validate the scheme, and nothing stops a configuration pointing at
http://. Data retention depends on which addons you run — the table's
deletion column describes the platform's behaviour, not your legal obligations.
What the app collects
Everything below goes to your own backend unless the Shared column says otherwise. Nothing is sent to an analytics, advertising or crash-reporting service, because the app bundles none — no Firebase Analytics, no Crashlytics, no Sentry, no ad SDK.
| Play data type | Collected | Required | Purpose | Shared | Deleted with the account |
|---|---|---|---|---|---|
| Personal info — Name | Yes | Yes | Account management | No | Yes, nulled |
| Personal info — Email | Yes | Yes | Account management, security | No | Yes — tombstoned to deleted-{id}@deleted.invalid, and the address is released for re-registration |
| Personal info — User IDs | Yes | Yes | Account management, fraud prevention | No | Username nulled; sign-in provider links hard-deleted |
| Personal info — Phone | Yes | No | Account management, 2FA | No | Yes, nulled |
| Personal info — Address | Yes | Per flow | Fulfilment (store), legal compliance (KYC) | No | Order records retained; KYC address retained |
| Financial — Payment info | Yes | No | Payments | Yes — Stripe | Not held by you |
| Financial — Other financial info | Yes | No | App functionality, fraud prevention | No (P2P method details are shown to the counterparty) | Transactions retained |
| Financial — Purchase history | Yes | No | App functionality | No | Retained |
| Photos and videos | Yes | No | KYC, dispute evidence, support | No | KYC documents retained |
| Files and docs | Yes | No | KYC, dispute evidence | No | Retained |
| Messages — other in-app messages | Yes | No | App functionality, support | Shown to the counterparty in P2P chat | Tickets and messages retained |
| App activity | Yes | No | App functionality | No | Mixed |
| Device or other IDs | Yes | No | Push delivery | No | Push subscription removed |
Location is not collected. The P2P country/region/city on an offer is typed by the user, not read from the device, and there is no location permission in the manifest. Do not declare Location.
Contacts, calendar, audio, health and web browsing are not collected.
Card payments go to Stripe, not to you
Fiat deposits open Stripe's own PaymentSheet. The card number, expiry and CVC
are entered inside Stripe's native UI and travel directly from the device to
Stripe — your backend only ever sees a clientSecret and a
paymentIntentId. Declare payment info as collected and shared with a third
party, and name Stripe.
KYC is the sensitive one
Play classes identity documents as personal and sensitive information, and this is where the app handles the most of it.
- What is captured: front and back scans of an identity document plus a selfie holding it. The stock document types are passport, driver's licence, national ID and residence permit — but the KYC form is server-driven, so the exact fields are whatever your levels define.
- How it travels: the file is base64-encoded into a JSON body (not
multipart) and posted to
/api/upload/kyc-document. The server validates the magic bytes, caps the decoded size at 10 MB, and stores it privately — not under a public uploads path. - EXIF is not read. The picker is called with
requestFullMetadata: false, and images are downscaled to 2048×2048 at quality 85 before upload. - No permission is requested for the gallery. Android capture routes through
the system Photo Picker, so the app never declares
READ_MEDIA_IMAGESand you never have to answer Play's Photo and Video Permissions declaration. - It is retained after account deletion, deliberately, because AML record keeping requires it. Say so in your privacy policy.
What account deletion actually does
The in-app deletion is not a soft flag. Inside one transaction it anonymises the record: email tombstoned, and password, phone, avatar, username, wallet address, profile and settings nulled; sign-in provider links are hard-deleted. The email address is released, so a deleted customer can register again.
What it does not remove: transaction and order records, KYC documents and the identity data on them, and support tickets and their messages. Those are retained by design. Your privacy policy has to say this — "we delete everything" is the answer that is not true.
Third parties the app contacts directly from the device
Most traffic goes to your backend. These do not:
| Host | What reaches it | Why it matters |
|---|---|---|
| Stripe | Card data, during a fiat deposit | Declared as shared; Stripe's own privacy policy applies |
| Google Sign-In | The sign-in exchange, only if you enable it | Ships disabled in the packaged config |
| CryptoCompare | News requests, carrying the device's IP and the API key in the client | Proxy this through your backend if you can — the key is quota-bearing and a client-side key is a shared quota |
vectorlogo.zone, via.placeholder.com |
Nothing but the request itself — decorative images | The request still discloses your customer's IP to a third party. Consider bundling the assets instead |
The iOS side
ios/Runner/PrivacyInfo.xcprivacy ships with the app and is wired into the
Runner target's Copy Bundle Resources phase. It declares no tracking, an empty
tracking-domains list, and two required-reason APIs (user defaults, file
timestamps). Read the comment at the top of that file before changing it — it
explains which reason codes apply to the app rather than to a plugin, and why
three other categories are deliberately absent.
Apple aggregates your manifest with every bundled framework's. Google Sign-In's own manifest declares coarse location, a device ID and usage data for analytics; that is Google's collection in Google's bundle, and your App Store Connect answers still have to account for it.
One thing to fix on your own deployment
The app puts the user id in the WebSocket query string rather than only in a header. Query strings are logged by proxies and reverse proxies as a matter of course. It is an internal identifier rather than a credential, but if you run access logging on your own edge, that is where it will accumulate.