feat!: track Snap lifecycle analytics events in SnapController#4048
Conversation
Migrates client-side analytics event tracking for Snap install, update, and uninstall flows from the MetaMask clients into SnapController, so all clients get consistent analytics coverage without each having to subscribe to the events separately. The controller now subscribes to its own lifecycle events (snapInstallStarted, snapInstallFailed, snapInstalled, snapUpdated, snapUninstalled) and calls AnalyticsController:trackEvent directly via the messenger, using SnapRegistryController:getMetadata to enrich events with the snap category. Preinstalled Snaps are excluded from tracking.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4048 +/- ##
=======================================
Coverage 98.58% 98.58%
=======================================
Files 425 425
Lines 12371 12410 +39
Branches 1950 1969 +19
=======================================
+ Hits 12196 12235 +39
Misses 175 175 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 473b1d5. Configure here.
Add `preinstalled` flag to `snapInstallStarted` and `snapInstallFailed` event payloads so subscribers can guard against tracking OTA updates of preinstalled Snaps. Add try/catch to all analytics subscribers so exceptions from `AnalyticsController:trackEvent` cannot break install/update flows.
Each event had two separate subscribers — one for lifecycle hooks and one for analytics. Combine them into a single subscriber per event.
| hasProperties: true, | ||
| }); | ||
| } catch (error) { | ||
| logError( |
There was a problem hiding this comment.
What error are we expecting here?
There was a problem hiding this comment.
Good question, may not be necessary to handle this.
Analytics errors should be swallowed silently without logging, matching the pattern used in MetaMask clients.
| await getMockSnapFilesWithUpdatedChecksum({ | ||
| sourceCode: 'a'.repeat(64_000_001), | ||
| }); | ||
| it('throws if the Snap source code is too large', async () => { |
There was a problem hiding this comment.
Why are there indentation changes? 🤔
There was a problem hiding this comment.
This function was outside the installSnaps describe block. 😕
| }); | ||
| ); | ||
|
|
||
| describe('Updating Snaps', () => { |
There was a problem hiding this comment.
Oh, it's added again later, why is the diff so wonky 😵
There was a problem hiding this comment.
Good question, I'm not sure. 😅
| "functions": 98.78, | ||
| "lines": 98.63, | ||
| "statements": 98.32 | ||
| "lines": 98.45, |
There was a problem hiding this comment.
Any ideas why the coverage dropped? 🤔
| const snapController = await getSnapController(options); | ||
|
|
||
| const newSnap = controller.getSnap(MOCK_SNAP_ID); | ||
| options.messenger.publish( |
There was a problem hiding this comment.
Unsure what the best practice is with stuff like this because this test doesn't actually test that it works in connection with an install
There was a problem hiding this comment.
The point of this test is to make sure that if SnapController:snapInstallStarted is dispatched, we call AnalyticsController:trackEvent. We test elsewhere that SnapController:snapInstallStarted is dispatched on install. I can change it if you prefer, but it feels redundant.
There was a problem hiding this comment.
Fair enough, just unsure what would be preferable. Not necessarily against this.
| | SnapControllerSnapInstallStartedEvent | ||
| | SnapControllerSnapInstallFailedEvent | ||
| | SnapControllerSnapInstalledEvent | ||
| | SnapControllerSnapUninstalledEvent |
There was a problem hiding this comment.
Are these not part of SnapControllerEvents?
There was a problem hiding this comment.
They are, so strictly speaking not needed to add it to AllowedEvents. I've always found it somewhat confusing that we don't distinguish between own actions/events and actions/events actually used by the messenger. Do you want me to remove it?
There was a problem hiding this comment.
Are you saying it is preferable to be explicit because we actively subscribe to these events?
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>

Summary
@metamask/analytics-controlleras a dependency and wires upAnalyticsController:trackEventas an allowed messenger action inSnapController.snapInstallStarted,snapInstallFailed,snapInstalled,snapUpdated,snapUninstalled) to emit analytics events, replacing the client-side tracking previously done in the MetaMask extension. Preinstalled Snaps are excluded from all tracking.snap_categoryby callingSnapRegistryController:getMetadata, consistent with the existingSnap Export Usedtracking.installSnaps,Updating Snaps,removeSnap,SnapController:snapInstalled,SnapController:snapUpdated).Breaking changes
trackEventconstructor parameter was removed.New actions
AnalyticsController:trackEventNew events
SnapController:snapInstallStartedSnapController:snapInstallFailedSnapController:snapInstalledSnapController:snapUpdatedSnapController:snapUninstalledThe existing logic for tracking these events in the clients can be removed.
Note
Medium Risk
Breaking API change (removed
trackEvent, new messenger actions/events) affects all SnapController integrators. Analytics behavior moves in-process—misconfigured messengers could drop events or fail at runtime.Overview
Breaking:
SnapControllerno longer accepts atrackEventconstructor hook. Hosts must allowAnalyticsController:trackEventon the messenger and subscribe to the expanded lifecycle events (includingpreinstalledon install start/fail payloads).Snap install/update/uninstall and export usage analytics are emitted inside
SnapControllerby subscribing to its own lifecycle events and callingAnalyticsController:trackEvent, withsnap_categoryfromSnapRegistryController:getMetadata. Preinstalled snaps are skipped for install/update/export events; uninstall is still tracked.Tests and test utilities were updated for the extra messenger calls and new analytics expectations; coverage numbers shifted slightly.
Reviewed by Cursor Bugbot for commit 1b9e382. Bugbot is set up for automated code reviews on this repo. Configure here.