Royal Academy is a learning platform for children K–8. Children under 13 are a protected class under U.S. federal law. This page is the plain-English version of what we do with their data and why — structured so every commitment below maps to a concrete line of code, a database field, or an operational control. If you want to verify any of this, our code is public and linked from the footer of each section.
What we collect
We collect the minimum data needed to run the learning platform. A child's account is created by their parent or guardian — children cannot sign themselves up.
- Profile — first name, last name, date of birth (for age-appropriate content), learning level, optional profile picture.
- Learning progress — which lessons they've started or finished, quiz scores, time spent, achievements earned.
- Lesson responses — button selections made during interactive lessons.
- Voice recordings — only if you opt in (see biometric section below). These are treated as biometric identifiers.
- Consent records — what you agreed to, when, from what IP and browser, and the version of the policy in effect at the time.
We do not collect: government IDs, social-security numbers, precise location, contacts, the child's email (students don't have an email on their account), payment info from the child, or anything we don't have a documented reason to have.
How we get your consent
Before a child's account is created, we show you a consent form listing every category above as a separate checkbox. Each category is a granular opt-in — a requirement of the 2025 COPPA amendments. You can't accidentally agree to everything with a single click.
The child account is only created once you submit consent.
If you abandon the form, no child record ever exists in our database.
(Technically enforced at compliance/views.py — the account
is created inside the consent POST, not before.)
Each consent record stores:
- The categories you agreed to.
- Whether you opted in to biometric (voice) collection.
- Whether you opted in to any third-party disclosure (today: disabled — see the third parties section).
- The exact version of this privacy policy you saw.
- The date, your IP, and your browser — so we can defend the consent if audited.
- When it expires (365 days by default).
Audio & biometric data
Some lessons include a moment where the child can record their voice as an answer. Under the FTC's 2025 COPPA Rule, a voiceprint is "personal information." Under the Illinois Biometric Information Privacy Act (BIPA, 740 ILCS 14), it's "biometric information." Both laws require a separate, specific, written consent — not just agreement to general data collection.
Our consent form has a dedicated "Audio Recording" checkbox with the biometric disclosure text attached. It defaults to off. If you leave it off:
- Audio-interaction moments are filtered out of your child's lessons on the server. The player never even receives them, so there's no silent pause or broken UI.
- The upload endpoint independently rejects any audio POST with a 403 if biometric consent is missing — a belt-and-suspenders check.
- Your child can still complete every lesson. Audio moments are optional.
If you opt in, recordings are stored in a private storage bucket accessible only via signed URLs that expire in 10 minutes. You can revoke biometric consent at any time from the child's privacy page; revocation deletes existing recordings from our storage.
How we enforce it (the "fail-closed" principle)
Every time a child makes a request to our server, a middleware checks: do they have active, non-expired consent on the current policy version? If the answer is "no" for any reason — never consented, consent withdrawn, consent expired, policy was updated — the child is immediately redirected to a "waiting for a grown-up" page until the situation is resolved.
This is enforced on every request, not cached at login time,
so a parent who withdraws consent locks out the child on their very
next click. (See compliance/middleware.py.)
How long we keep data
The 2025 COPPA amendments prohibit indefinite retention. Each category
has a specific, published retention window. When a window passes, the
data is permanently deleted — not soft-deleted, not anonymised. A nightly
job (retention_cleanup) enforces the schedule.
Child's first name, date of birth, learning level, optional profile picture.
Kept while the account is active; deleted immediately on request.Lesson completions, quiz scores, time spent, achievements.
Deleted 30 days after consent is withdrawn or the account is closed.Button selections and activity answers given during lessons.
Deleted 90 days after consent is withdrawn.Voice responses captured during audio-interaction moments — only collected when a parent has explicitly opted in under BIPA and COPPA's biometric definition.
Deleted from our storage 30 days after consent is withdrawn, and immediately when biometric consent is revoked.Record of when consent was granted, renewed, or withdrawn, including IP and user-agent. Append-only; parents can request a copy at any time.
Retained 7 years — required to demonstrate compliance if audited.Proof that a deletion request was processed (preserves parent username and deletion metadata; the child's data itself is gone).
Retained 7 years.ZIP archives produced when a parent exports their child's data.
Auto-expire 48 hours after creation; the download link stops working and the file is removed from our storage.Parent email, Stripe customer/subscription IDs. No child PII is ever sent to Stripe.
Kept while the account is active; removed on account deletion except where tax law requires longer retention of invoice records.Who else sees it
We use a small number of third-party processors to run the service. For each, we disclose what data actually reaches them and whether it includes any child personal information.
We do not currently share any child data with anyone for advertising, marketing, analytics, or any other purpose beyond running the service. The 2025 COPPA Rule requires a separate opt-in for third-party advertising disclosures — our consent form includes that checkbox, but it's disabled and explicitly defaults to "no."
Purpose: Subscription billing.
What they receive: Parent name, parent email, payment card details. No child data is ever sent.
Purpose: Transactional email to parents (password resets, billing).
What they receive: Parent name, parent email, message contents. No child data.
Purpose: Application hosting (App Platform), managed database, object storage (Spaces) for profile pictures, lesson videos, and audio.
What they receive: Everything processed by the service lives on DigitalOcean infrastructure. Private files (profile pictures, audio, exports) are served via signed URLs that expire in 10 minutes.
Purpose: Production error reporting so we can fix crashes.
What they receive: Exception stack traces and request metadata. PII scrubbing is enabled (`send_default_pii=False`); usernames, emails, and request bodies are excluded.
Purpose: DNS and edge caching for static assets.
What they receive: Standard network metadata (IP addresses, request paths). No child application data is cached at the edge.
Your rights as a parent
You have the right to review, correct, export, and delete your child's data at any time. These aren't paper rights — we've built each one into the product.
- Review: Open the Parent Hub, pick the child, and you can see exactly what we have on them — progress, responses, recordings, consent history.
- Correct: Edit the child's profile from the same page. Changes take effect immediately.
- Export: One click produces a ZIP containing
profile.json,progress.json,responses.json,consent_history.json, and anaudio/folder with every recording (if any). Download link is valid for 48 hours. - Delete a single child: Confirm by typing the child's first name. All of their data — progress, responses, audio, consent history — is permanently deleted within seconds.
- Delete everything: From the account settings page. Requires your password. Deletes all children, then your parent account.
- Revoke biometric consent only: Toggle off from the child's privacy page. Existing recordings are deleted; future audio moments are skipped.
- View the audit log: A full, append-only history of every consent action we took on the account. Available on request.
How we secure it
The technical controls that protect your child's data:
- Transport: HTTPS enforced site-wide; HSTS with a 1-year max-age, preload-listed.
- Passwords: Argon2 hashing; minimum 10 characters; standard Django password validators.
- Sessions: Secure, HttpOnly cookies. No "remember me" cross-contamination between parent and child sessions.
- CSRF: Enabled on every mutating request; no exemptions.
- Audio & exports: Stored in a private bucket; served only via signed URLs that expire in 10 minutes.
- Error reporting: Sentry captures exceptions but has PII scrubbing turned on (
send_default_pii=False). Usernames, emails, and request bodies are excluded. - Audit log: Every consent action is recorded in an append-only table that cannot be updated or deleted — enforced at the model level, not just by policy.
- Fail-closed middleware: Consent is re-checked on every authenticated request; there's no "cached OK" to poison.
When we change this policy
If we materially change what data we collect, how we use it, or who we share it with, the privacy policy version is bumped. The next time your child logs in, they'll be redirected to the "waiting for a grown-up" page, and you'll be asked to review and re-consent to the new version. We don't silently migrate your prior consent.
The current version of this policy is 1.0.0. Consent is refreshed every 365 days at minimum, regardless of whether the policy has changed.
Contact & complaints
If you have questions about any of the above, or you think we've done something wrong, email [email protected]. We aim to respond within 3 business days.
You can also file a complaint directly with the U.S. Federal Trade Commission at reportfraud.ftc.gov, which administers COPPA. If biometric data is a specific concern, the Illinois Attorney General's office accepts BIPA complaints.
compliance/constants.py.