Skip to content

Privacy policy is listener-scoped and blocks both DJ apps' store submissions #228

Description

@jakebromberg

Problem

pages/privacy.js is listener-scoped and says, twice, that WXYC collects no personally identifiable information:

Our website, Android app, and iOS app collect anonymous analytics data to help us understand performance and usage trends. This data does not include personally identifiable information. — §2

No personally identifiable information is collected or used for marketing or advertising. — §3

That was true when the only apps were the listener apps, where users are anonymous. It is false for the two DJ apps, which authenticate a named individual against dj.wxyc.org, hold a session token and a JWT in encrypted device storage, and act on a per-DJ record (/djs/bin). A DJ's username, email, and DJ id are personally identifiable by any reading of the term.

This is not a hygiene issue. Both app stores require the linked privacy policy to match the store's data-safety declaration:

  • Google Play Data Safetywxyc-dj-android cannot be submitted for review with a declaration that contradicts its linked policy.
  • Apple App Store privacy labels — the same for wxyc-dj-ios, which is already built.

Both apps link to this one page, so this single file is a submission blocker for both.

Desired end state

pages/privacy.js distinguishes the listener apps from the DJ apps and states accurately, for the DJ apps, what identifying data is collected, why, where it is stored, and that it is not used for advertising. The page remains a single document — the goal is one policy that covers four apps honestly, not four policies that can drift.

Where

  • pages/privacy.js — the whole file is ~60 lines of JSX with <h2>-numbered sections. Sections 2 (Information Collection), 3 (Data Usage), and 4 (Third-Party Services) all need amending; section 1 (Introduction) currently enumerates "our website, Android app, and iOS app" and needs to name the DJ apps too.
  • The Last updated: line (currently March 18, 2025) must be bumped.

What the DJ apps actually do — write the policy from this, not from assumption

Confirmed against wxyc-dj-ios and wxyc-dj-android as built:

  • Authentication. A DJ signs in with a dj.wxyc.org username or email, by password or by a mailed one-time code. Backend-Service issues a session token; the app exchanges it for a JWT.
  • Storage. Both tokens live in device-local encrypted storage only (iOS Keychain, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, no iCloud sync; Android encrypted token storage). Not synced, not backed up off-device.
  • Identifiers in the JWT. DJ id, email, role.
  • Per-DJ data. The bin (/djs/bin) is a per-DJ record on Backend-Service.
  • Telemetry — and this is the part most likely to be got wrong. The DJ apps' error reporting is deliberately stricter than the listener apps', and the policy should not over-declare. wxyc-dj-ios ships Sentry under a contract that is enforced at compile time, not by review convention: sendDefaultPii off, no screenshots, no view hierarchy, no session replay, no tracing, and error context restricted to types that structurally cannot carry free text. URLs are stripped of query and fragment before an event leaves the device. See wxyc-dj-ios/docs/adr/0007-ios-anonymous-error-reporting.md for the full contract and the three leak channels it closes. Read that ADR before writing the telemetry sentences — declaring "we collect crash reports containing personal data" would be inaccurate in the other direction and would create a Data Safety declaration the app does not match.
  • Analytics. wxyc-dj-ios sends analytics into dj-site's PostHog project (444958) with personProfiles = .never. Org-level context is in WXYC/CLAUDE.md.

Constraints

  • One page, four apps. Do not fork a separate DJ policy. Two policies drift, and the drift surfaces as a store rejection months later.
  • The listener apps' existing claims stay true and should stay on the page — the fix is to scope them, not delete them.
  • The DJ apps are internal tools for station staff, not consumer products; the policy should say who the DJ apps are for.
  • Deployment: this site is on GitHub Pages, so the change is live on merge. Nothing to coordinate with an app release.

Acceptance criteria

  • §1 names all four apps and distinguishes listener from DJ
  • §2 and §3 scope the "no personally identifiable information" claims to the listener apps, and state accurately what the DJ apps collect
  • The DJ-app section covers: sign-in identifiers, token storage being device-local and encrypted, the per-DJ bin, and the telemetry posture as actually implemented per ADR 0007
  • §4 remains accurate for third parties (PostHog; Sentry for the DJ apps)
  • Last updated: bumped
  • The page renders (npm run build) and reads as one coherent document
  • Someone filling in Play Data Safety / App Store privacy labels can answer every question from this page without guessing

Related

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions