Repository navigation
feat(analytics-controller): add marketingCampaignCookieId state field and setMarketingCampaignCookieId action - #10373
Conversation
… and setMarketingCampaignCookieId action Moves marketingCampaignCookieId from metamask-extension's MetaMetricsController into AnalyticsController, where all other marketing consent state already lives. The field is automatically cleared when optOutOfMarketing or resetMarketingConsentDecision is called, so clients no longer need to null it out manually after those calls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion types Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Add messenger action regression tests, including the null case.
Review effort: Lite
Findings: None
What changed in this PR
This PR adds persisted marketingCampaignCookieId state and a messenger setter, clearing the value during marketing consent opt-out/reset flows.
Changes:
- Adds state, defaults, persistence metadata, and consent-clearing behavior.
- Exposes the setter action and type.
- Adds tests and changelog documentation.
The messenger-facing setter still needs regression coverage, including the null case.
| File | Summary |
|---|---|
packages/analytics-controller/src/index.ts |
Exports the new action type. |
packages/analytics-controller/src/AnalyticsController.ts |
Adds state, persistence, setter, and clearing behavior. |
packages/analytics-controller/src/AnalyticsController.test.ts |
Tests defaults, persistence, and consent behavior. |
packages/analytics-controller/src/AnalyticsController-method-action-types.ts |
Defines and unions the new messenger action. |
packages/analytics-controller/CHANGELOG.md |
Documents the feature. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
NicolasMassart
left a comment
There was a problem hiding this comment.
The missing messenger-level test is a reasonable follow-up/non-blocking improvement, not enough to withhold approval given the implementation and existing direct coverage.
|
@metamaskbot publish-preview |
|
Missing test added in follow-up PR: #10398 |
… `setMarketingCampaignCookieId` (MetaMask#10398) ## Description Follow-up to MetaMask#10373, addressing the [Copilot review comment](MetaMask#10373 (review)) asking for messenger action regression tests for `setMarketingCampaignCookieId`, including the `null` case. The tests added in MetaMask#10373 call the controller method directly, which would keep passing if the method were removed from `MESSENGER_EXPOSED_METHODS` or the action type union drifted. This adds two tests in the `setMarketingCampaignCookieId` describe block that invoke `AnalyticsController:setMarketingCampaignCookieId` through the messenger: - with a value → state is updated - with `null` → `marketingCampaignCookieId` is cleared ## Verification - Full `@metamask/analytics-controller` test suite passes (100% coverage maintained) - Regression value confirmed: temporarily removing the action from `MESSENGER_EXPOSED_METHODS` fails exactly these two tests while the direct-call tests still pass - `yarn lint:eslint` passes ## Checklist - [x] Tests pass - [x] Lint passes - [ ] No changelog entry needed (test-only change) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Test-only change with no production code or runtime behavior modifications. > > **Overview** > Adds **two regression tests** in the `setMarketingCampaignCookieId` suite that exercise the **`AnalyticsController:setMarketingCampaignCookieId` messenger action** instead of calling the controller method directly. > > One test asserts that invoking the action with a GA cookie ID updates `marketingCampaignCookieId` in state; the other asserts that passing **`null`** clears it. Together they guard against the action being dropped from **`MESSENGER_EXPOSED_METHODS`** or action-type drift while direct-call tests would still pass. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit be4d68b. 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: Sisyphus <clio-agent@sisyphuslabs.ai>
## Explanation Publish `@metamask/analytics-controller@3.2.0` so clients can consume the additive changes that have accumulated on `main` since 3.1.0, including the new `marketingCampaignCookieId` state field and `setMarketingCampaignCookieId` messenger action ([MetaMask#10373](MetaMask#10373)). Minor bump: the release only adds new, optional API surface — a new state field initialized to `null` and a new messenger action — so it is not breaking. The field is automatically cleared when the user opts out of marketing or resets their marketing consent decision. ## References - Add `marketingCampaignCookieId` state field and `setMarketingCampaignCookieId` action to `AnalyticsController`: MetaMask#10373 - Add messenger action regression tests for `setMarketingCampaignCookieId`: MetaMask#10398 ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Release-only version and changelog updates with a minor, backward-compatible analytics API bump; no runtime logic changes in this PR. > > **Overview** > Cuts **monorepo release 1281.0.0** by publishing **`@metamask/analytics-controller@3.2.0`** and wiring dependents to it. > > The analytics-controller changelog documents **3.2.0** as additive API: a **`marketingCampaignCookieId`** state field (default **`null`**) and **`setMarketingCampaignCookieId`**, with the ID cleared on **`optOutOfMarketing`** or **`resetMarketingConsentDecision`**. **`network-controller`** and **`wallet-cli`** bump **`@metamask/analytics-controller`** to **`^3.2.0`**; **`yarn.lock`** and package version fields are updated accordingly. No application source changes appear in this diff—only release metadata and dependency pins. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9e777df. 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
MetaMask#46600) ## **Description** Moves ownership of the marketing campaign cookie id (`marketingCampaignCookieId`) from `MetaMetricsController` to `AnalyticsController`, which now supports the field as of `@metamask/analytics-controller@3.2.0` (core PR MetaMask#10373). **Context:** `AnalyticsController` already owns the marketing consent state (`optedInToMarketing`, `marketingConsentDecisionMade`), and core MetaMask#10373 added the cookie id plus a `AnalyticsController:setMarketingCampaignCookieId` messenger action to it, with controller-side auto-clear on `optOutOfMarketing` and `resetMarketingConsentDecision`. This completes the migration on the extension side and resolves [mcmire's comment on MetaMask#46473](MetaMask#46473 (comment)): the clearing is now a controller action invoked through the messenger, and the manual clearing blocks are gone from `analytics.ts`. **Solution:** - Dependency bumped to stable `@metamask/analytics-controller@^3.2.0` (no preview builds). - Migration `229` moves the persisted cookie id value from `MetaMetricsController` state to `AnalyticsController` state, preserving both the string and the historically-supported numeric forms. - `MetaMetricsController` no longer holds any state or exposed methods (the controller shell remains). - The platform adapter reads the cookie via `AnalyticsController:getState`; `metamask-controller.js` writes via the new controller action. - `setParticipateInMetaMetrics` no longer clears the cookie at all, and `setDataCollectionForMarketing` no longer clears it manually — the controller handles clearing. **Accepted behavior change:** the cookie id is retained after a full metrics opt-out / onboarding reset while marketing consent remains on (core's `optOut`/`resetConsentDecision` intentionally do not clear it). - Flat-state type, Sentry-state flag, E2E fixtures/snapshots and unit tests follow the new owner. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: Depends on: MetaMask/core#10373 (shipped in `@metamask/analytics-controller@3.2.0`) Follow-up context: MetaMask#46473 (comment) ## **Manual testing steps** 1. Enable the marketing consent toggle during onboarding (or via Settings → Privacy → Data collection for marketing toggle). 2. Visit a website (e.g. metamask.io), open the inspector console, and execute the following: ``` window.postMessage( { target: 'metamask-contentscript', data: { name: 'metamask-cookie-handler', data: { jsonrpc: '2.0', method: 'getCookieFromMarketingPage', params: [{ ga_client_id: 99999, origin: window.location.origin }], id: Date.now(), origin: window.location.origin, }, }, }, window.location.origin, ); ``` 3. Confirm AnalyticsController state has marketingCampaignCookieId set to 99999 (check in the inspector). 4. Toggle "Data collection for marketing" off in Privacy Settings and confirm marketingCampaignCookieId is cleared. 5. Do the same steps again with marketing consent toggle disabled during onboarding and confirm marketingCampaignCookieId is not set. <!-- ## **Screenshots/Recordings** ### **Before** ### **After** --> ## **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] > **Medium Risk** > Touches persisted analytics/marketing identity state and consent clearing behavior across upgrades; migration 229 must run correctly for existing users. > > **Overview** > **`marketingCampaignCookieId`** is moved from **`MetaMetricsController`** to **`AnalyticsController`** (via **`@metamask/analytics-controller@^3.2.0`**), with migration **229** copying persisted string/numeric values and stripping the field from **`MetaMetricsController`**, which is now an empty controller shell. > > Reads and writes go through **`AnalyticsController:getState`** and **`AnalyticsController:setMarketingCampaignCookieId`** (platform adapter, marketing-page cookie handler, messenger delegation). Extension helpers **`setParticipateInMetaMetrics`** / **`setDataCollectionForMarketing`** no longer manually null the cookie; clearing is delegated to core on marketing opt-out. **Opting out of MetaMetrics alone no longer clears the cookie** (intentional behavior change). Types, Sentry flags, fixtures, and tests follow the new owner. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4ac3158. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
Summary
marketingCampaignCookieId?: string | nulltoAnalyticsControllerState(persisted, backward-compatible optional field)setMarketingCampaignCookieId(id: string | null)method exposed via the messengernullwhenoptOutOfMarketingorresetMarketingConsentDecisionis calledAnalyticsControllerSetMarketingCampaignCookieIdActiontypeMotivation
marketingCampaignCookieIdcurrently lives inMetaMetricsControllerin metamask-extension. SinceAnalyticsControlleralready owns all other marketing consent state (optedInToMarketing,marketingConsentDecisionMade), this field belongs here. Moving it to core also allows the auto-clear on opt-out to live in the controller itself, so clients no longer need to null it out manually after callingoptOutOfMarketingorresetMarketingConsentDecision.Test plan
yarn workspace @metamask/analytics-controller run test— all tests pass, 100% coverage maintainedyarn workspace @metamask/analytics-controller run build— no type errors🤖 Generated with Claude Code
Note
Medium Risk
Introduces persisted marketing attribution data tied to consent clearing rules; clients must migrate from extension-local storage without mishandling opt-out semantics.
Overview
Adds persisted
marketingCampaignCookieIdtoAnalyticsControllerso clients can store a marketing attribution identifier (e.g. a GA client ID) alongside existing marketing consent state, defaulting tonulland remaining optional for older persisted state.Exposes
setMarketingCampaignCookieId(string | null)on the messenger (with a matching action type export). Marketing consent flows now reset the ID tonullonoptOutOfMarketingandresetMarketingConsentDecision; product analyticsoptOut/resetConsentDecisionintentionally leave it unchanged. Tests and the package changelog cover defaults, persistence metadata, set/clear behavior, and the consent split.Reviewed by Cursor Bugbot for commit c93969f. Bugbot is set up for automated code reviews on this repo. Configure here.