Skip to content

Move gameplay analytics from GA4 to the first-party service #165

Description

@Knorcedger

Problem

Gameplay analytics shipped through consent-denied GA4 in #70, but the property has never surfaced those events. The intended product boundary is now explicit: stonesiegegame.com may use consented GA4 for website traffic, while StoneSiege gameplay statistics must be sent only to a project-operated first-party service.

Today the live game still loads Google Tag Manager and sends app_open, menu_screen, match_start, match_resume, match_end, and campaign completion events to GA4. The private Knorcedger/stonesiege-be repository contains an ingest service, but it is not deployed or connected. The public privacy policy consequently also names the wrong processor for gameplay data.

Scope

  • Productionise and deploy the existing first-party ingest service before changing the client.
  • Replace the web/mobile gameplay GA4 transport with a resilient first-party HTTP sink while preserving the platform-neutral AnalyticsSink boundary and keeping packages/sim untouched.
  • Keep the existing Settings → Share anonymous gameplay stats opt-out; when disabled, send no analytics requests.
  • Retain session-scoped identifiers only, add deduplicating event IDs and match IDs, and send no account, advertising, or persistent device identifier.
  • Add protected aggregate reporting sufficient to answer launches, menu funnel, matches started/finished, duration, outcome, civilisation, difficulty, map size, campaign/chapter, platform, and app version.
  • Remove gameplay-specific GA4 configuration and disclosures while keeping website analytics a separate website concern.
  • Update the website privacy policy, mobile/store documentation, and declarations in the coordinated release.

Acceptance criteria

  • The first-party service is live with health monitoring, validated/bounded ingestion, retention expiry, production CORS, rate limiting, and no stored client IP.
  • app_open, menu_screen, match_start, match_resume, match_end, and campaign_chapter_complete arrive with populated parameters and can be read through protected aggregate reporting.
  • The game makes no request to Google Analytics or Google Tag Manager and contains no gameplay GA measurement ID.
  • Turning off Share anonymous gameplay stats prevents the first-party client from loading/sending; offline or failed analytics never blocks or errors gameplay.
  • Website traffic remains separate and uses GA4 only after website consent.
  • Public privacy/store documentation accurately identifies first-party gameplay collection, infrastructure processors, retention, opt-out, and the absence of advertising/cross-site tracking.
  • npm run check passes and live browser verification covers a practice-match start and resignation.

Delivery order

  1. Backend PR and deployment.
  2. Website policy/consent PR and deployment.
  3. Game client PR and deployment.
  4. Live ingestion, reporting, GA4, and cookie verification.

Tradeoffs

Operating the service adds hosting, database, abuse-prevention, retention, monitoring, and reporting responsibilities. A public open-source client cannot safely hold an ingest secret, so the endpoint must rely on strict schemas, small request limits, CORS, rate limits, idempotency, and monitoring rather than a bundled token. Session-scoped identifiers deliberately cannot provide cross-session retention.

Supersedes the GA4 transport decision in #62 while retaining its event design, opt-out, offline-safety, and disclosure principles.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions