Skip to content

feat: Support clicks and custom event tracing#432

Open
SpennyNDaJets wants to merge 4 commits intomainfrom
spenny/support-product-analytics-tracing
Open

feat: Support clicks and custom event tracing#432
SpennyNDaJets wants to merge 4 commits intomainfrom
spenny/support-product-analytics-tracing

Conversation

@SpennyNDaJets
Copy link
Contributor

@SpennyNDaJets SpennyNDaJets commented Mar 25, 2026

Summary

Support tracing for the following product analytics events

  • Clicks
  • PageViews
  • LD.track

Make sure to add the LD context to each of these traces

Note:

  • Removes support for otel eventNames
  • Passes in full url for clicks to better support search

How did you test this change?

  1. Run the react router e2e app
  2. Make sure the client is running
  • Clicks are recorded with correct info
  • PageViews are recorded with correct info
  • Custom events are recorded with correct info

https://www.loom.com/share/e112659086f94a228279a97cc2b690b7

Are there any deployment considerations?

Breaking change: removal of event_names


Note

Medium Risk
Medium risk because it changes the OpenTelemetry instrumentation surface area (removes otel.eventNames and adds new history/location patching) and alters what events/spans are emitted, which can affect downstream analytics and performance.

Overview
Adds product analytics tracing to the observability SDK: click spans (with full URL), page-view spans via new LocationChangeInstrumentation, and optional LD.track spans controlled by a new productAnalytics option.

Removes support for configuring user-interaction spans via otel.eventNames, and threads LaunchDarkly context keys into these product-analytics spans/logs by persisting context keys on afterIdentify and attaching them to click/page-view/track spans.

Updates the React Router e2e app to exercise the new behavior (new /ldclient and /ldclient-lazy routes/pages, plus updated staging OTLP/backend endpoints and anonymous LD context).

Written by Cursor Bugbot for commit 1a76688. This will update automatically on new commits. Configure here.

export const LD_INITIALIZE_EVENT = '$ld:telemetry:session:init'
export const LD_TRACK_EVENT = '$ld:telemetry:track'
export const LD_TRACK_SPAN_NAME = 'launchdarkly.track'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

How the name will be displayed in traces

})
}

this.observe?.recordLog('LD.track', 'info', trackAttrs)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we still want a log?

@SpennyNDaJets SpennyNDaJets changed the title Feat: Support clicks and custom event tracing feat: Support clicks and custom event tracing Mar 25, 2026
@SpennyNDaJets SpennyNDaJets marked this pull request as ready for review March 26, 2026 15:00
@SpennyNDaJets SpennyNDaJets requested a review from a team as a code owner March 26, 2026 15:00
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

private _productAnalyticsEvents(): ProductAnalyticsEvents {
const pa = this._options?.productAnalytics
if (pa === false) {
return {}
Copy link

Choose a reason for hiding this comment

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

Disabling product analytics still tracks clicks and page views

Medium Severity

When productAnalytics is false, _productAnalyticsEvents() returns {} (empty object). Downstream consumers check config.productAnalyticsEvents?.clicks !== false and config.productAnalyticsEvents?.pageViews !== false, which both evaluate to undefined !== falsetrue. This means click tracking and page view tracking remain enabled even when the user explicitly opts out by setting productAnalytics: false. The empty object needs to explicitly set clicks: false, pageViews: false, and trackEvents: false for the opt-out to propagate correctly.

Additional Locations (1)
Fix in Cursor Fix in Web

}
}
return paEvents
}
Copy link

Choose a reason for hiding this comment

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

Duplicated _productAnalyticsEvents method across two files

Low Severity

_productAnalyticsEvents() is implemented identically in both ObserveSDK and the Highlight client class. This duplication means any bug fix (such as the productAnalytics: false issue) needs to be applied in two places, increasing the risk of divergent behavior over time. Extracting this into a shared utility function would reduce maintenance burden.

Additional Locations (1)
Fix in Cursor Fix in Web

@@ -45,8 +45,13 @@ export const FEATURE_FLAG_VARIATION_INDEX_ATTR = `${FEATURE_FLAG_SCOPE}.result.v
export const FEATURE_FLAG_APP_ID_ATTR = `${LD_SCOPE}.application.id`
export const FEATURE_FLAG_APP_VERSION_ATTR = `${LD_SCOPE}.application.version`

export const PRODUCT_ANALYTICS_SCOPE = 'product_analytics'
export const PRODUCT_ANALYTICS_CONTEXT_ATTR = `${PRODUCT_ANALYTICS_SCOPE}.context_keys`
Copy link
Contributor

Choose a reason for hiding this comment

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

question: Do we want the context information under the product_analytics scope? At least in a spans attributes.

I imagine the context being a more generic attribute which we can add to spans across various use cases, so I prefer not locking it into PA even though it fits for this instance.

Maybe context.context_keys.<key>?

* User interaction instrumentation event names to record.
* Defaults to 'click', 'input', 'submit' window events.
*/
eventNames?: EventName[]
Copy link
Contributor

Choose a reason for hiding this comment

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

Double checking, this is ok to remove?

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