Skip to content

feat(notification-services-controller): enforce marketing consent on notification preferences - #10861

Draft
zelkibuilds wants to merge 4 commits into
feat/marketing-consent-controllerfrom
feat/marketing-consent-notification-services
Draft

zelkibuilds wants to merge 4 commits into
feat/marketing-consent-controllerfrom
feat/marketing-consent-notification-services

Conversation

@zelkibuilds

@zelkibuilds zelkibuilds commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Explanation

Marketing notifications rely on marketing consent. #10821 turns them off when consent goes off; this PR covers the other direction in @metamask/notification-services-controller: a marketing notification can't be turned on without consent, and new users don't start with marketing notifications on unless they consented.

  • updateNotificationPreferences (new method and messenger action):
    • Takes only the sections and fields being changed (NotificationPreferencesUpdate). Fields left out keep their stored value; arrays and maps are replaced whole.
    • Merges over a fresh read of the stored preferences, one update at a time, and returns the saved preferences.
    • Re-reads the preferences once the queued updates finish, not after each one, so UIs bound to the AUS cache never show a state without updates still queued.
    • A section missing from stored preferences (added after they were created) starts from its defaults.
    • Rejects an update that turns a marketing notification on without consent with MarketingConsentRequiredError (match on MARKETING_CONSENT_REQUIRED_ERROR_CODE). A marketing notification already on in AUS doesn't block other updates.
    • Never creates preferences that aren't set up yet: their existence marks first-time setup as done.
  • First-time preferences: both marketing channels (push, and in-app feature announcements) now follow AnalyticsController marketing consent.
  • Deprecated: isFeatureAnnouncementsEnabled, setFeatureAnnouncementsEnabled, and the hasMarketingConsent and productAnnouncementEnabled options, all replaced by marketing consent.
  • Ownership: moved to team-engagement in teams.json.

Client impact

  • Breaking: the NSC messenger must allow AnalyticsController:getState and AuthenticatedUserStorageService:invalidateQueries.
  • Breaking: first-time notification preferences follow consent, so mobile users without consent no longer start with feature announcements on.
  • Clients write notification preference changes through updateNotificationPreferences, sending only what changed. Reads stay on AuthenticatedUserStorageService:getNotificationPreferences.

