Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions domains/data/knowledge/metrametrics-identity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: metrametrics-identity
domain: data
description: Which extension MetaMetrics events are sent without the user's analytics ID, set by the excludeMetaMetricsId option or by an event name starting with Send or Confirm
---

# MetaMetrics Identity on Anonymous Events

Read at `metamask-extension` [`c31416a`](https://github.com/MetaMask/metamask-extension/commit/c31416a47811bc4355a904925021a30f4c5564bb).

## The Mechanism

Each event is sent under the user's analytics ID or under one shared anonymous ID, decided per event, except that an event with sensitive properties is sent under both (see Sensitive Properties):

1. The background `trackEvent` reads `excludeMetaMetricsId` from the event's build options. When it is true, [`applyAnonymousEventOptions`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/analytics.ts#L303-L333) sets an `anonymous: true` marker on the event's properties.
2. The platform adapter reads the marker. A marked event is sent with `anonymousId` set to `METAMETRICS_ANONYMOUS_ID` ([`0x0000000000000000`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/shared/constants/metametrics.ts#L777)), and an unmarked one with `userId` set to the analytics ID ([`platform-adapter.ts:345-355`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/platform-adapter.ts#L345-L355)). The analytics ID is a hex string rather than a UUIDv4, so the adapter sets `skipUUIDv4Check: true` ([`platform-adapter.ts:308-321`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/platform-adapter.ts#L308-L321)). Sentry attaches the same value to its events as `user.id` ([`sentry-metametrics.ts:47-51`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/lib/sentry-metametrics.ts#L47-L51)), so an identified Segment row and a Sentry event from one install carry one ID.
3. [`enrichEventProperties`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/platform-adapter.ts#L137-L172) adds the profile identity properties to unmarked events only, and deletes `profile_id`, `canonical_profile_id` and the marker from marked ones.
4. Some events are renamed on the anonymous path through [`anonymousEventNameOverrides`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/platform-adapter.ts#L246), for example the transaction lifecycle events and `SignatureRequested`.

No event is sent while basic functionality is off ([`analytics.ts:351`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/analytics.ts#L351)).

## The Name Default

`excludeMetaMetricsId` is not only the caller's choice. An event whose name matches `/^send|^confirm/iu` is marked anonymous unless the caller passes `excludeMetaMetricsId: false` ([`analytics.ts:321-324`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/analytics.ts#L321-L324)). The comment above it calls the match a carry-over from the previous implementation.

So a new event whose name begins with `Send` or `Confirm` loses user-level attribution by default. Every such event shares one ID in Segment, and user-level dimensions such as account type or feature flags cannot be joined to it.

## Sensitive Properties

An event carrying `sensitiveProperties` cannot also set `excludeMetaMetricsId: true`. `applyAnonymousEventOptions` throws ([`analytics.ts:307-315`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/analytics.ts#L307-L315)), and `trackEvent` catches the error and reports it to Sentry ([`analytics.ts:391-392`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/controllers/analytics/analytics.ts#L391-L392)), so the event is not sent.

Otherwise an event with sensitive properties is sent twice: once under the analytics ID without them, and once with them and the anonymous marker, under the anonymous name where `anonymousEventNameOverrides` has one ([`AnalyticsController.ts:1452-1483`](https://github.com/MetaMask/core/blob/d0487f6f68af1bb9be22f5aa4eb72e036b0f4452/packages/analytics-controller/src/AnalyticsController.ts#L1452-L1483) in `@metamask/analytics-controller` 2.1.0, with the feature enabled at [`analytics-controller-init.ts:59`](https://github.com/MetaMask/metamask-extension/blob/c31416a47811bc4355a904925021a30f4c5564bb/app/scripts/messenger-client-init/analytics-controller-init.ts#L59)). A count over both rows counts the event twice.

## Detection

```bash
git grep -n 'excludeMetaMetricsId: true' -- app shared ui ':!*.test.*'
```

At `c31416a` this returns the phishing-detection, `eth_requestAccounts` and MetaMetrics data-deletion call sites, among others. A new hit, or a new event name beginning with `Send` or `Confirm`, drops the analytics ID from that event. Check that this is intended.
40 changes: 40 additions & 0 deletions domains/data/knowledge/segment-governance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: segment-governance
domain: data
description: Segment event governance via segment-schema is advisory — no CI enforcement prevents unregistered events from shipping
---

# Segment Event Governance

## Architecture

| Component | Location |
|-----------|----------|
| Tracking plan | `Consensys/segment-schema` → `tracking-plans/metamask-extension.yaml` |
| Event registry | `shared/constants/metametrics.ts` → `MetaMetricsEventName` enum (300+ entries) |
| Review process | `CONTRIBUTING.md` in segment-schema; Data Council review |
| Governance channel | `#metamask-metametrics`, `@consensys/data-council` |

## The Gap

There is **no CI enforcement** in the extension repo. A developer can:

1. Add entry to `MetaMetricsEventName` enum
2. Call `trackEvent` with it
3. Merge and ship to production

...without registering in segment-schema or going through Data Council review.

## Implications

- Schema drift between tracking plan and production events
- No property schema validation for unregistered events
- Billing impact goes unreviewed
- Data Council review is bypassable by omission

## Recommended Fix

CI check that:
1. Parses `MetaMetricsEventName` entries
2. Validates each against `tracking-plans/metamask-extension.yaml`
3. Fails build if event is missing from the plan