Analytics

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.

Stop searching.
Start discovering.

Download free on iPhone and Android.

Download on the App Store Get it on Google Play