Commit bd0b0f1
feat: integrate analytics controller (MetaMask#42885)
## **Description**
This PR integrates AnalyticsController in Extension codebase.
It replaces this state:
- MetaMetricsController's `metaMetricsId`
- MetaMetricsController's `participateInMetaMetrics`
- MetaMetricsController's `segmentApiCalls`
by this state:
- AnalyticsController's `analyticsId`
- AnalyticsController's `optedIn`
- AnalyticsController's `eventQueue`
- MetaMetricsController's `completedMetaMetricsOnboarding`
Since these changes impact many areas of the codebase, we’ve decided to
take a phased approach.
This PR migrates the persisted state and updates the UI compatibility
selectors, as well as the background `getState()` function, to derive
the legacy values (`metaMetricsId`, `participateInMetaMetrics`) from the
new state. This lets existing code continue using the legacy values
while the source of truth moves to `AnalyticsController.analyticsId`,
`AnalyticsController.optedIn`, and
`MetaMetricsController.completedMetaMetricsOnboarding`.
In future phases, we’ll progressively remove all remaining usages of the
legacy values (`metaMetricsId`, `participateInMetaMetrics`) throughout
the codebase.
The files that deserve more attention during PR review are the
following:
- app/scripts/controllers/analytics/platform-adapter.ts
- app/scripts/controllers/metametrics-controller.ts
```mermaid
flowchart TB
subgraph Before["Before"]
direction LR
MMC1["MetaMetricsController"] --> SDK1["Segment SDK"]
Early1["Early events"] --> SDK1
end
subgraph After["After"]
direction LR
MMC2["MetaMetricsController"] --> AC["AnalyticsController"]
AC --> SDK2["Segment SDK"]
Early2["Early events"] --> SDK2
end
Before ~~~ After
```
## **Changelog**
CHANGELOG entry: null
## **Related issues**
Fixes: MetaMask/MetaMask-planning#7193
## **Manual testing steps**
Main test case
1. Build two different Extensions, one on this branch and one on main,
the goal will be to compare events emitted by both and confirm they're
equivalent
2. Go through onboarding with both extension and find your
metaMetricsId/analyticsId by doing right click on extension UI, then
inspect > Application > Storage > IndexedDB > metamask-backup >
MetaMetricsController/AnalyticsController
3. Open Segment, choose the right source (usually `MetaMask Extension
[Dev]`, except if you configured SEGMENT_WRITE_KEY env variable with
your own Segment project), and filter events with your
metaMetricsId/analyticsId
4. Confirm the three types of events emitted by both extension are
equivalent:
a. track
b. identify
c. page
Edge cases
- Anonymous events (see list
[here](MetaMask/MetaMask-planning#7230))
- Fully anonymous ones
- These events are fully anonymous in the sense that the entire event,
including all properties are considered as sensitive and get anonymized
- Fully anonymous events are emitted by passing "excludeMetaMetricsId:
true" as option (Example
[here](https://github.com/MetaMask/metamask-extension/blob/main/app/scripts/background.js#L502))
- An easy one to reproduce is "Phishing Page Displayed": visit one of
the pages listed
[here](https://phishing-detection.api.cx.metamask.io/v1/stalelist) and
the event will be emitted
- Partially anonymous ones
- These events are partially anonymous in the sense that some properties
are considered as sensitive and some are not. As a consequence, 2 events
are sent: an anonymous one with all properties, and a non-anonymous one
with only properties considered as non-sensitive
- Partially anonymous events are emitted by passing
"sensitiveProperties" (Example
[here](https://github.com/MetaMask/metamask-extension/blob/main/ui/pages/contacts/components/add-contact-form.tsx#L236-L239))
- An easy one to reproduce is "Contact Added": go to Contacts, click
"Add contact", and add Vitalik's address as contact
(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045)
- Before this PR, both events used to have similar messageId (example:
"1780055175321.6592", and "1780055175321.6592-0x000"), while with this
PR, messageId have a new uuidv4 format and both events don't have
similar messageId (example: "5cc0d85e-3f0e-4374-8811-d36924d06689" and
"433ff4c1-948d-4a4e-9470-81e878c7df44")
- Anonymous ones with event renaming
- Some anonymous events get renamed when being emitted (list of events
available
[here](https://github.com/MetaMask/metamask-extension/blob/main/app/scripts/controllers/metametrics-controller.ts#L113-L130)):
for example “Signature Requested” gets renamed “Signature Requested
Anon”
- An easy one to reproduce is “Signature Requested” (see Fragments
sections below for more detail)
- Fragments
- Fragments are events used to tie a multi-step flow together, such as
“Signature Requested” followed later by “Signature Approved” or
“Signature Rejected”
- They can be tested by visiting
[test-dapp](https://metamask.github.io/test-dapp/), then connect
extension, then click "Sign Typed Data V4", then accept or reject
signature
- The purpose of fragments is for both each event of the multi-step flow
to share the same properties
- Before this PR, events from a same fragment used to have similar
`messageId` (example: "signature-3947127447", and
"signature-3947127447-success" or "signature-3947127447-failure"), while
with this PR, `messageId` have a new uuidv4 format and events from a
same fragment don't have similar `messageId` (example:
"9e3a83d0-ce13-47d2-a2f4-08a6d9adc29d" and
"d2368a25-01c5-4b3c-af55-7d5f54eb58a6")
- Persisted queue
- Go to home page
- Check that persisted queue is an empty object: right click on
extension UI, then inspect > Application > Storage > IndexedDB >
metamask-backup > MetaMetricsController/AnalyticsController >
segmentApiCalls/eventQueue
- Turn internet off
- Click on "Swap"
- Confirm no event is sent to Segment
- Confirm events are added to persisted queue, including "Unified
SwapBridge Button Clicked" (click on refresh button in the inspector to
see them)
- Wait for 5 minutes
- Turn internet on
- Restart extension
- Confirm events are sent to Segment, including "Unified SwapBridge
Button Clicked", and there's a 5 minute difference between `timestamp`
and `sentAt`
- These repro steps are not working on main branch, because persisted
queue used to get cleared, regardless of whether the callback represents
success or failure, whereas in this PR, it only gets cleared upon
success. That change of behavior introduces the risk that if an event is
malformed, it can end up being retried after every extension restart.
But at the same time it allows us to collect more events, in cases of
transient failures (e.g. offline, timeout). This core repo PR got opened
to align behavior with what's currently on main:
MetaMask/core#8934
- Early events
- Right click on extension UI, then inspect > Application > Storage >
Extension storage > Local > KeyringController > Right click to delete
KeyringController
- Restart Extension straight away
- You should see "Vault Corruption Restore Wallet Screen Viewed" event
in Segment
- Opt out event
- Start from a fresh onboarding state, go through create/import wallet,
on the MetaMetrics onboarding page, uncheck “Participate in
MetaMetrics”, continue and finish onboarding.
- On Chrome, you should see "Metrics Opt Out" event in Segment
- On Firefox, you should not see "Metrics Opt Out" event in Segment
- Delete metametrics
- Right click on extension UI, then inspect > Network, and paste
"regulations" in the search bar
- Go to Settings > Privacy > Delete MetaMetrics data and click the
button
- You should see an API call in the Networks tab, with "subjectIds"
array as parameter, and your metaMetricsId/analyticsId included in that
array
## **Screenshots/Recordings**
NA
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **Pre-merge reviewer checklist**
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **High Risk**
> Central refactor of consent, IDs, queuing, and anonymous event
handling across background, Segment, and data-deletion paths; messageId
and offline-queue behavior differ from main and can affect metrics
parity or stuck retries.
>
> **Overview**
> This PR routes MetaMetrics **track / identify / page** through
**`AnalyticsController`** and a new **Segment `platform-adapter`**,
instead of **`MetaMetricsController`** calling Segment directly.
>
> **State & consent:** Persisted **`metaMetricsId`**,
**`participateInMetaMetrics`**, and **`segmentApiCalls`** are removed
from **`MetaMetricsController`** in favor of **`AnalyticsController`**
(`analyticsId`, `optedIn`, `eventQueue`) plus
**`completedMetaMetricsOnboarding`**. Opt-in/out now calls
**`AnalyticsController:optIn` / `optOut`**; IDs come from
**`getMetaMetricsId()`** → analytics state. **Sentry** snapshots add
**`AnalyticsController`** and drop the old MMC consent fields.
>
> **Behavior changes:** Anonymous / sensitive events use a
**`properties.anonymous`** marker; the adapter swaps to the shared
anonymous ID and renames select signature/transaction events. Direct
Segment logic (payload building, **`segmentApiCalls`** MV3 replay,
deterministic **`messageId`**, **`generateMetaMetricsId`**) is removed
from MMC. **Early** and **opt-out** paths use
**`custom-segment-tracking`** reading **`AnalyticsController`** from
backup state. **RPC middleware**, **data deletion**, and **background**
helpers read consent/ID via **`controller.getState()`** /
**`analyticsController.state`**.
>
> **Tests:** Large **`metametrics-controller`** test updates; new
**`platform-adapter`** unit tests.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
5d73b11. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Norbert Elter <72046715+itsyoboieltr@users.noreply.github.com>1 parent 37d9a60 commit bd0b0f1
117 files changed
Lines changed: 3124 additions & 2165 deletions
File tree
- app/scripts
- constants
- controllers
- analytics
- metametrics-data-deletion
- lib
- critical-error
- rpc-method-middleware/handlers
- segment
- __tests__
- state-corruption
- messenger-client-init
- messengers
- seedless-onboarding
- migrations
- lavamoat
- browserify
- beta
- experimental
- flask
- main
- webpack/mv2
- beta
- experimental
- flask
- main
- test
- data
- e2e
- dist
- fixtures
- tests
- bridge
- metrics
- state-snapshots
- settings
- integration
- confirmations
- signatures
- transactions
- data
- defi
- nfts
- notifications&auth
- data
- jest
- ui
- components
- app
- assets/defi-list/cells
- metametrics-toggle
- toast-master
- wallet-overview
- multichain
- funding-method-modal
- token-list-item
- ui/survey-toast
- contexts
- ducks/metamask
- hooks/ramps/useRamps
- pages
- asset/components
- home
- onboarding-flow
- create-password
- creation-successful
- metametrics
- onboarding-flow-switch
- setup-passkey
- settings/privacy-tab
- selectors
- store
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1276 | 1276 | | |
1277 | 1277 | | |
1278 | 1278 | | |
1279 | | - | |
| 1279 | + | |
1280 | 1280 | | |
1281 | 1281 | | |
1282 | 1282 | | |
| |||
1370 | 1370 | | |
1371 | 1371 | | |
1372 | 1372 | | |
1373 | | - | |
1374 | | - | |
| 1373 | + | |
1375 | 1374 | | |
1376 | 1375 | | |
1377 | | - | |
| 1376 | + | |
1378 | 1377 | | |
1379 | 1378 | | |
1380 | 1379 | | |
| |||
2157 | 2156 | | |
2158 | 2157 | | |
2159 | 2158 | | |
2160 | | - | |
2161 | | - | |
| 2159 | + | |
2162 | 2160 | | |
2163 | 2161 | | |
2164 | 2162 | | |
2165 | 2163 | | |
2166 | 2164 | | |
2167 | 2165 | | |
2168 | | - | |
2169 | | - | |
2170 | | - | |
2171 | | - | |
2172 | | - | |
2173 | | - | |
| 2166 | + | |
| 2167 | + | |
| 2168 | + | |
2174 | 2169 | | |
2175 | 2170 | | |
2176 | 2171 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
44 | 49 | | |
45 | 50 | | |
46 | 51 | | |
| |||
194 | 199 | | |
195 | 200 | | |
196 | 201 | | |
| 202 | + | |
197 | 203 | | |
198 | 204 | | |
199 | 205 | | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | 206 | | |
204 | 207 | | |
205 | 208 | | |
| |||
Lines changed: 245 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
0 commit comments