WARFORM Privacy Policy
ON THIS PAGE
- 1. Introduction
- 2. Data We Collect
- 2.1 Account data (personal)
- 2.2 Health and fitness data
- 2.3 Social data (personal)
- 2.4 Subscription / billing (financial, limited)
- 2.5 Technical data
- 3. Legal Bases (UK GDPR)
- 4. What Each Third-Party SDK Receives
- 4.1 Supabase (database, auth, storage)
- 4.2 OneSignal (push notifications — optional)
- 4.3 Google Health Connect (optional, opt-in per type)
- 4.4 Advertising (none today)
- 4.5 Google Play Billing + RevenueCat (payments)
- 4.6 Email delivery (provider chain — currently Resend)
- 4.8 Google Sign-In (optional)
- 4.9 Open Food Facts (barcode lookup, free)
- 4.10 Cloudflare Turnstile (anti-bot, optional)
- 4.11 google_fonts
- 4.12 International transfers
- 5. How We Use Your Data
- 6. Your Questions, Answered Directly
- 7. Your UK GDPR Rights
- 8. Security
- 9. No Cookies, No Tracking
- 10. Children
- 11. Retention
- 12. Changes
- 13. Contact
1. Introduction
This Privacy Policy explains how KAAZIO LTD ("we", "us", "our"), a controller established in the United Kingdom — KAAZIO LTD, Company No. 17460399, registered office 25 Saltwells Crescent, Middlesbrough, England, TS4 2DX [HUMAN: ICO registration reference], collects, uses, stores, and protects personal data when you use the WARFORM mobile application and related services (the "Service"). WARFORM is a gamified fitness tracking application for adults aged 18 and over.
We do not sell your personal data. We collect the minimum needed to run the Service, and we describe every category and every external processor below.
This policy is governed by the UK General Data Protection Regulation (UK GDPR) and the Data Protection Act 2018.
2. Data We Collect
2.1 Account data (personal)
- Email address — required for signup, login, verification codes, password resets and account deletion.
- Username (callsign) and Warrior name (display name) — both are your chosen public identifiers.
- Password — stored only as a cryptographic hash by the auth provider (Supabase GoTrue); we can never read it.
- Google account ID token — if you choose Google Sign-In, the app exchanges a Google ID token for a Supabase session; we store no Google credentials.
- Auth user ID (UUID) — the internal key linking your data to your account.
- Account status / suspension state — moderation records (kept in your profile's
account_status/suspended_untilfields).
2.2 Health and fitness data
- Age, gender, height, weight, target weight, activity level, BMI, maintenance calories — onboarding profile fields.
- Workout logs — name, date, duration, estimated calories, exercise names, sets, reps, weight, RPE, per-set
logged_setshistory, supersets, distances, duration-seconds. - Nutrition logs — food names, calories, macros (protein/carbs/fat), meal type, meal-photo storage paths.
- Water intake logs.
- Sleep logs — duration (minutes), quality rating, notes.
- Body measurements — type + circumference (cm) + date.
- PFT results — push-ups, plank, 2-mile run scores and computed event points.
- Limitation toggles — knees / lower back / shoulders / wrists protection preferences (advisory, not medical).
- Health Connect metrics (read-only when granted): steps, heart rate, sleep stages. See section 4.3 — this data stays on the device.
- Progress photos (Elite) — stored in a private bucket behind per-user access policies.
- Meal photos — private bucket, per-user folder policy.
2.3 Social data (personal)
- Friendships / friend requests — bidirectional social graph records.
- Squad chat messages — text and workout-share messages between accepted friends, stored in
public.messages(see section 6). - Presence —
last_seentimestamps shown to friends in your squad roster.
2.4 Subscription / billing (financial, limited)
- Subscription tier, is_pro flag, subscription source, subscription_updated_at — mirrored onto your profile by the payment webhook.
- Stripe customer ID — optional; present on the profile schema for RevenueCat Web Billing customers; the direct Stripe integration is NOT deployed.
- Purchase ledger rows — store (
PLAY_STORE/STRIPE/PROMO), transaction IDs, original purchase IDs, product IDs, tier, purchased/expiry timestamps, bonus flags. We store no card numbers and no bank details — payment data is processed entirely by Google Play / RevenueCat.
2.5 Technical data
- Device info — platform (Android), model, OS version, app version, captured into crash logs and push-token rows.
- Push tokens — OneSignal player ID + device info, stored in
device_push_tokens. - Analytics events — feature usage events (screen views, meal logged, workout finished, etc.) with coarse properties only; no message content, no free-text. Insert-only, opt-out in Settings.
- Crash logs — error type, message, stack trace, route, device info, app version, optional user ID (fatal and soft errors). Anonymous (user-less) crash rows are also accepted before login.
- IP-to-country estimate — used transiently for pricing display; the IP itself is not stored by us (see section 4.7).
3. Legal Bases (UK GDPR)
We process your personal data on the following legal bases:
- Contract — Article 6(1)(b) UK GDPR: account data, workout/nutrition/sleep logs, social messages, push tokens, purchase ledger — processing necessary to perform the contract between you and us (providing the Service you signed up for).
- Legitimate interest — Article 6(1)(f) UK GDPR: crash logs, rate-limit records, abuse prevention, account status — necessary for our interests in security, fraud prevention and service integrity, balancing your rights and expectations.
- Consent — Article 6(1)(a) UK GDPR: Health Connect reads, analytics events where opt-in is required by law, and the five opt-in notification categories (workout reminders, streak-at-risk, program-day, rest-day notes, and the monthly service review — all default OFF).
- Legal obligation — Article 6(1)(c) UK GDPR: minimal retention of transaction records required by tax/accounting law.
Where processing involves data within the special categories of Article 9 UK GDPR (notably health data in section 2.2), we rely on your explicit consent (Article 9(2)(a)) for the optional Health Connect integration, and otherwise process fitness-log data on the basis that you provided it voluntarily and expressly for the purpose of the Service you requested (contract), such that the processing is manifestly within your reasonable expectations. If you have questions about the specific basis applied to a given activity, contact us at support@warform.app.
4. What Each Third-Party SDK Receives
4.1 Supabase (database, auth, storage)
- What leaves the device: all logged training, nutrition, sleep, measurement, social, purchase, crash and telemetry data described in section 2. Session JWTs (stored in Android Keystore-backed encrypted storage, not plaintext).
- Purpose: primary backend (auth, Postgres with row-level security, file storage buckets).
- Provider policy: supabase.com/privacy
4.2 OneSignal (push notifications — optional)
- What leaves the device: OneSignal player ID, the Supabase user ID (as OneSignal login identity), push token, device model/OS.
- Purpose: delivering friend requests, message notifications, opt-in training reminders and opt-in streak-at-risk / program-day / rest-day notes.
- Notifications may include the sender's callsign and a short preview of the message (e.g., "New message from [callsign]") or a description of shared content (e.g., "Shared a workout: [name]"). Push notifications are delivered via OneSignal.
- Notifications are rate-capped server-side (max 1 automated push per user per day, 10 caller-triggered pushes per minute).
- Provider policy: onesignal.com/privacy
4.3 Google Health Connect (optional, opt-in per type)
- What leaves the device: nothing. Health Connect reads happen on-device only; the app reads steps, heart rate, sleep stages, active calories and distance when you grant them. Nothing is ever written back to our server from Health Connect — the data is rendered locally on the Wearables screen only.
- Write-back (Elite, explicit grant only): the app can write completed workout records (title, start/end time, type) INTO Health Connect. This is a one-way write; the app does not read back anything extra.
- Revocation: you can disconnect from the Wearables screen or Android Settings; access stops immediately.
- Provider policy: Google Health Connect processes locally on the device.
4.4 Advertising
Advertising: WARFORM ships with no advertising and no ad SDK initialized. We do not run any ad provider today, we do not serve ads, and we do not collect advertising identifiers. If the economics of keeping WARFORM running ever force us to consider advertising, the change starts here: these legal pages update first with at least 30 days' notice, paid subscribers never see ads, health and fitness data is never an ad target, and personal data is never sold. Until such a notice exists, any statement about ads in this policy is a commitment against them, not a disclosure of them.
4.5 Google Play Billing + RevenueCat (payments)
- What leaves the device: the app calls RevenueCat (
purchases_flutter) with your Supabase user ID; RevenueCat handles the Google Play purchase flow, receipt validation and entitlement. We store only the mirrored entitlement, subscription tier, source and transaction identifiers — no card numbers, no bank account details, no billing addresses. - Stripe (web purchases): when the payments build flag is ON, the paywall offers an optional "Pay on web" path. It opens a Stripe HOSTED checkout page (warform.app/subscribe → Stripe Checkout Session, created by our own edge function create-checkout-session) — we never render card fields in the app and raw payment credentials never touch our servers or our database. This Stripe lane is DIRECT: our own webhook mirrors the entitlement, and RevenueCat plays no role in web payments. When the flag is OFF (closed testing), no Stripe checkout is offered and none of this applies.
- Refunds/subscriptions: governed by Google Play policies and the RevenueCat-hosted management page.
4.6 Email delivery (provider chain — currently Resend)
- What leaves the server: your email address + a 6-digit verification code in the subject/body. The code itself is stored only as a SHA-256 hash in our database.
- Purpose: OTP delivery for signup, sign-in code verification, password reset and account deletion. Every attempt is logged to
email_logs(email + provider + success + error). - The provider chain: OTP mail is sent through an ordered chain of processors — Resend (resend.com/privacy) today. If the active provider reports a hard failure, the next configured processor attempts the same single send (hard-failure-only failover: a successful attempt is never retried and never fails over). The chain may also include Brevo (brevo.com/privacy), Maileroo (maileroo.com/privacy) and Plunk (useplunk.com — self-hosted, reached only through our own tunnel endpoint), each solely while enabled by our configuration.
- No marketing emails are sent through this pipeline; no email content beyond the single verification code leaves the server.
4.8 Google Sign-In (optional)
- What leaves the device: your Google ID token, exchanged server-side with Supabase to create a session. We never request or store Google contacts, Google Drive data, or any Google profile information beyond the account email that Supabase records.
4.9 Open Food Facts (barcode lookup, free)
- What leaves the device: a barcode number you scanned, sent as an anonymous HTTP GET to
world.openfoodfacts.org. - What we get back: product name, quantity, nutriments. No account data is attached to this request.
4.10 Cloudflare Turnstile (anti-bot, optional)
- What leaves the device: a Turnstile widget token, if
TURNSTILE_REQUIREDis enabled. Used only to protect the OTP endpoint from abuse. - Provider policy: cloudflare.com/privacypolicy
4.11 google_fonts
- Bundled at build time — fonts ship with the APK and no runtime request to Google Fonts servers is made from the app.
4.12 International transfers
Some processors (Supabase, RevenueCat, OneSignal, Google) may transfer data outside the UK. These transfers are protected by appropriate safeguards (Standard Contractual Clauses or adequacy decisions). Where a processor operates in a country covered by a UK adequacy decision, that decision provides the safeguard; otherwise the transfer is governed by the UK Addendum to the EU Standard Contractual Clauses or the processor's own UK-approved transfer mechanism.
5. How We Use Your Data
- Running the app you asked for — displaying your logs, computing XP/level/streak, streak freezes, medals, seasons, PFT scores, coach briefings, squad leaderboards.
- Server-side verification — gamification columns (XP, level, streak) are written only by trusted server functions; you cannot self-assign them.
- Push notification delivery — gated by per-category opt-in switches and a 1-per-user-per-day cap.
- Crash investigation and support — crash logs (device + stack trace) are used to diagnose and fix failures.
- Anonymous product analytics — coarse usage counters only; never message content, never food names, never note text. Opt-out at Settings.
- Local pricing display — IP-to-country, cached locally.
- Abuse prevention — rate limits, account status (suspended/banned) for Community Guidelines enforcement.
We do not use your health or exercise data for advertising.
6. Your Questions, Answered Directly
Do we use AI?
WARFORM contains no artificial intelligence, machine learning, or large language models. The "AI Coach" is a deterministic rule-based engine that applies fixed if/then logic to your own logged data. No user content is sent to external AI providers.
Coach briefings are generated by selecting pre-written phrases from a curated bank using deterministic rules. This is not AI-generated content. The phrase for a given rule is picked deterministically from the category pool by a stable (user, date) seed, so a briefing shown twice the same day is identical. There is no cloud AI provider, no per-request AI API call, and no model training on your data anywhere in the app or server.
Can the team read user chats/logs?
- Chat messages are stored in
public.messages(Squad chat between accepted friends). Technically, the service role (used by our Edge Functions and admins) can query them. While technical access exists (service-role key), no human on the team routinely reads user chats except to investigate abuse reports you file or comply with legal obligations. The automated wordlist moderation and report queue from the earlier social build were removed; only the ban/suspend account-status path remains. - Workout/nutrition/sleep logs are private to you under row-level security; team access is limited to support requests you open (e.g. "my data export failed") and abuse investigation.
- Who holds service-role access: the Supabase project owner and Edge Function secrets. The
SUPABASE_SERVICE_ROLE_KEYnever ships in the app binary. - Crash logs may contain the route you were on and a stack trace; we read them to fix bugs.
What is persisted in the database vs on-device only?
- Persisted server-side (Supabase Postgres): all of section 2 (profile, workout/nutrition/sleep/water logs, measurements, PFT, squad chat, friendships, purchase ledger, push tokens, crash logs, telemetry events, OTP-code hashes, email-delivery logs, photo storage in private buckets).
- On-device only: cached snapshots (encrypted, expire after 1 day), country preference, telemetry opt-out flag, notification preference toggles (server-mirrored), voice-input transcript buffer (never uploaded), coach briefings (computed from data already on the server), offline write-queue (pending inserts for when you regain connectivity — the queue lives in encrypted storage and drains to the server).
- Ephemeral server-side: OTP codes (10-minute expiry, deleted on use or expiry), OTP tickets (15-minute single-use proof), email delivery log rows (provider audit trail — purged together with your account; see "Account deletion" below).
Voice coaching: on-device or cloud?
On-device. The app uses the speech_to_text Flutter plugin, which delegates to the platform's built-in recognizer (Android SpeechRecognizer). No cloud speech API is configured; no audio or transcript leaves the device. The recognized text is parsed into set fields locally, and the transcript buffer is discarded when the dialog closes. The microphone permission (RECORD_AUDIO) is requested contextually — only when you tap the mic button in the set-logging dialog, never at install.
Health Connect: what is read/written, and where is it stored?
- Read (opt-in per type): steps, heart rate, sleep stages (asleep/in-bed/awake/deep/REM/light), active calories, distance. Data stays on the device — the Wearables screen renders it; the app never uploads it to Supabase or to any third party.
- Write (Elite + explicit grant only): completed workout records (activity type, start, end, title, optional distance) are written INTO Health Connect. This is a one-way write; we do not read back anything we didn't already have.
- Where stored: on-device, inside Health Connect's own local store. We store no Health Connect data in our database.
Payments: who processes them and what do WE store?
- Google Play Billing is the processor on Android (via the RevenueCat SDK for receipt validation and entitlement management). RevenueCat operates the PLAY entitlement layer only: the web purchase path runs through a Stripe HOSTED checkout page created by our own edge function, mirrored by our own webhook (DIRECT topology — Stripe is never integrated via RevenueCat).
- We store: subscription tier,
is_pro, subscription source, subscription update timestamp, Stripe customer ID (RevenueCat Web Billing users only), and a purchases ledger with transaction IDs / product IDs / purchase & expiry timestamps. We do not store card numbers, CVVs, bank accounts, or billing addresses. - Refunds and cancellations: follow Google Play policy; entitlement is revoked automatically when the RevenueCat webhook reports
EXPIRATIONorREFUND.
Account deletion: what does the delete flow actually remove, what remains?
The delete flow (Settings → Danger Zone → Delete Account) does:
- Asks you to confirm a 6-digit email code (
purpose: delete) — stored hashed, 10-minute expiry. - Asks for your current password as a second factor (verified server-side before the code is consumed).
- On confirmation, runs a full cascade: deletes your storage objects in
meal-photos,progress-photosandavatarsbuckets, then rows frommessages,conversation_members,meal_templates,food_favorites,food_logs,water_logs,sleep_logs,body_measurements,workout_logs(which cascadesworkout_log_exercises),workout_plans(which cascadesworkout_exercises),device_push_tokens,crash_logs(explicit),friendships, youremail_logsrows (purged by email address), then your profile row, then the auth user itself. - Deleting the profile row frees your Warrior name for someone else to claim.
What remains after deletion:
- Your Google Play / RevenueCat purchase history — held by Google and RevenueCat under their own retention rules, not something we can delete from their systems.
- OTP codes and tickets expire on their own (10/15 minutes) and are not touched by the flow.
- Anonymous crash-log rows (from before you signed in) remain — they contain no user ID by design.
- Supabase Postgres WAL / point-in-time recovery snapshots may retain historical state for a limited infrastructure-defined window after the live tables are cleaned.
How to use it: Settings → Danger Zone → Delete Account → Send verification code → enter code + password → confirm permanent deletion. Deletion is irreversible.
7. Your UK GDPR Rights
You have the following rights under the UK GDPR and Data Protection Act 2018:
- Right of access (Article 15): request a copy of the personal data we hold about you. In-app: Settings → Data Management → "Full JSON" export, or contact support@warform.app for a manual full export.
- Right to rectification (Article 16): correct inaccurate data. In-app: edit your profile (username, warrior name, body metrics, goals), or contact us.
- Right to erasure (Article 17): have your personal data deleted. In-app: Settings → Danger Zone → Delete Account (full flow described in section 6), or contact us for assistance.
- Right to restriction of processing (Article 18): ask us to pause a specific processing activity while a dispute is resolved. Contact support@warform.app.
- Right to data portability (Article 20): receive your data in a structured, commonly used, machine-readable format. In-app: Settings → Data Management → "Export CSV" or "Full JSON".
- Right to object (Article 21): object to processing based on legitimate interests (e.g. crash logs, abuse prevention). Contact us and we will assess the objection.
- Right to withdraw consent (Article 7(3)): where processing is based on consent (Health Connect, opt-in notification categories, analytics), you may withdraw it at any time: revoke Health Connect from the Wearables screen or Android Settings; toggle notification and analytics switches in Settings.
We respond to rights requests within one month (extendable by two further months for complex requests, as permitted by UK GDPR Article 12(3)).
You have the right to lodge a complaint with the Information Commissioner's Office (ICO), the UK supervisory authority for data protection issues (www.ico.org.uk).
Additional choices in-app:
- Opt out of analytics: Settings → toggle "Anonymous product analytics" off.
- Turn off push notifications: Settings → Notifications, per-category switches; or revoke the OS notification permission. All five automated categories (workout reminders, streak-at-risk, program-day, rest-day notes, monthly service review) default to OFF — strictly opt-in.
Contact: support@warform.app for any privacy request, including a manual full export or deletion assist.
8. Security
- Transport: all API traffic uses HTTPS/TLS (
android:usesCleartextTraffic="false"in the Android manifest). - At-rest: Supabase Storage buckets for meal/progress photos are private (signed 30-minute URLs only). The
avatarsbucket is public by design (avatars are meant to be visible). - Row-level security (RLS): every table is governed by RLS policies so one user cannot read or write another user's data (own-row-only policies, friend-visible policies for the social graph, and no-policy tables restricted to the service role).
- Server-side write guards: gamification columns, subscription columns and trial state are protected by BEFORE INSERT/UPDATE triggers that revert unauthorized client writes.
- Encrypted device storage: Supabase session tokens and health-data snapshots live in
flutter_secure_storage(Android Keystore-backed); legacy plaintext caches are actively purged on app start. - OTP codes: stored only as SHA-256 hashes, 10-minute expiry, 5-attempt cap, timing-safe comparison, 60-second resend cooldown, 10-per-day cap per email.
- Secrets: the Supabase service-role key, RevenueCat webhook secret, OneSignal REST key, email-provider keys and the push-schedule secret all live as Supabase Edge Function secrets — never in the app binary, never in the repo.
- Staff access: limited to support, security and abuse prevention, on a least-privilege basis. No team member routinely reads user content.
9. No Cookies, No Tracking
The WARFORM app sets no tracking cookies — mobile apps do not use browser cookies, and we use no equivalent device fingerprinting. No advertising identifiers are read for anything: WARFORM ships no initialized ad SDK, serves no ads and collects no advertising identifiers — section 4.4's Advertising clause carries the commitment and the 30-day-notice process that would govern any future change.
This website (warform.app) sets no cookies, loads no tracking pixels, and embeds no analytics beacons. Nothing about your visit is profiled, and no cross-site identifiers follow you. The site is static pages served by our host; we do not run visitor analytics on it.
In the app: anonymous product analytics exist but are OFF by default — a Settings switch you may turn on, carrying coarse feature-usage counters only (never message content, never free text, never food names). Crash reports attach device/OS/app version and are never sold. That is the entire behavioral data surface.
10. Children
WARFORM is restricted to users 18 years or older, enforced at onboarding with an age gate (age ≥ 18; under-18 entries hit an "ACCESS DENIED" block screen and proceed no further).
- No parental-consent flow exists, by design. We do not offer the service to minors under any consent mechanism — there is nothing for a parent to consent to. The 18+ gate is the control.
- Known minors are excluded. We do not knowingly collect data from anyone under 18. If we learn an account belongs to a minor — by report or discovery — we delete the account and its data.
- Report a minor's account: email support@warform.app from any address; deletion follows our account-deletion process without requiring the minor's credentials.
- If you are a parent or guardian with questions, the contact section below reaches a human.
11. Retention
- Account data + logs: retained while your account is active; deleted via the account-deletion cascade when you remove your account (subject to the exceptions in section 6).
- Encrypted device caches: expire after 1 day.
- OTP codes: expire after 10 minutes (or immediately upon successful verification / attempt exhaustion).
- OTP tickets: expire after 15 minutes, single-use.
- Email delivery logs (
email_logs): retained for deliverability monitoring while your account is active; purged when you delete your account. - Crash logs and telemetry: retained for as long as needed to debug and improve the Service; removed for your account by the deletion flow.
- Supabase infrastructure backups: deleted live data may persist in point-in-time-recovery snapshots for a limited infrastructure-defined window.
12. Changes
We may update this policy. Material changes are announced in-app at least 30 days before they take effect (with the "Last updated" date above reflecting each revision). Continued use after a change constitutes acceptance.
13. Contact
Questions, requests, or complaints: support@warform.app (KAAZIO).
You also have the right to lodge a complaint with the Information Commissioner's Office (ICO), the UK supervisory authority for data protection issues (www.ico.org.uk).