Skip to content

Commit 7a23062

Browse files
fix: add location to swaps metrics missing that field (#32188)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- mms-check directive vocabulary — read by .github/scripts/shared/pr-template-checks.ts at module load to build the validation plan. Directives are invisible in rendered markdown and must NOT be removed or edited without updating the validator registry. type=text Section must contain non-placeholder prose. type=changelog Section must have a valid CHANGELOG entry: line. type=issue-link Section must have a Fixes:/Closes:/Refs: line with a value. type=manual-testing Section must have real testing steps or an explicit N/A. type=screenshot Section must have evidence (image/URL) or an explicit N/A. type=checklist Section must have all checkboxes consciously checked. required=true|false Whether a missing/invalid section runs the validator at all. blocking=true|false Whether a failure of this check fails the CI workflow. Default: false — failures are shown as warnings in the sticky comment but do not block the PR. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> The `Unified SwapBridge Page Viewed` analytics event was missing the `location` property, so we could not attribute page views to the user's entry point (Main View, Token View, Trending Explore, etc.) unlike other Unified SwapBridge events that receive `location` via `BridgeController.setLocation()`. This change threads the route-level `location` (already set in `useSwapBridgeNavigation`) into `useTrackSwapPageViewed` and includes it on both `Unified SwapBridge Page Viewed` and the companion `Asset Viewed` event. `BridgeView` passes the mandatory `location` argument, defaulting to `Main View` when route params omit it (e.g. deeplink fallback paths). ## **Changelog** <!-- mms-check: type=changelog required=true blocking=true --> <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: null ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: [SWAPS-4539](https://consensyssoftware.atlassian.net/browse/SWAPS-4539) ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> ```gherkin Feature: Unified SwapBridge Page Viewed location attribution Scenario: Page viewed from wallet includes navbar location Given the app is unlocked on the wallet home screen When the user opens Swaps from the wallet trade actions Then a "Unified SwapBridge Page Viewed" event is emitted with location "Main View" Scenario: Page viewed from token details includes token view location Given the user is on a token's asset details screen When the user taps Swap Then a "Unified SwapBridge Page Viewed" event is emitted with location "Token View" Scenario: Asset Viewed includes the same location Given the user navigates into the swap flow from any entry point When the swap page loads and the page viewed event fires Then the companion "Asset Viewed" event includes the same location property ``` Verify events via MetaMetrics debug / Segment inspector or local analytics logging. Unit tests: `yarn jest app/components/UI/Bridge/hooks/useTrackSwapPageViewed/index.test.ts` ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> N/A — analytics-only change; no UI difference. ### **Before** <!-- [screenshots/recordings] --> N/A ### **After** <!-- [screenshots/recordings] --> https://github.com/user-attachments/assets/a895e9f1-b20f-4f70-9408-323aa9c70e8b <img width="987" height="362" alt="Screenshot 2026-06-22 at 4 20 10 PM" src="https://github.com/user-attachments/assets/0f8f62a9-677f-491e-a8e0-25a57d4ee9e9" /> <img width="756" height="311" alt="Screenshot 2026-06-22 at 4 20 24 PM" src="https://github.com/user-attachments/assets/241f2e7e-91e7-4c13-be2b-f35348e298a3" /> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/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-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [ ] 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. [SWAPS-4539]: https://consensyssoftware.atlassian.net/browse/SWAPS-4539?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics-only property addition with no user-facing or transactional behavior changes. > > **Overview** > Adds **`location`** (swap entry point) to **Unified SwapBridge Page Viewed** and the companion **Asset Viewed** events so page views can be attributed the same way as other swap/bridge analytics. > > `useTrackSwapPageViewed` now takes a required `MetaMetricsSwapsEventSource` and includes it in the event payload. **BridgeView** passes navigation `route.params.location`, defaulting to **Main View** when params omit it (e.g. deeplink fallbacks). Unit tests assert `location` on the tracked properties. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2a3fad8. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 994a0de commit 7a23062

3 files changed

Lines changed: 17 additions & 7 deletions

File tree

app/components/UI/Bridge/Views/BridgeView/index.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ import { type BridgeRouteParams } from '../../hooks/useSwapBridgeNavigation/inde
109109
import BridgeTrendingTokensSection from '../../components/BridgeTrendingTokensSection/BridgeTrendingTokensSection';
110110
import { selectRemoteFeatureFlags } from '../../../../../selectors/featureFlagController';
111111
import type { RootState } from '../../../../../reducers';
112+
import { MetaMetricsSwapsEventSource } from '@metamask/bridge-controller';
112113
import { useTrackSwapPageViewed } from '../../hooks/useTrackSwapPageViewed/index.ts';
113114
import { BridgeViewFooter } from './BridgeViewFooter.tsx';
114115
import { getQuoteStreamReasonString } from './BridgeView.utils';
@@ -197,7 +198,8 @@ const BridgeViewContent = ({ latestSourceBalance }: BridgeViewContentProps) => {
197198
const { resetToTokenMode, syncFiatAmountToTokenAmount } = sourceAmountInput;
198199

199200
/** The entry point location for analytics (e.g. Main View, Token View, Trending Explore) */
200-
const location = route.params?.location;
201+
const location =
202+
route.params?.location ?? MetaMetricsSwapsEventSource.MainView;
201203
const transactionActiveAbTests = route.params?.transactionActiveAbTests;
202204

203205
// inputRef is used to programmatically blur the input field after a delay
@@ -385,7 +387,7 @@ const BridgeViewContent = ({ latestSourceBalance }: BridgeViewContentProps) => {
385387
headerTitle = `${strings('swaps.title')}/${strings('bridge.title')}`;
386388
}
387389

388-
useTrackSwapPageViewed();
390+
useTrackSwapPageViewed(location);
389391

390392
const handleSourceMaxPress = () => {
391393
if (latestSourceBalance?.displayBalance) {

app/components/UI/Bridge/hooks/useTrackSwapPageViewed/index.test.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { MetaMetricsSwapsEventSource } from '@metamask/bridge-controller';
12
import { renderHook } from '@testing-library/react-native';
23
import { useSelector } from 'react-redux';
34
import {
@@ -19,6 +20,8 @@ const mockUseSelector = useSelector as jest.MockedFunction<typeof useSelector>;
1920
const mockTrackEvent = jest.fn();
2021
const mockCreateEventBuilder = jest.fn();
2122

23+
const mockLocation = MetaMetricsSwapsEventSource.MainView;
24+
2225
const sourceToken = {
2326
symbol: 'ETH',
2427
chainId: '0x1',
@@ -55,7 +58,7 @@ describe('useTrackSwapPageViewed', () => {
5558
return undefined;
5659
});
5760

58-
renderHook(() => useTrackSwapPageViewed());
61+
renderHook(() => useTrackSwapPageViewed(mockLocation));
5962

6063
expect(mockTrackEvent).not.toHaveBeenCalled();
6164
expect(mockCreateEventBuilder).not.toHaveBeenCalled();
@@ -72,7 +75,7 @@ describe('useTrackSwapPageViewed', () => {
7275
return undefined;
7376
});
7477

75-
renderHook(() => useTrackSwapPageViewed());
78+
renderHook(() => useTrackSwapPageViewed(mockLocation));
7679

7780
const expectedPageProperties = {
7881
chain_id_source: '1',
@@ -81,6 +84,7 @@ describe('useTrackSwapPageViewed', () => {
8184
token_symbol_destination: 'USDC',
8285
token_address_source: sourceToken.address,
8386
token_address_destination: destToken.address,
87+
location: mockLocation,
8488
};
8589

8690
expect(mockTrackEvent).toHaveBeenCalledTimes(2);
@@ -115,7 +119,7 @@ describe('useTrackSwapPageViewed', () => {
115119
return undefined;
116120
});
117121

118-
const { rerender } = renderHook(() => useTrackSwapPageViewed());
122+
const { rerender } = renderHook(() => useTrackSwapPageViewed(mockLocation));
119123

120124
rerender(undefined);
121125

app/components/UI/Bridge/hooks/useTrackSwapPageViewed/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { MetaMetricsSwapsEventSource } from '@metamask/bridge-controller';
12
import { useEffect, useRef } from 'react';
23
import { useSelector } from 'react-redux';
34
import { useAnalytics } from '../../../../hooks/useAnalytics/useAnalytics';
@@ -11,7 +12,9 @@ import {
1112
selectSourceToken,
1213
} from '../../../../../core/redux/slices/bridge';
1314

14-
export const useTrackSwapPageViewed = () => {
15+
export const useTrackSwapPageViewed = (
16+
location: MetaMetricsSwapsEventSource,
17+
) => {
1518
const { trackEvent, createEventBuilder } = useAnalytics();
1619
const sourceToken = useSelector(selectSourceToken);
1720
const destToken = useSelector(selectDestToken);
@@ -30,6 +33,7 @@ export const useTrackSwapPageViewed = () => {
3033
token_symbol_destination: destToken?.symbol,
3134
token_address_source: sourceToken.address,
3235
token_address_destination: destToken?.address,
36+
location,
3337
};
3438
trackEvent(
3539
createEventBuilder(MetaMetricsEvents.SWAP_PAGE_VIEWED)
@@ -44,5 +48,5 @@ export const useTrackSwapPageViewed = () => {
4448
.build(),
4549
);
4650
}
47-
}, [sourceToken, destToken, trackEvent, createEventBuilder]);
51+
}, [sourceToken, destToken, location, trackEvent, createEventBuilder]);
4852
};

0 commit comments

Comments
 (0)