Skip to content

fix(identify): keep identify running while opted out - #167

Merged
ioannisj merged 3 commits into
mainfrom
fix/identify-runs-while-opted-out
Nov 5, 2026
Merged

ioannisj merged 3 commits into
mainfrom
fix/identify-runs-while-opted-out

Conversation

@ioannisj

@ioannisj ioannisj commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Problem

identify lists "the user is opted out" as a guard that short-circuits the whole call, and opt-in says opt-out short-circuits identify. posthog-js and posthog-android don't do that. Their identify keeps going while opted out: it updates local identity and reloads flags. The only thing opt-out drops is the event.

  • posthog-js identify() (packages/browser/src/posthog-core.ts:3327) only returns early for an uninitialized SDK, an invalid id, or _requirePersonProcessing. Opt-out is enforced in capture() (posthog-core.ts:1795). The person-properties hash only gets cached if capture() accepted the event (posthog-core.ts:3411-3424). Flags reload when the distinct id changes (posthog-core.ts:3456-3461).
  • Flag loading doesn't depend on opt-out anymore: "Feature flag loading is no longer gated by capture opt-out" (posthog-js#3596 comment).
  • posthog-android identify() (PostHog.kt:1592) has no opt-out check. Opt-out is enforced in capture() (PostHog.kt:972).

bootstrap already says the same thing: "opt-out suppresses event emission, not the local identity state".

Changes

  • identify: the requirement now says client SDKs must not short-circuit identify on opt-out. While opted out, identify updates local identity state and person properties for flags, and reloads flags when the distinct id changes. It doesn't capture $identify / $set, and it doesn't update the dedup hash for an event it didn't capture. In the Behavior section, opt-out comes out of the step 1 guards and the Error handling drop list.
  • Two new @client scenarios:
    • identify while opted out changes the distinct id, sends a flags request for the new id, and enqueues nothing
    • after opt-in, identifying again with the same properties still sends $set, because the opted-out call didn't cache the hash
  • opt-in: optOut step 3 and Interactions now say opt-out blocks the event, and that identify still updates identity and reloads flags. What they say about capture / group / alias is unchanged.
  • acceptance/public/identify.feature: the same two scenarios, built only from existing steps.
  • Archived as openspec/changes/archive/2026-11-02-fix-identify-runs-while-opted-out/.

Reference coverage is partial. posthog-js defaultOptOutScenario (packages/browser/src/__tests__/browser-next-differential/scenarios.ts:126) checks identity state and that no event goes out while opted out, but its harness disables flags (legacy-browser-adapter.ts:54), so nothing in the reference suite covers the flags reload. The hash rule is covered by personProcessing.test.ts:1051, with the event dropped by before_send rather than opt-out.

Where other SDKs stand on the hash rule:

  • posthog-android passes the opt-in scenario, but in the same-id anonymous-to-identified transition it caches the hash even when capture() dropped the event (PostHog.kt:1693).
  • posthog-react-native (posthog-js packages/core) already keeps identity and flags running while opted out, but it caches the hash on a new distinct id regardless (packages/core/src/posthog-core.ts:399), so it fails the opt-in scenario.
  • posthog-ios is picking up the same fix separately.

Testing

openspec validate --specs --strict --no-interactive: 68 passed, 0 failed.

Agent context

DRI: @ioannisj
Autonomy: Human-driven (agent-assisted)

@ioannisj
ioannisj marked this pull request as ready for review November 2, 2026 12:31
@ioannisj
ioannisj requested a review from a team as a code owner November 2, 2026 12:31
@ioannisj
ioannisj requested review from a team and removed request for a team November 3, 2026 13:17
@ioannisj
ioannisj merged commit 9e48a52 into main Nov 5, 2026
10 checks passed
@ioannisj
ioannisj deleted the fix/identify-runs-while-opted-out branch November 5, 2026 06:31
andehen added a commit to PostHog/posthog-sdk-test-harness that referenced this pull request Nov 5, 2026
The new sdk-specs pin adds scenarios that the companion tests count:

- on-feature-flags.feature gains a client-only failed-load listener
  scenario (PostHog/sdk-specs#94), so the server profile sees 4
  not-applicable cases.
- identify.feature gains two client-only opted-out identify scenarios
  (PostHog/sdk-specs#167), so the feature set has 11 cases.
- evaluate-flags.feature gains seven "Server snapshot" event opt-out
  scenarios tagged @server, not @SDK:server (PostHog/sdk-specs#111).
  The snapshot matrix now selects only @SDK:server scenarios, the same
  scope as the acceptance suite, so it keeps its 21 cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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