Child Name Privacy in Analytics
A child's nickname is PII. The app had five analytics call sites that logged it. Replacing the name with is_custom (preset vs user-typed) was the fix — but it took a round of pushback before the preset names came back.
The Problem
The app lets parents add children with nicknames or names — "Emma," "Bug," "the little one." Some are custom names the parent typed. Others are preset names from a fixed list built into the app.
An analytics audit found that five call sites across the app were logging
child.name as an analytics parameter. Custom-typed names are PII. If a
parent types their child's real name, it ends up in the analytics database. That's
not okay for a family app.
The Fix: is_custom
The actionable question isn't "what name did they pick?" — it's "did they create a custom name or choose a preset?" Custom names signal engagement and personalisation. Preset names tell me which nicknames resonate most.
I replaced child.name with an is_custom boolean at all five
call sites:
Analytics.logEvent("child_added", parameters: [
"is_custom": NicknameStore.loadedCustomNames().contains(child.name) ? "true" : "false",
"age_years": child.years,
"age_months": child.months,
"city": child.city
])
NicknameStore.loadedCustomNames() is a static method that returns the
set of names the user has typed themselves. If child.name is in that set,
is_custom is "true". If it's not — meaning it came from the
app's preset list — is_custom is "false".
The Pushback
Claude's initial implementation removed name logging entirely and replaced it with
just is_custom. I pushed back: preset names are not PII and are actually
useful analytics data. Knowing that "Buddy" and "Bug" are the most popular preset
picks is relevant product information.
The right rule is: custom-typed names are PII and must never be logged. Preset names
from the app's own fixed list are safe — they're our vocabulary, not the user's personal
data. The is_custom field distinguishes the two cases in the analytics
schema.
After I pushed back, the implementation was updated to log preset names (as
name_preset: child.name when is_custom = "false") while
still blocking custom names entirely.
The Audit
All five call sites were reviewed: child_added, child_updated,
child_deleted, child_switched, and onboarding_completed.
Each was updated to use is_custom and conditionally log the preset name.
No raw custom-typed names remain in the analytics path.
- Custom-typed names are PII. Preset names from a fixed app list are not.
- The binary is_custom signal is often more actionable than the raw value anyway.
- Audit all call sites of any sensitive field together — a partial fix is worse than no fix because it creates false confidence.
