Skip to content

feat: add trackEvent for custom pipeline events#384

Merged
talissoncosta merged 11 commits intofeat/send-evaluation-data-to-analytics-pipelinefrom
feat/track-event-custom-pipeline
Mar 25, 2026
Merged

feat: add trackEvent for custom pipeline events#384
talissoncosta merged 11 commits intofeat/send-evaluation-data-to-analytics-pipelinefrom
feat/track-event-custom-pipeline

Conversation

@talissoncosta
Copy link
Copy Markdown
Contributor

@talissoncosta talissoncosta commented Mar 17, 2026

Summary

  • Add trackEvent(eventName, metadata?) public method to send custom events through the evaluation analytics pipeline (v1/analytics/batch)
  • Events are sent immediately with the current identity (or null if anonymous) — no buffering
  • Pipeline-only: requires evaluationAnalyticsConfig; no-op otherwise
  • Add PipelineEventType enum (FLAG_EVALUATION, CUSTOM_EVENT) to replace magic strings, exported from index.ts for consumer access
  • Unify event building into shared buildAnalyticEvent method for both flag evaluations and custom events
  • Rename sdkMetadatagetEventMetadata, reuse currentTraitsSnapshot across event types
  • Make pipeline analytics properties private
  • Uses Record<string, unknown> instead of Record<string, any> for metadata, enforcing type narrowing on consumers

Test plan

  • Unit tests (8 new): correct event shape, no-op guards (no config, empty name), null identity when anonymous, identity after identify, flush on flushInterval === 0, no deduplication, null identity after logout
  • All 84 tests pass (no regressions)
  • Manual E2E validation with Angular playground app + local echo server

@talissoncosta talissoncosta marked this pull request as ready for review March 17, 2026 20:35
@talissoncosta talissoncosta requested a review from a team as a code owner March 17, 2026 20:35
@talissoncosta talissoncosta requested review from kyle-ssg and removed request for a team March 17, 2026 20:35
@talissoncosta talissoncosta linked an issue Mar 19, 2026 that may be closed by this pull request
@Zaimwa9 Zaimwa9 self-requested a review March 23, 2026 08:04
@Zaimwa9 Zaimwa9 self-assigned this Mar 23, 2026
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

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

Thanks for picking this up. 2 main comments:

  • One related to the identifying behavior of the custom events and the risk of loosing them (or relevant non-identified context)
  • Some comments to avoid code repetition

Additionally, i'll work now on removing the trimPipelineBuffer as described here as I think it can definitely get improved

}
}

private buildCustomEvent(eventName: string, identityIdentifier: string | null, metadata?: Record<string, unknown>, timestamp?: number): IPipelineEvent {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should extract the whole logic from here :

and be able to use the buildCustomEvent with both FLAG_EVALUATION and CUSTOM_EVENT

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Including using get sdkMetadata for the above. NIT: As it also includes the page_url we could rename it into something like getEventMetadata and also rename buildCustomEvent into buildAnalyticEvent

Same with currentTraitsSnapshot that could replace my previous inline ternary

Copy link
Copy Markdown
Contributor Author

@talissoncosta talissoncosta Mar 23, 2026

Choose a reason for hiding this comment

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

Makes sense, both build the same IPipelineEvent shape. I'll consolidate into a single shared method that takes event_type as a parameter.

Agreed — getEventMetadata and buildAnalyticEvent are more accurate now that they serve both event types. I'll also reuse currentTraitsSnapshot in the flag evaluation path to replace the inline ternary.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@talissoncosta talissoncosta requested a review from Zaimwa9 March 23, 2026 14:12
Copy link
Copy Markdown
Contributor

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

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

Thanks for the changes. Ready to approve after rebase + one nit

* Requires `evaluationAnalyticsConfig` to be set; no-op otherwise.
* Events are sent with the current identity (or null if anonymous).
* @experimental Internal use only — API may change without notice.
* @hidden
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

just missing the internal tag here too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks @Zaimwa9
Fixed in: 2849346

talissoncosta and others added 9 commits March 24, 2026 09:23
Add trackEvent(eventName, metadata?) to the public type definitions,
allowing custom events to be sent through the evaluation analytics pipeline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add trackEvent method that sends custom_event through the analytics
pipeline batch endpoint. Events tracked before identify() are buffered
in pendingCustomEvents and drained once identity is set, preserving
original timestamps. Pending events are cleared on logout.

Includes helper methods (getPageUrl, currentTraitsSnapshot, sdkMetadata,
buildCustomEvent) to keep the implementation clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cover custom event shape, no-op without config, no-op with empty name,
queue-before-identify with drain, immediate flush when flushInterval is 0,
no deduplication, timestamp preservation, cleanup on logout, and pending
buffer maxBuffer cap.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… trackEvent

Use the stricter Record<string, unknown> for user-provided metadata,
which forces consumers to narrow values before using them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace string literals 'flag_evaluation' and 'custom_event' with
PipelineEventType.FLAG_EVALUATION and PipelineEventType.CUSTOM_EVENT
to avoid magic strings and ensure type safety.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace 'custom_event' string literals with PipelineEventType.CUSTOM_EVENT
  in test assertions and helpers
- Export PipelineEventType from index.ts for consumer access
- Add test for identify → logout → track cycle to verify state resets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mark evaluationAnalyticsUrl, evaluationAnalyticsMaxBuffer, pipelineEvents,
pipelineAnalyticsInterval, isPipelineFlushing, pipelineRecordedKeys, and
pendingCustomEvents as private to prevent external access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Custom events are now sent immediately with the current identity
(or null if anonymous), instead of being buffered until identify()
is called. This prevents events from being silently lost when
identify() is never called and supports anonymous tracking use cases
(e.g. public pages, pre-login).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract shared buildAnalyticEvent method that handles both
FLAG_EVALUATION and CUSTOM_EVENT types, replacing the separate
buildCustomEvent and inline event construction in recordPipelineEvent.

Rename sdkMetadata to getEventMetadata (includes page_url, not just SDK
info) and reuse currentTraitsSnapshot in the flag evaluation path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@talissoncosta talissoncosta force-pushed the feat/track-event-custom-pipeline branch from ffa2f7f to 3879f71 Compare March 24, 2026 12:26
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@talissoncosta talissoncosta requested a review from Zaimwa9 March 24, 2026 12:31
@Zaimwa9
Copy link
Copy Markdown
Contributor

Zaimwa9 commented Mar 24, 2026

@talissoncosta Sorry just missing the latest code from feat/send-evaluation-data-to-analytics-pipeline that removed the trimPipelineBuffer (to remove the callsites in this branch) and integrated into flushPipelineAnalytics

Remove trimPipelineBuffer, aligning with parent branch (36066b2).
Add buffer overflow flush condition to trackEvent, matching the
approach in recordPipelineEvent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@talissoncosta talissoncosta force-pushed the feat/track-event-custom-pipeline branch from 2efe60e to ca2ed55 Compare March 24, 2026 17:19
@talissoncosta
Copy link
Copy Markdown
Contributor Author

Thanks for flagging that @Zaimwa9
Fixed it in: ca2ed55

@talissoncosta talissoncosta merged commit 0e819eb into feat/send-evaluation-data-to-analytics-pipeline Mar 25, 2026
3 checks passed
@talissoncosta talissoncosta deleted the feat/track-event-custom-pipeline branch March 25, 2026 16:17
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.

Track evaluation analytics custom events

2 participants