Skip to content

fix: send persisted anonymousId and userId with telemetry events - #56

Open
claudiacodacy wants to merge 1 commit into
masterfrom
fix/telemetry-stable-ids
Open

claudiacodacy wants to merge 1 commit into
masterfrom
fix/telemetry-stable-ids

Conversation

@claudiacodacy

Copy link
Copy Markdown
Contributor

Problem

The Segment Kotlin SDK (1.21.0) stores its own anonymousId and userId in /tmp/analytics-kotlin/<writeKey>/ (StorageImpl.kt). /tmp is cleared on reboot, so after every restart:

  • the install gets a new anonymousId and counts as a new install
  • a signed-in user's events go out without a userId until they log in again

The plugin already persists a stable anonymousId and the userId in CodacyPluginSettings.xml (Config.kt), but only sends them inside the event properties, not as the message's own ids.

What this looks like in the warehouse (jetbrains_ides, last 90 days):

VS Code JetBrains
Anonymous ids seen on one day only 23% 60%
Average active days per anonymous id 15.5 3.0

Only ~16% of JetBrains events carry a user_id, so JetBrains install counts are inflated and install-based retention can't be measured.

Fix

Add a Segment enrichment plugin that sets anonymousId, and userId when signed in, on every event from the persisted plugin settings.

Testing

  • Not compiled locally: there's no JDK 17 on the machine this was written on, and there's no CI build for PRs. Please run ./gradlew buildPlugin before merging.
  • After a release, check jetbrains_ides.tracks: anonymous_id should stay the same across IDE restarts and reboots, and user_id should be set for signed-in users.

Related: OD-700 (IDE telemetry).

🤖 Generated with Claude Code

The Segment SDK stores its own anonymousId and userId under
/tmp/analytics-kotlin/<writeKey>, which is cleared on reboot. Every
restart showed up as a new install, and signed-in users lost their
userId until the next login. Set both ids on every event from the
plugin's persisted settings instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claudiacodacy
claudiacodacy marked this pull request as ready for review October 7, 2026 17:03
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.

Run reviewer

TIP This summary will be updated as you push new changes.

@codacy-production codacy-production Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

The event enrichment can send a stale authenticated userId after sign-out because a null persisted userId does not clear the existing event identity. This should be fixed before merging.

All required identity and plugin-registration test scenarios are missing, leaving the acceptance criteria unverified. Codacy reports the PR as up to standards.

About this PR

  • Add automated tests covering persisted identity enrichment, sign-out behavior, and plugin registration before merging.

Test suggestions

  • Verify events receive the persisted anonymousId after analytics SDK storage is cleared or unavailable
  • Verify signed-in users’ events receive the persisted userId
  • Verify unsigned users’ events do not retain or send a stale userId
  • Verify the enrichment plugin is registered and executes for tracked events
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Verify events receive the persisted anonymousId after analytics SDK storage is cleared or unavailable
2. Verify signed-in users’ events receive the persisted userId
3. Verify unsigned users’ events do not retain or send a stale userId
4. Verify the enrichment plugin is registered and executes for tracked events

TIP Improve review quality by adding custom instructions
TIP How was this review? Give us feedback

override fun execute(event: BaseEvent): BaseEvent {
val state = Config.instance.state
event.anonymousId = state.anonymousId
state.userId?.let { event.userId = it.toString() }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MEDIUM RISK

Clear the event identity when the persisted userId is absent so logout cannot send a stale SDK userId.

Suggested change
state.userId?.let { event.userId = it.toString() }
event.userId = state.userId?.toString()

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.

1 participant