Lesson 213: Privacy-Safe Telemetry Session Receipt Without PII (2026)

Direct answer: Wire game_session_started (or your first session event) with properties build_label and surface only—then file telemetry_session_receipt_v1.json on BUILD_RECEIPT so facilitators can prove which depot players ran without collecting PII. Continues Lesson 212 save slot labels; pairs the PostHog beginner pipeline (evening wire-up) with live-ops receipt discipline.

Lesson hero for privacy-safe telemetry session receipt without PII

Why this matters now (July 2026 privacy audits)

July 2026 teams enable analytics the same week they promote fest_public builds. GDPR second-wave audits and Google Play Data Safety reviews ask what you collect—not whether PostHog is “anonymous enough” by marketing copy. Common failures:

  1. Steam ID in event properties — links playtest and fest sessions to accounts (PII when joined).
  2. IP retention — PostHog geolocation on by default ($ip: null required).
  3. No surface dimension — dashboards cannot separate playtest_invite from fest_public after Lesson 211 isolation.

This lesson is the course milestone for telemetry_session_receipt_v1.json—not a repeat of the ninety-minute blog tutorial.

Beginner path (35-minute receipt pass)

Step Action Success check
1 Copy VERSIONbuild_label property Matches BUILD_RECEIPT row
2 Add surface enum playtest_invite | fest_public | gx_public
3 Fire game_session_started once Live Events in PostHog
4 Confirm no PII properties Schema audit GREEN
5 Write release-evidence/privacy.md one-pager Linked from About
6 File telemetry_session_receipt_v1.json T1–T6 pass

Time: ~35 minutes after PostHog project exists; 50 minutes first self-hosted vs cloud decision.

Developer path (gates T1–T6)

Gate Check Fail when
T1 build_label on every session event Missing or hand-typed per build
T2 surface matches playtest scope map fest events tagged playtest_invite
T3 PII denylist enforced steam_id, email, ip, player_name present
T4 $ip: null on capture payload IP geolocation enabled
T5 Opt-in / opt-out documented No functional toggle when EU skew
T6 telemetry_session_receipt_v1.json promotion_allowed: false

Allowed session event schema

Event name: game_session_started (or one agreed name—do not fork per engineer).

Allowed properties:

Property Type Example Notes
build_label string fest-demo-2026-10-rc1 From repo VERSION
surface string fest_public Matches facilitator contract
session_index int 3 Install-local counter only

Forbidden on session events: steam_id, discord_id, email, player_name, country_code from IP, hardware_id, free-text chat.

Godot 4.5 capture snippet (reference)

func _emit_session_started(surface: String) -> void:
    Telemetry.capture("game_session_started", {
        "build_label": ProjectSettings.get_setting("application/config/version"),
        "surface": surface,
        "session_index": _session_index
    }, ip_null := true)

Unity: same properties on TelemetryClient.Capture; set PostHog $ip null per blog Recipe A.

telemetry_session_receipt_v1.json

{
  "schema": "telemetry_session_receipt_v1",
  "build_label": "fest-demo-2026-10-rc1",
  "analytics_backend": "posthog_cloud_eu",
  "session_event_name": "game_session_started",
  "allowed_properties": ["build_label", "surface", "session_index"],
  "pii_denylist_enforced": true,
  "ip_collection_disabled": true,
  "opt_in_pattern": "region_aware_default",
  "privacy_posture_path": "release-evidence/privacy.md",
  "paired_receipts": {
    "save_slot_label": "release-evidence/saves/SAVE_SLOT_LABEL_RECEIPT.json",
    "facilitator_contract": "release-evidence/facilitator/FACILITATOR_CONTRACT_RECEIPT.json"
  },
  "gates": {
    "T1_build_label_on_session": "pass",
    "T2_surface_dimension": "pass",
    "T3_pii_denylist": "pass",
    "T4_ip_null": "pass",
    "T5_opt_in_documented": "pass",
    "T6_receipt": "pass"
  },
  "live_events_proof_capture_id": "posthog-live-2026-05-25-abc",
  "promotion_allowed": true
}

Pin under release-evidence/telemetry/TELEMETRY_SESSION_RECEIPT.json.

BUILD_RECEIPT columns

Column Value
telemetry_session_receipt Path + pass/fail
build_label Matches upload logs
surface Primary production surface
save_slot_label_receipt Lesson 212 when saves ship

Thursday row review — add Telemetry row: denylist + Live Events screenshot ID.

Proof table (session audit)

surface build_label Live Events seen? PII scan Ship?
playtest_invite playtest-2026-07-rc1 yes pass soak only
fest_public fest-demo-2026-10-rc1 yes pass after T6

Key takeaways

  1. build_label + surface are the minimum viable session dimensions for multi-channel fest ops.
  2. Receipt proves schema, not that you “use PostHog”—Live Events ID is evidence.
  3. Denylist is code-enforced—review event JSON in CI, not honor system.
  4. Lesson 212 saves and Lesson 213 telemetry are independent trust lanes—both belong on BUILD_RECEIPT.
  5. Crash correlation (214) and refund dashboard (215) assume T1–T2 are already GREEN.
  6. Pair playtest isolation runbooks for scope vocabulary.
  7. AI dialogue moderation (216) must not log player prompts in telemetry—keep NPC patches out of analytics.
  8. Blog pipeline teaches wire-up; this lesson teaches promotion gate.

Prerequisites

Common mistakes

  • Logging steam_id “for debugging.”
  • Using distinct_id = Steam account hash.
  • Skipping surface because “we only have one build.”
  • Shipping telemetry before privacy.md exists.
  • Mixing chat moderation logs into PostHog.

Troubleshooting

Symptom Lane
Events missing build_label T1 + VERSION spine
Playtest traffic in fest funnel T2 + scope map
GDPR question from publisher Blog opt-in patterns + privacy.md
Wrong depot in reviews Lesson 212 + 206, not telemetry alone

Mini exercise (50 minutes)

  1. Add denylist unit test rejecting steam_id property.
  2. Emit session on playtest build; verify surface in Live Events.
  3. Repeat on fest build; distinct build_label.
  4. File receipt; screenshot Live Events UUID into live_events_proof_capture_id.
  5. Update BUILD_RECEIPT row before Wednesday smoke.

Next: Lesson 214 — crash symbolicate + build_label correlation.

Continuity — H1 2026 arc (212–217)

Lesson Receipt focus
212 Save slot labels
213 (this) Telemetry session without PII
214 Crash + build_label
215 Refund signals
216 AI dialogue patch
217 H1 capstone

FAQ

Replace the PostHog blog tutorial?
No—blog is wire-up; this lesson is BUILD_RECEIPT gate for fest promotion.

Can we add level_id later?
Yes—extend allowlist in receipt semver bump; session event stays minimal until T6 passes.

Self-hosted PostHog?
Set analytics_backend accordingly; T3–T4 rules unchanged.

Web HTML5 itch build?
Same build_label + surface; use anonymous distinct_id per blog—never itch username. For Construct GA4 funnel events, pair playtest analytics preflight with Lesson 241 construct playtest analytics receipt.


Prove session telemetry with build_label and surface only—or pause fest analytics until privacy auditors see the receipt.