Skip to content

Commit 029d028

Browse files
authored
feat(replay): Track mobile replay network capture adoption (#6428)
* feat(core): Track GlobalErrorBoundary adoption Register a no-op `GlobalErrorBoundary` integration when the component mounts so the name flows through to `event.sdk.integrations` — the same channel used for feature- adoption signals like `MobileFeedback` and `AppStart`. Also introduces a shared `registerFeatureMarker` helper. Subsequent markers for other opt-in features (NavigationContainer, ExpoRouter error boundary, AppLoaded, ...) will use this helper — see #6415. Refs: #6415 * feat(replay): Track mobile replay network capture adoption Register no-op `MobileReplayNetworkDetails` and `MobileReplayNetworkBodies` integrations at replay setup when the corresponding options are configured, so the names flow through to `event.sdk.integrations`. Two markers give a clean funnel: replay on → network details on (any `networkDetailAllowUrls`) → bodies on (`networkCaptureBodies`, defaults to true). Refs: #6415
1 parent da20ca9 commit 029d028

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

packages/core/src/js/replay/mobilereplay.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import type { ResolvedNetworkOptions } from './networkUtils';
77
import { isHardCrash } from '../misc';
88
import { hasHooks } from '../utils/clientutils';
99
import { isExpoGo, notMobileOs } from '../utils/environment';
10+
import { registerFeatureMarker } from '../utils/featureMarkers';
1011
import { NATIVE } from '../wrapper';
1112
import { makeEnrichXhrBreadcrumbsForMobileReplay } from './xhrUtils';
1213

14+
const MOBILE_REPLAY_NETWORK_DETAILS_INTEGRATION_NAME = 'MobileReplayNetworkDetails';
15+
const MOBILE_REPLAY_NETWORK_BODIES_INTEGRATION_NAME = 'MobileReplayNetworkBodies';
16+
1317
export const MOBILE_REPLAY_INTEGRATION_NAME = 'MobileReplay';
1418

1519
/**
@@ -387,6 +391,13 @@ export const mobileReplayIntegration = (initOptions: MobileReplayOptions = defau
387391
return;
388392
}
389393

394+
if ((options.networkDetailAllowUrls?.length ?? 0) > 0) {
395+
registerFeatureMarker(MOBILE_REPLAY_NETWORK_DETAILS_INTEGRATION_NAME, client);
396+
if (options.networkCaptureBodies ?? true) {
397+
registerFeatureMarker(MOBILE_REPLAY_NETWORK_BODIES_INTEGRATION_NAME, client);
398+
}
399+
}
400+
390401
// Initialize the cached replay ID on setup
391402
cachedReplayId = NATIVE.getCurrentReplayId();
392403

packages/core/test/replay/mobilereplay.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,50 @@ describe('Mobile Replay Integration', () => {
534534
});
535535
});
536536

537+
describe('network detail feature markers', () => {
538+
let mockAddIntegration: jest.Mock;
539+
let mockGetIntegrationByName: jest.Mock;
540+
let markerClient: jest.Mocked<Client>;
541+
542+
beforeEach(() => {
543+
mockAddIntegration = jest.fn();
544+
mockGetIntegrationByName = jest.fn().mockReturnValue(undefined);
545+
markerClient = {
546+
on: jest.fn(),
547+
getOptions: jest.fn(() => ({})),
548+
getIntegrationByName: mockGetIntegrationByName,
549+
addIntegration: mockAddIntegration,
550+
} as unknown as jest.Mocked<Client>;
551+
});
552+
553+
it('does not register network markers when networkDetailAllowUrls is empty', () => {
554+
const integration = mobileReplayIntegration({ networkDetailAllowUrls: [] });
555+
integration.setup?.(markerClient);
556+
557+
expect(mockAddIntegration).not.toHaveBeenCalledWith({ name: 'MobileReplayNetworkDetails' });
558+
expect(mockAddIntegration).not.toHaveBeenCalledWith({ name: 'MobileReplayNetworkBodies' });
559+
});
560+
561+
it('registers both markers when networkDetailAllowUrls is set (bodies default true)', () => {
562+
const integration = mobileReplayIntegration({ networkDetailAllowUrls: ['https://api.example.com'] });
563+
integration.setup?.(markerClient);
564+
565+
expect(mockAddIntegration).toHaveBeenCalledWith({ name: 'MobileReplayNetworkDetails' });
566+
expect(mockAddIntegration).toHaveBeenCalledWith({ name: 'MobileReplayNetworkBodies' });
567+
});
568+
569+
it('registers only the details marker when bodies are explicitly disabled', () => {
570+
const integration = mobileReplayIntegration({
571+
networkDetailAllowUrls: ['https://api.example.com'],
572+
networkCaptureBodies: false,
573+
});
574+
integration.setup?.(markerClient);
575+
576+
expect(mockAddIntegration).toHaveBeenCalledWith({ name: 'MobileReplayNetworkDetails' });
577+
expect(mockAddIntegration).not.toHaveBeenCalledWith({ name: 'MobileReplayNetworkBodies' });
578+
});
579+
});
580+
537581
describe('platform checks', () => {
538582
it('should return noop integration in Expo Go', () => {
539583
jest.spyOn(environment, 'isExpoGo').mockReturnValue(true);

0 commit comments

Comments
 (0)