Skip to content

feat!: track Snap lifecycle analytics events in SnapController#4048

Merged
Mrtenz merged 6 commits into
mainfrom
mrtenz/snap-controller-analytics
Jun 25, 2026
Merged

feat!: track Snap lifecycle analytics events in SnapController#4048
Mrtenz merged 6 commits into
mainfrom
mrtenz/snap-controller-analytics

Conversation

@Mrtenz

@Mrtenz Mrtenz commented Jun 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds @metamask/analytics-controller as a dependency and wires up AnalyticsController:trackEvent as an allowed messenger action in SnapController.
  • Subscribes to the controller's own lifecycle events (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.
  • Enriches each event with snap_category by calling SnapRegistryController:getMetadata, consistent with the existing Snap Export Used tracking.
  • Adds tests for each analytics event, grouped into the relevant existing describe blocks (installSnaps, Updating Snaps, removeSnap, SnapController:snapInstalled, SnapController:snapUpdated).

Breaking changes

  • Clients must update their root messenger's allowed actions and events to include the new entries.
  • The trackEvent constructor parameter was removed.

New actions

  • AnalyticsController:trackEvent

New events

  • SnapController:snapInstallStarted
  • SnapController:snapInstallFailed
  • SnapController:snapInstalled
  • SnapController:snapUpdated
  • SnapController:snapUninstalled

The 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: SnapController no longer accepts a trackEvent constructor hook. Hosts must allow AnalyticsController:trackEvent on the messenger and subscribe to the expanded lifecycle events (including preinstalled on install start/fail payloads).

Snap install/update/uninstall and export usage analytics are emitted inside SnapController by subscribing to its own lifecycle events and calling AnalyticsController:trackEvent, with snap_category from SnapRegistryController: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.

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.
@socket-security

socket-security Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​metamask/​analytics-controller@​1.1.1981008892100

View full report

@Mrtenz Mrtenz marked this pull request as ready for review June 24, 2026 11:19
@Mrtenz Mrtenz requested a review from a team as a code owner June 24, 2026 11:19
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.58%. Comparing base (fb62fb0) to head (1b9e382).
⚠️ Report is 2 commits behind head on main.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cursor cursor 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.

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.

Reviewed by Cursor Bugbot for commit 473b1d5. Configure here.

Comment thread packages/snaps-controllers/src/snaps/SnapController.ts
Comment thread packages/snaps-controllers/src/snaps/SnapController.ts
Mrtenz added 2 commits June 24, 2026 14:21
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(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What error are we expecting here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good question, may not be necessary to handle this.

Comment thread packages/snaps-controllers/src/snaps/SnapController.ts
Analytics errors should be swallowed silently without logging, matching
the pattern used in MetaMask clients.
@Mrtenz Mrtenz requested a review from FrederikBolding June 24, 2026 13:30
Comment thread packages/snaps-controllers/src/snaps/SnapController.ts
await getMockSnapFilesWithUpdatedChecksum({
sourceCode: 'a'.repeat(64_000_001),
});
it('throws if the Snap source code is too large', async () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why are there indentation changes? 🤔

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This function was outside the installSnaps describe block. 😕

});
);

describe('Updating Snaps', () => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, it's added again later, why is the diff so wonky 😵

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good question, I'm not sure. 😅

"functions": 98.78,
"lines": 98.63,
"statements": 98.32
"lines": 98.45,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Any ideas why the coverage dropped? 🤔

const snapController = await getSnapController(options);

const newSnap = controller.getSnap(MOCK_SNAP_ID);
options.messenger.publish(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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.

@FrederikBolding FrederikBolding Jun 24, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fair enough, just unsure what would be preferable. Not necessarily against this.

Comment on lines +560 to +563
| SnapControllerSnapInstallStartedEvent
| SnapControllerSnapInstallFailedEvent
| SnapControllerSnapInstalledEvent
| SnapControllerSnapUninstalledEvent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are these not part of SnapControllerEvents?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are you saying it is preferable to be explicit because we actively subscribe to these events?

Comment thread packages/snaps-controllers/src/snaps/SnapController.test.tsx Outdated
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
@Mrtenz Mrtenz added this pull request to the merge queue Jun 25, 2026
Merged via the queue into main with commit c67053b Jun 25, 2026
131 checks passed
@Mrtenz Mrtenz deleted the mrtenz/snap-controller-analytics branch June 25, 2026 08:49
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