Skip to content

fix(app): stop sending the relay's session identity to analytics - #1839

Open
ethicnology-agent wants to merge 1 commit into
slopus:mainfrom
ethicnology-agent:fix/app-analytics-drops-server-session-identity
Open

ethicnology-agent wants to merge 1 commit into
slopus:mainfrom
ethicnology-agent:fix/app-analytics-drops-server-session-identity

Conversation

@ethicnology-agent

Copy link
Copy Markdown

Fixes the analytics part of #1833. The other two parts of that issue are deliberately left alone — see the scope note at the end.

Problem

PRIVACY.md:24,31 states that analytics events use an anonymised id and that "we cannot match this back to any user or account".

session_switched sends four properties that defeat it:

tracking?.capture('session_switched', {
    session_id: session.id,
    session_created_at: session.createdAt,
    last_active_at: session.activeAt,
    last_updated_at: session.updatedAt,
});

The distinct id really is unlinkable on its own — it is derived from the account secret. But session_id is the relay's own Session primary key, and the three timestamps are the server's own columns (schema.prisma:98). Anyone holding both the PostHog profile and the database can join one to the other, which is the exact operation the policy says is impossible. The unlinkability of the identifier does not help when the properties are server-owned keys.

session_switched is the only event that does this. Every other event in sources/track/index.ts sends flags, enumerations or client versions — I checked all of them.

What this changes

The four properties go, and the parameter goes with them so the identity cannot drift back in through a future caller. The event still counts a switch, which is what it was added for.

  • sources/track/index.ts — trackSessionSwitched() takes nothing and captures a bare event; the now-unused Session type import is dropped.
  • Two call sites lose the argument. The if (session) guard stays, because "only count a switch to a session that exists" is still the intent.
  • sources/track/index.test.ts (new) — asserts the event carries no properties at all, with a comment recording why.
  • useNavigateToSession.test.ts — the existing assertion no longer expects an argument.

Verified red/green: against the current event both new cases fail; with the change, sources/track/ and useNavigateToSession pass 13/13, tsc --noEmit is clean, and the app suite is 1899 passed / 1 skipped.

One pre-existing failure is unrelated and not introduced here: sources/components/sessionPresentation.test.ts fails to collect with ReferenceError: __DEV__ is not defined, on origin/main as well as on this branch.

If you want per-session funnels back

They need an identifier the relay cannot compute — a random value generated on the device, stored locally, never sent to the server. I did not add one, because whether that trade is worth making is your call, not mine, and it is a different change.

Scope: what this does not touch

#1833 reports three gaps between PRIVACY.md and the code. This PR closes one.

  • Push notification content. Making the body content-free is a small code change, but it costs users informative notifications. That is a product trade-off you should decide, not something to slip into a privacy fix.
  • The missing account-deletion path. That is a feature — an endpoint, a cascade across every account-owned relation, and client UI. It needs its own design.

I have also not edited PRIVACY.md. For this path the text is now accurate again; for the other two, whether the code or the policy moves is your decision.

session_switched carried the relay's own Session primary key and three exact
server-side timestamps: createdAt, activeAt and updatedAt. PRIVACY.md states
that analytics events use an anonymised id and cannot be matched back to any
user or account. The distinct id is indeed unlinkable on its own, derived
from the account secret, but those four properties join straight back to the
Session table, so the pair re-identified the profile and the claim did not
hold.

Drop them. The event still counts a switch, which is what it was added for.
Per-session analysis, if it is wanted later, needs an identifier the relay
cannot compute - a client-generated value stored only on the device - rather
than the server's own key.

The parameter goes with the properties so the identity cannot drift back in
through a future caller.

session_switched was the only event carrying a server-owned identifier; every
other one sends flags, enumerations or client versions.
@ethicnology-agent
ethicnology-agent force-pushed the fix/app-analytics-drops-server-session-identity branch from fea83e9 to e909b8f Compare October 1, 2026 19:02
@ethicnology-agent

Copy link
Copy Markdown
Author

Rebased onto current main (4cf54d1). Clean rebase, diff unchanged.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants