Skip to content

feat(network-controller): emit RPC service analytics via AnalyticsController#9270

Open
cryptodev-2s wants to merge 3 commits into
mainfrom
feat/network-controller-analytics-events
Open

feat(network-controller): emit RPC service analytics via AnalyticsController#9270
cryptodev-2s wants to merge 3 commits into
mainfrom
feat/network-controller-analytics-events

Conversation

@cryptodev-2s

@cryptodev-2s cryptodev-2s commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Explanation

Today NetworkController emits no analytics. It publishes rpcEndpointUnavailable and rpcEndpointDegraded events, and each client app independently subscribes to them and turns them into the RPC Service Unavailable / RPC Service Degraded Segment events. The extension still routes those through MetaMetricsController; mobile already routes them through AnalyticsController. The handlers are near identical duplication across both repos.

This moves that translation into NetworkController so it is written once and delivered through the AnalyticsController:trackEvent action over the messenger (which is the whole reason AnalyticsController exists). Clients can then delete their duplicated handlers and just wire the new option.

The feature is fully opt in via a new optional analytics constructor option. When omitted, no analytics are emitted and AnalyticsController is never called, so existing consumers are unaffected. The two genuinely client specific pieces are injected because core cannot know them:

  • isRpcEndpointUrlPublic(url): whether an endpoint URL is safe to report verbatim (depends on the client network lists, Quicknode URLs, Infura key)
  • rpcServiceEventsSampleRate: the proportion of events to emit (depends on the build environment, typically 1% in production and 100% in dev)

Core reads analyticsId via AnalyticsController:getState, applies the sample rate with generateDeterministicRandomNumber, skips local connection errors, builds the properties, and delivers the event. AnalyticsController keeps owning consent gating.

What changed

  • New src/rpc-service-events.ts: pure helpers (sanitizeRpcEndpointUrl, buildRpcServiceEventProperties, toAnalyticsTrackingEvent) plus the NetworkControllerAnalyticsOptions and RpcServiceEventName types
  • src/NetworkController.ts: new optional analytics option, widened AllowedActions with AnalyticsController:getState + AnalyticsController:trackEvent, two guarded self subscriptions, and a private #trackRpcServiceEvent
  • Added @metamask/analytics-controller dependency and tsconfig references (no dependency cycle)
  • index.ts, tests/helpers.ts, CHANGELOG.md, and a new tests/NetworkController.analytics.test.ts

Open question

AnalyticsTrackingEvent has no category field, so the old category: 'Network' is not carried for now. Confirming with the analytics owners how they want category mapped before relying on it downstream.

Follow ups (separate repos)

  • metamask-extension: delete messenger-action-handlers.ts + utils.ts, pass the analytics option, delegate the two AnalyticsController actions. This is where the extension stops using MetaMetricsController for these events.
  • metamask-mobile: same deletion and wiring (it already delegates AnalyticsController).

References

N/A

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've highlighted breaking changes using the "BREAKING" category above as appropriate
  • I've manually tested code paths covered by the new tests

Note

Medium Risk
Opt-in analytics on RPC failure paths with URL redaction and sampling, but new cross-controller messenger coupling and consumers must delegate AnalyticsController actions when enabling the feature.

Overview
NetworkController can now turn existing rpcEndpointUnavailable / rpcEndpointDegraded signals into RPC Service Unavailable and RPC Service Degraded analytics in one place, via optional constructor analytics and AnalyticsController:trackEvent (opt-in; default behavior unchanged).

When analytics is set, the controller subscribes to those RPC events and runs #trackRpcServiceEvent: skip local connection errors, require analyticsId from AnalyticsController:getState, apply rpcServiceEventsSampleRate with generateDeterministicRandomNumber, then track. Clients inject isRpcEndpointUrlPublic and the sample rate; messenger must delegate AnalyticsController:getState and AnalyticsController:trackEvent.

New rpc-service-events helpers sanitize endpoint URLs (host vs 'custom'), build event properties (CAIP chain id, optional degraded fields, http_status), and wrap AnalyticsTrackingEvent. @metamask/analytics-controller is added as a dependency; types are exported from the package index. Tests cover helpers and controller analytics wiring (including no-op paths and captureException on failures).

Reviewed by Cursor Bugbot for commit 8697e1f. Bugbot is set up for automated code reviews on this repo. Configure here.

…troller

NetworkController now emits "RPC Service Unavailable" and "RPC Service
Degraded" analytics events itself through the AnalyticsController:trackEvent
action, instead of relying on each client app to translate its
rpcEndpointUnavailable/rpcEndpointDegraded events into MetaMetrics.

The feature is opt in via a new optional `analytics` constructor option.
When omitted, no analytics are emitted and AnalyticsController is never
called. The two client specific pieces stay injected because core cannot
know them: `isRpcEndpointUrlPublic` (depends on the client network lists)
and `rpcServiceEventsSampleRate` (depends on the build environment).

The generic property building, event naming, connection error skipping and
delivery now live in core (src/rpc-service-events.ts), so both clients can
drop their duplicated handlers in follow up PRs.
@cryptodev-2s cryptodev-2s requested review from a team as code owners June 25, 2026 20:19
The build tsconfig flagged passing the `unknown` catch variable to
`captureException`, which expects an `Error`. Cast it, matching the other
captureException call sites. Also regenerate the root README dependency
graph to include the new analytics-controller edge.
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