A food-delivery app of Zomato's shape must refuse alcohol orders to under-18s. The sign-up form asks for a full date of birth and the team is about to store it on the user row alongside the address. What should the account record hold instead, and what does the full date of birth cost you later?
Show the full answer Hide the answer
The deciding property
The system needs to answer one question at order time: may this account buy alcohol? It does not need to know the customer's birthday. A date of birth is a strong quasi-identifier and, in many datasets, the third field an attacker needs after postcode and gender to single someone out. A boolean plus the evidence of how it was set answers the business question with none of that exposure.
So the record holds age_verified_over_18: true, verified_on: 2026-03-14, method: document-scan, and
nothing else. The check happens once against the date of birth; the date of birth is never persisted.
What the full date of birth costs you later
- Breach severity. Date of birth plus name plus address is the trio used for account takeover at banks and telcos. A leak of 2 million rows with dates of birth is a materially worse incident than the same rows without them, and that difference is what regulators and customers price.
- Scope creep. A field that exists gets used. Within two years marketing has a birthday campaign and analytics has an age-cohort dashboard, each a new purpose that needs its own basis.
- Subject access and erasure surface. Every copy of that field, in the warehouse and in three vendor exports, is now a thing you must find and remove.
- Re-verification. The boolean has the opposite problem: a person who was 17 at sign-up is 18 later. Store the check date so a nightly job can re-run the check for accounts that failed, rather than storing the birth date to recompute it.
GDPR Article 25 calls this data protection by design and by default. The architectural reading is narrower and more useful: persist the answer, not the input.
Why the other options fail
- Store the full date of birth on the user row. This is the default that teams reach for because the form already collected it, and it is the mistake the whole item is about. Collecting a field is not a reason to keep it. Verify and discard.
- Store the user's age in years and recompute it every night. A nightly recompute needs the date of birth to compute from, so this option quietly keeps the field it claims to avoid. Worse, an integer age is still a quasi-identifier and now it drifts out of date between runs.
- Store a salted hash of the date of birth. A date of birth has roughly 30,000 plausible values. A hash with a per-record salt is reversible by brute force in milliseconds, and a hash you cannot compare against anything is useless for the age check anyway. Hashing a low-entropy value is not minimisation.
When not to do this
If the product genuinely needs the date of birth for its core purpose, keep it and protect it. An insurer pricing a policy, a health service, a pension platform: for these the birth date is the input to the service, and stripping it is not minimisation, it is breaking the product. The test is whether any feature reads the field for something other than the gate. If none does, the field should not survive the sign-up request, and the cheapest privacy control available to any team is the field that was never written.