← All writing

Privacy-First Product Analytics: What to Measure When You Refuse to Track People

A product can learn from usage without building a profile of every person. This is the measurement model I use when trust, minimal collection, and useful product decisions all matter.


The default analytics question is usually “What did this person do?”

It is an efficient way to build funnels, retention cohorts, and personalised prompts. It is also the wrong starting point for a product where collecting behavioural history is hard to justify, difficult to explain, or simply unnecessary.

For a privacy-first product, I start with a smaller question: “What decision are we trying to make?”

That question changes the data design. You may need to know that a lesson is too difficult, a screen is crashing after an update, or a new feature is rarely completed. You may not need a persistent identifier, a cross-session timeline, a precise location, or a replay of every tap to learn it.

This is an engineering guide, not legal advice. Privacy requirements depend on the product, market, and data involved. The European Commission’s GDPR guidance describes data minimisation as collecting only what is necessary for a defined purpose. That is a useful product-design constraint even when a team is not making a legal assessment.

Start with a decision log

Before adding an event, write the decision it should support. If the team cannot name one, the event does not belong in the product yet.

Question: Are children leaving the new phonics activity before completion?
Decision: Simplify or split the activity if incomplete sessions rise.

Question: Did the latest release introduce a startup failure?
Decision: Prioritise a hotfix if launches fail after the update.

Question: Which individual used the app every morning last month?
Decision: No valid product decision for this product. Do not collect it.

The first two questions have a bounded purpose. The third creates a behavioural profile without a clear need. A decision log makes that difference visible before data collection becomes an implementation detail hidden in a service SDK.

Measure product health, not people

For many product decisions, the useful unit is an aggregate rather than a person.

Imagine a weekly activity summary stored locally or sent as a deliberately small report:

{
  "week_start": "2026-07-20",
  "activity_type": "phonics",
  "completed_count": 37,
  "retry_count": 14,
  "duration_bucket": "1-3m",
  "app_version": "1.4.0"
}

There is no account identifier, advertising identifier, IP address, raw timestamp, or per-session trail. The record can still answer useful questions:

  • Are completions falling after a content change?
  • Does one activity need an easier first step?
  • Did a release increase failure reports for a particular app version?
  • Is a new feature used enough to justify further work?

The absence of a person-level identifier limits what the team can learn. You cannot build a long-term engagement profile, retarget someone who stopped using the app, or inspect one family’s detailed history. That is not a measurement bug. It is the boundary that makes the system easier to justify.

Aggregate does not automatically mean anonymous

It is tempting to label every summary “anonymous” and move on. A small enough group can still be recognisable. A rare event combined with exact time, device details, and version information can become identifying even when a database column is not named user_id.

I treat aggregation as a design technique, not a magic word. The review still asks:

  • Could this record be linked back to a specific person by combining it with another system?
  • Is the reporting group large enough to avoid exposing an unusual outcome?
  • Do we need the exact timestamp, or would a day or week be enough?
  • Do we need a precise duration, or would a bucket answer the same question?
  • How long does the report need to exist before it can be deleted?

The safe answer is usually the less precise one. A weekly total is often more useful than an event stream because it forces the team to think about outcomes rather than every movement inside the product.

Separate diagnostics from behavioural measurement

Crash reports, performance traces, and product metrics often get bundled together because they all look like “analytics” on a procurement page. They serve different purposes and deserve different rules.

Diagnostic data helps answer: “Is the app functioning?” Product measurement helps answer: “Should we change this experience?” Marketing data helps answer: “Who should we persuade to come back?”

Those are not interchangeable needs.

For a privacy-first mobile app, I would keep diagnostics narrowly scoped:

Allowed: app version, operating-system version, error code, coarse device class,
         occurrence count, and a scrubbed stack trace where needed.

Avoided: account identifiers, typed content, message bodies, precise location,
         clipboard data, screen recordings, and a permanent device history.

The point is not to make support impossible. It is to stop a routine crash report from becoming a second analytics system with no clear owner.

Keep the raw event on the device when that is enough

For Tuniri, learning progress is useful to the family using the app. It does not need to become a remote behavioural timeline for the developer. That means the richest data can remain on the device, where it supports the Parent Dashboard and the child’s learning experience.

When a product still needs a broader signal, there are lower-collection options:

  1. Use support requests, app-store reviews, and structured interviews for qualitative feedback.
  2. Generate local summaries that do not include a child profile or event history.
  3. Ask for an explicit, understandable opt-in before sharing a diagnostic report.
  4. Run a short, time-boxed research build rather than leaving a broad event stream on forever.

These methods are slower than opening a funnel dashboard. They also force a product team to be clearer about what it wants to learn and whether the answer is worth collecting.

Make each metric expire

Temporary events have a habit of becoming permanent because removing them is nobody’s named task. I add an expiry to every new measurement:

Metric: phonics_activity_completion
Purpose: validate a revised lesson sequence
Owner: learning experience team
Review date: 2026-10-01
Delete condition: the release decision is complete
Retention: 90-day aggregate only

This changes the discussion from “Can we add tracking?” to “What are we collecting, why, and when do we stop?”

The technical work follows naturally. Put the metric schema in version control. Test that the summary does not include excluded fields. Review any new package and platform permission as part of the feature. Check the release build as well as the Dart source, because an SDK can collect more than its integration code makes obvious.

A practical review for every new signal

Before a new metric goes into a mobile product, I want this checklist answered in writing:

[ ] What product decision will this signal change?
[ ] Can a count, bucket, or aggregate answer the question?
[ ] What identifiers and precise timestamps can be removed?
[ ] Is diagnostic data separated from product measurement?
[ ] Who owns the metric and its deletion date?
[ ] What is the retention period?
[ ] Can someone explain the data flow to a parent or customer in plain language?

If the final question produces a complicated answer, the design probably contains more data than the feature needs.

The trade-off is real, and worth naming

Privacy-first measurement does not produce the same precision as individual tracking. It cannot explain every conversion, recover every lost session, or deliver the kind of highly targeted prompt that follows a person across devices.

That is the trade. In products built around trust, especially products used by children, I would rather accept an incomplete answer than collect a complete record of someone else’s behaviour by default.

The goal is not to have no information. It is to have enough information to make an honest product decision, then stop collecting when the decision has been made.