Follow-ups

  • PerpsController writes whole preferences to AUS from a possibly stale copy. Route its two watchlist writes (#persistWatchlistToRemote, #syncWatchlistFromRemote) through NotificationServicesController:updateNotificationPreferences as { perps: { watchlistMarkets } }, then remove AuthenticatedUserStorageService:putNotificationPreferences from the Perps messenger in both clients. Needs the Perps team.
  • Remove the deprecated feature announcements config.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

High Risk
Breaking messenger wiring and first-time marketing/feature-announcement defaults affect all clients; preference writes now gate marketing channels on consent and change how stale AUS data is handled.

Overview
Adds updateNotificationPreferences (and the matching messenger action) as the supported write path for Authenticated User Storage notification prefs: partial updates merge over a fresh read, updates are serialized, the AUS preferences cache is invalidated/refreshed, and turning marketing push or in-app channels on without consent throws MarketingConsentRequiredError.

Breaking: the NSC messenger must allow AnalyticsController:getState and AuthenticatedUserStorageService:invalidateQueries. On first-time preference creation, both marketing channels are seeded from analytics marketing consent; hasMarketingConsent / productAnnouncementEnabled are ignored (users without consent no longer default to feature announcements on).

Deprecates isFeatureAnnouncementsEnabled, setFeatureAnnouncementsEnabled, and those enable options in favor of AUS marketing.inAppNotificationsEnabled. Adds @metamask/analytics-controller and moves package ownership to team-engagement.

Reviewed by Cursor Bugbot for commit c54f779. Bugbot is set up for automated code reviews on this repo. Configure here.

…notification preferences

- Add updateNotificationPreferences, which saves a partial update merged
  over a fresh read, one update at a time, and rejects an update that
  turns a marketing channel on without marketing consent
  (MarketingConsentRequiredError).
- Seed both marketing channels from AnalyticsController consent when
  preferences are created for the first time.
- Deprecate isFeatureAnnouncementsEnabled, setFeatureAnnouncementsEnabled
  and the hasMarketingConsent/productAnnouncementEnabled options.
- Move ownership to team-engagement.
@zelkibuilds

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-previews

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@11.0.1-preview-2a7a9a077
@metamask-previews/accounts-controller@40.1.0-preview-2a7a9a077
@metamask-previews/address-book-controller@8.0.0-preview-2a7a9a077
@metamask-previews/advanced-chart-core@1.0.0-preview-2a7a9a077
@metamask-previews/ai-controllers@2.0.0-preview-2a7a9a077
@metamask-previews/analytics-controller@4.0.0-preview-2a7a9a077
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-2a7a9a077
@metamask-previews/announcement-controller@9.0.0-preview-2a7a9a077
@metamask-previews/app-metadata-controller@3.0.0-preview-2a7a9a077
@metamask-previews/approval-controller@10.0.0-preview-2a7a9a077
@metamask-previews/assets-controller@19.0.0-preview-2a7a9a077
@metamask-previews/assets-controllers@112.1.2-preview-2a7a9a077
@metamask-previews/authenticated-user-storage@4.1.0-preview-2a7a9a077
@metamask-previews/base-controller@10.0.0-preview-2a7a9a077
@metamask-previews/base-data-service@2.1.0-preview-2a7a9a077
@metamask-previews/bitcoin-regtest-up@2.0.0-preview-2a7a9a077
@metamask-previews/bridge-controller@82.0.3-preview-2a7a9a077
@metamask-previews/bridge-status-controller@76.4.0-preview-2a7a9a077
@metamask-previews/build-utils@4.0.0-preview-2a7a9a077
@metamask-previews/chain-agnostic-permission@2.0.0-preview-2a7a9a077
@metamask-previews/chomp-api-service@6.0.1-preview-2a7a9a077
@metamask-previews/claims-controller@1.0.3-preview-2a7a9a077
@metamask-previews/client-controller@2.0.0-preview-2a7a9a077
@metamask-previews/client-utils@3.0.4-preview-2a7a9a077
@metamask-previews/compliance-controller@3.0.0-preview-2a7a9a077
@metamask-previews/composable-controller@13.0.0-preview-2a7a9a077
@metamask-previews/config-registry-controller@5.0.0-preview-2a7a9a077
@metamask-previews/connectivity-controller@1.0.0-preview-2a7a9a077
@metamask-previews/controller-utils@13.0.0-preview-2a7a9a077
@metamask-previews/core-backend@12.2.0-preview-2a7a9a077
@metamask-previews/cryptography@1.1.2-preview-2a7a9a077
@metamask-previews/delegation-controller@4.0.0-preview-2a7a9a077
@metamask-previews/earn-controller@13.0.2-preview-2a7a9a077
@metamask-previews/eip-5792-middleware@4.0.1-preview-2a7a9a077
@metamask-previews/eip-7702-internal-rpc-middleware@1.0.0-preview-2a7a9a077
@metamask-previews/eip1193-permission-middleware@3.0.0-preview-2a7a9a077
@metamask-previews/eth-block-tracker@16.0.0-preview-2a7a9a077
@metamask-previews/eth-json-rpc-middleware@25.0.0-preview-2a7a9a077
@metamask-previews/eth-json-rpc-provider@7.0.0-preview-2a7a9a077
@metamask-previews/foundryup@2.0.0-preview-2a7a9a077
@metamask-previews/gas-fee-controller@27.0.0-preview-2a7a9a077
@metamask-previews/gator-permissions-controller@6.0.1-preview-2a7a9a077
@metamask-previews/geolocation-controller@2.0.0-preview-2a7a9a077
@metamask-previews/java-tron-up@2.0.0-preview-2a7a9a077
@metamask-previews/json-rpc-engine@11.0.0-preview-2a7a9a077
@metamask-previews/json-rpc-middleware-stream@9.0.0-preview-2a7a9a077
@metamask-previews/keyring-controller@28.2.0-preview-2a7a9a077
@metamask-previews/kyc-controller@0.10.0-preview-2a7a9a077
@metamask-previews/local-node-utils@2.0.0-preview-2a7a9a077
@metamask-previews/logging-controller@10.0.0-preview-2a7a9a077
@metamask-previews/marketing-consent-controller@0.0.0-preview-2a7a9a077
@metamask-previews/message-manager@15.0.0-preview-2a7a9a077
@metamask-previews/messenger@3.0.0-preview-2a7a9a077
@metamask-previews/messenger-cli@1.0.0-preview-2a7a9a077
@metamask-previews/money-account-api-data-service@2.2.0-preview-2a7a9a077
@metamask-previews/money-account-balance-service@3.1.2-preview-2a7a9a077
@metamask-previews/money-account-controller@2.0.0-preview-2a7a9a077
@metamask-previews/money-account-mfa-whitelist@0.1.0-preview-2a7a9a077
@metamask-previews/money-account-upgrade-controller@5.1.0-preview-2a7a9a077
@metamask-previews/money-account-utils@2.1.0-preview-2a7a9a077
@metamask-previews/multichain-account-service@14.1.0-preview-2a7a9a077
@metamask-previews/multichain-api-middleware@5.0.0-preview-2a7a9a077
@metamask-previews/multichain-network-controller@4.0.0-preview-2a7a9a077
@metamask-previews/multichain-transactions-controller@8.0.0-preview-2a7a9a077
@metamask-previews/name-controller@10.0.0-preview-2a7a9a077
@metamask-previews/network-connection-banner-controller@1.0.0-preview-2a7a9a077
@metamask-previews/network-controller@37.0.1-preview-2a7a9a077
@metamask-previews/network-enablement-controller@7.0.2-preview-2a7a9a077
@metamask-previews/notification-services-controller@29.0.3-preview-2a7a9a077
@metamask-previews/passkey-controller@4.1.0-preview-2a7a9a077
@metamask-previews/permission-controller@14.0.0-preview-2a7a9a077
@metamask-previews/permission-log-controller@6.0.0-preview-2a7a9a077
@metamask-previews/perps-controller@20.1.0-preview-2a7a9a077
@metamask-previews/phishing-controller@18.2.1-preview-2a7a9a077
@metamask-previews/platform-api-docs@0.2.1-preview-2a7a9a077
@metamask-previews/polling-controller@17.0.0-preview-2a7a9a077
@metamask-previews/preferences-controller@24.0.0-preview-2a7a9a077
@metamask-previews/profile-controller@1.1.0-preview-2a7a9a077
@metamask-previews/profile-metrics-controller@5.1.3-preview-2a7a9a077
@metamask-previews/profile-sync-controller@34.0.3-preview-2a7a9a077
@metamask-previews/ramps-controller@27.0.1-preview-2a7a9a077
@metamask-previews/rate-limit-controller@8.0.0-preview-2a7a9a077
@metamask-previews/react-data-query@2.0.0-preview-2a7a9a077
@metamask-previews/remote-feature-flag-controller@7.0.0-preview-2a7a9a077
@metamask-previews/sample-controllers@6.0.0-preview-2a7a9a077
@metamask-previews/seedless-onboarding-controller@12.0.0-preview-2a7a9a077
@metamask-previews/selected-network-controller@27.0.0-preview-2a7a9a077
@metamask-previews/sentinel-api-service@2.1.0-preview-2a7a9a077
@metamask-previews/shield-controller@7.0.4-preview-2a7a9a077
@metamask-previews/signature-controller@40.0.0-preview-2a7a9a077
@metamask-previews/smart-transactions-controller@27.1.0-preview-2a7a9a077
@metamask-previews/snap-account-service@4.0.0-preview-2a7a9a077
@metamask-previews/social-controllers@3.8.0-preview-2a7a9a077
@metamask-previews/solana-test-validator-up@2.0.0-preview-2a7a9a077
@metamask-previews/stellar-quickstart-up@0.0.0-preview-2a7a9a077
@metamask-previews/storage-service@2.0.0-preview-2a7a9a077
@metamask-previews/subscription-controller@14.0.0-preview-2a7a9a077
@metamask-previews/transaction-controller@72.2.1-preview-2a7a9a077
@metamask-previews/transaction-pay-controller@30.1.0-preview-2a7a9a077
@metamask-previews/transaction-pay-middleware@0.0.0-preview-2a7a9a077
@metamask-previews/user-operation-controller@42.0.1-preview-2a7a9a077
@metamask-previews/utils@12.0.0-preview-2a7a9a077
@metamask-previews/wallet@17.1.0-preview-2a7a9a077
@metamask-previews/wallet-cli@0.0.0-preview-2a7a9a077

@zelkibuilds
zelkibuilds marked this pull request as ready for review October 16, 2026 14:27
@zelkibuilds
zelkibuilds requested review from a team as code owners October 16, 2026 14:27
@zelkibuilds zelkibuilds self-assigned this Oct 16, 2026
@zelkibuilds
zelkibuilds deployed to default-branch October 16, 2026 14:27 — with GitHub Actions Active
@zelkibuilds
zelkibuilds marked this pull request as draft October 16, 2026 14:28
…d updates finish

Re-reading after every update published in-between states to UIs bound to
the AUS cache, so a toggle still queued briefly flipped back. Re-read once
the queue drains, and only if an update was written. Start a section
missing from stored preferences from its defaults.
@zelkibuilds

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-previews

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. Learn how to use preview builds in other projects.

Expand for full list of packages and versions.
@metamask-previews/account-tree-controller@11.0.1-preview-9bee3d25c
@metamask-previews/accounts-controller@40.1.0-preview-9bee3d25c
@metamask-previews/address-book-controller@8.0.0-preview-9bee3d25c
@metamask-previews/advanced-chart-core@1.0.0-preview-9bee3d25c
@metamask-previews/ai-controllers@2.0.0-preview-9bee3d25c
@metamask-previews/analytics-controller@4.0.0-preview-9bee3d25c
@metamask-previews/analytics-data-regulation-controller@0.0.0-preview-9bee3d25c
@metamask-previews/announcement-controller@9.0.0-preview-9bee3d25c
@metamask-previews/app-metadata-controller@3.0.0-preview-9bee3d25c
@metamask-previews/approval-controller@10.0.0-preview-9bee3d25c
@metamask-previews/assets-controller@19.0.0-preview-9bee3d25c
@metamask-previews/assets-controllers@112.1.2-preview-9bee3d25c
@metamask-previews/authenticated-user-storage@4.1.0-preview-9bee3d25c
@metamask-previews/base-controller@10.0.0-preview-9bee3d25c
@metamask-previews/base-data-service@2.1.0-preview-9bee3d25c
@metamask-previews/bitcoin-regtest-up@2.0.0-preview-9bee3d25c
@metamask-previews/bridge-controller@82.0.3-preview-9bee3d25c
@metamask-previews/bridge-status-controller@76.4.0-preview-9bee3d25c
@metamask-previews/build-utils@4.0.0-preview-9bee3d25c
@metamask-previews/chain-agnostic-permission@2.0.0-preview-9bee3d25c
@metamask-previews/chomp-api-service@6.0.1-preview-9bee3d25c
@metamask-previews/claims-controller@1.0.3-preview-9bee3d25c
@metamask-previews/client-controller@2.0.0-preview-9bee3d25c
@metamask-previews/client-utils@3.0.4-preview-9bee3d25c
@metamask-previews/compliance-controller@3.0.0-preview-9bee3d25c
@metamask-previews/composable-controller@13.0.0-preview-9bee3d25c
@metamask-previews/config-registry-controller@5.0.0-preview-9bee3d25c
@metamask-previews/connectivity-controller@1.0.0-preview-9bee3d25c
@metamask-previews/controller-utils@13.0.0-preview-9bee3d25c
@metamask-previews/core-backend@12.2.0-preview-9bee3d25c
@metamask-previews/cryptography@1.1.2-preview-9bee3d25c
@metamask-previews/delegation-controller@4.0.0-preview-9bee3d25c
@metamask-previews/earn-controller@13.0.2-preview-9bee3d25c
@metamask-previews/eip-5792-middleware@4.0.1-preview-9bee3d25c
@metamask-previews/eip-7702-internal-rpc-middleware@1.0.0-preview-9bee3d25c
@metamask-previews/eip1193-permission-middleware@3.0.0-preview-9bee3d25c
@metamask-previews/eth-block-tracker@16.0.0-preview-9bee3d25c
@metamask-previews/eth-json-rpc-middleware@25.0.0-preview-9bee3d25c
@metamask-previews/eth-json-rpc-provider@7.0.0-preview-9bee3d25c
@metamask-previews/foundryup@2.0.0-preview-9bee3d25c
@metamask-previews/gas-fee-controller@27.0.0-preview-9bee3d25c
@metamask-previews/gator-permissions-controller@6.0.1-preview-9bee3d25c
@metamask-previews/geolocation-controller@2.0.0-preview-9bee3d25c
@metamask-previews/java-tron-up@2.0.0-preview-9bee3d25c
@metamask-previews/json-rpc-engine@11.0.0-preview-9bee3d25c
@metamask-previews/json-rpc-middleware-stream@9.0.0-preview-9bee3d25c
@metamask-previews/keyring-controller@28.2.0-preview-9bee3d25c
@metamask-previews/kyc-controller@0.10.0-preview-9bee3d25c
@metamask-previews/local-node-utils@2.0.0-preview-9bee3d25c
@metamask-previews/logging-controller@10.0.0-preview-9bee3d25c
@metamask-previews/marketing-consent-controller@0.0.0-preview-9bee3d25c
@metamask-previews/message-manager@15.0.0-preview-9bee3d25c
@metamask-previews/messenger@3.0.0-preview-9bee3d25c
@metamask-previews/messenger-cli@1.0.0-preview-9bee3d25c
@metamask-previews/money-account-api-data-service@2.2.0-preview-9bee3d25c
@metamask-previews/money-account-balance-service@3.1.2-preview-9bee3d25c
@metamask-previews/money-account-controller@2.0.0-preview-9bee3d25c
@metamask-previews/money-account-mfa-whitelist@0.1.0-preview-9bee3d25c
@metamask-previews/money-account-upgrade-controller@5.1.0-preview-9bee3d25c
@metamask-previews/money-account-utils@2.1.0-preview-9bee3d25c
@metamask-previews/multichain-account-service@14.1.0-preview-9bee3d25c
@metamask-previews/multichain-api-middleware@5.0.0-preview-9bee3d25c
@metamask-previews/multichain-network-controller@4.0.0-preview-9bee3d25c
@metamask-previews/multichain-transactions-controller@8.0.0-preview-9bee3d25c
@metamask-previews/name-controller@10.0.0-preview-9bee3d25c
@metamask-previews/network-connection-banner-controller@1.0.0-preview-9bee3d25c
@metamask-previews/network-controller@37.0.1-preview-9bee3d25c
@metamask-previews/network-enablement-controller@7.0.2-preview-9bee3d25c
@metamask-previews/notification-services-controller@29.0.3-preview-9bee3d25c
@metamask-previews/passkey-controller@4.1.0-preview-9bee3d25c
@metamask-previews/permission-controller@14.0.0-preview-9bee3d25c
@metamask-previews/permission-log-controller@6.0.0-preview-9bee3d25c
@metamask-previews/perps-controller@20.1.0-preview-9bee3d25c
@metamask-previews/phishing-controller@18.2.1-preview-9bee3d25c
@metamask-previews/platform-api-docs@0.2.1-preview-9bee3d25c
@metamask-previews/polling-controller@17.0.0-preview-9bee3d25c
@metamask-previews/preferences-controller@24.0.0-preview-9bee3d25c
@metamask-previews/profile-controller@1.1.0-preview-9bee3d25c
@metamask-previews/profile-metrics-controller@5.1.3-preview-9bee3d25c
@metamask-previews/profile-sync-controller@34.0.3-preview-9bee3d25c
@metamask-previews/ramps-controller@27.0.1-preview-9bee3d25c
@metamask-previews/rate-limit-controller@8.0.0-preview-9bee3d25c
@metamask-previews/react-data-query@2.0.0-preview-9bee3d25c
@metamask-previews/remote-feature-flag-controller@7.0.0-preview-9bee3d25c
@metamask-previews/sample-controllers@6.0.0-preview-9bee3d25c
@metamask-previews/seedless-onboarding-controller@12.0.0-preview-9bee3d25c
@metamask-previews/selected-network-controller@27.0.0-preview-9bee3d25c
@metamask-previews/sentinel-api-service@2.1.0-preview-9bee3d25c
@metamask-previews/shield-controller@7.0.4-preview-9bee3d25c
@metamask-previews/signature-controller@40.0.0-preview-9bee3d25c
@metamask-previews/smart-transactions-controller@27.1.0-preview-9bee3d25c
@metamask-previews/snap-account-service@4.0.0-preview-9bee3d25c
@metamask-previews/social-controllers@3.8.0-preview-9bee3d25c
@metamask-previews/solana-test-validator-up@2.0.0-preview-9bee3d25c
@metamask-previews/stellar-quickstart-up@0.0.0-preview-9bee3d25c
@metamask-previews/storage-service@2.0.0-preview-9bee3d25c
@metamask-previews/subscription-controller@14.0.0-preview-9bee3d25c
@metamask-previews/transaction-controller@72.2.1-preview-9bee3d25c
@metamask-previews/transaction-pay-controller@30.1.0-preview-9bee3d25c
@metamask-previews/transaction-pay-middleware@0.0.0-preview-9bee3d25c
@metamask-previews/user-operation-controller@42.0.1-preview-9bee3d25c
@metamask-previews/utils@12.0.0-preview-9bee3d25c
@metamask-previews/wallet@17.1.0-preview-9bee3d25c
@metamask-previews/wallet-cli@0.0.0-preview-9bee3d25c

This branch was successfully deployed

1 active (outdated) deployment
default-branch — c54f7794 Deployed Oct 16, 2026 by zelkibuilds via Determine whether this PR is a release PR #5608
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.

1 participant