Repository: getsentry/sentry
Pull request: feat(SR): Add SR to Mobile project onboarding features
🛑 we decided to only merge the [Android changes](https://github.com/getsentry/sentry/pull/87408) now, will review iOS+RN when new view renderer is default 🛑 

Adds SR config snippets to onboarding feature snippets for iOS/RN as applicable (Flutter will follow in 1-2 months):

- ✅ iOS
- ✅ RN

Note: this PR also changes the order of the product selection buttons -> split out into https://github.com/getsentry/sentry/pull/87412

related PR for sentry-docs: https://github.com/getsentry/sentry-docs/pull/13034

fixes https://github.com/getsentry/sentry/issues/84250

Problem statement:
[New Org/Project Creation] Add Mobile Replay Instructions, Opt-in Only
## Add Mobile Replay Onboarding Instructions

- to the new org/project creation flow
- covers iOS, Android, and React Native (excl. Flutter until it's out of beta)
- default to replay being 'unchecked'/not enabled
- user analytics to track this funnel (1) users that land on the new org/project creation flow for mobile and (2) what % send replays

Hints from issue discussion:
Routing to @getsentry/product-owners-replays for [triage](https://develop.sentry.dev/processing-tickets/#3-triage) ⏲️

Commit message: add SR feature to iOS onboarding

Patch to review:
diff --git a/static/app/components/onboarding/productSelection.tsx b/static/app/components/onboarding/productSelection.tsx
index 225ffb22fe632f..07d9905b371d21 100644
--- a/static/app/components/onboarding/productSelection.tsx
+++ b/static/app/components/onboarding/productSelection.tsx
@@ -76,8 +76,16 @@ function getDisabledProducts(organization: Organization): DisabledProducts {
 // Since the ProductSelection component is rendered in the onboarding/project creation flow only, it is ok to have this list here
 // NOTE: Please keep the prefix in alphabetical order
 export const platformProductAvailability = {
-  android: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
-  'apple-ios': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
+  android: [
+    ProductSolution.PERFORMANCE_MONITORING,
+    ProductSolution.PROFILING,
+    ProductSolution.SESSION_REPLAY,
+  ],
+  'apple-ios': [
+    ProductSolution.PERFORMANCE_MONITORING,
+    ProductSolution.PROFILING,
+    ProductSolution.SESSION_REPLAY,
+  ],
   'apple-macos': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   bun: [ProductSolution.PERFORMANCE_MONITORING],
   capacitor: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.SESSION_REPLAY],
@@ -187,7 +195,11 @@ export const platformProductAvailability = {
   'python-tornado': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-starlette': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'python-wsgi': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
-  'react-native': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
+  'react-native': [
+    ProductSolution.PERFORMANCE_MONITORING,
+    ProductSolution.PROFILING,
+    ProductSolution.SESSION_REPLAY,
+  ],
   ruby: [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'ruby-rack': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
   'ruby-rails': [ProductSolution.PERFORMANCE_MONITORING, ProductSolution.PROFILING],
@@ -391,18 +403,6 @@ export function ProductSelection({
           checked={urlProducts.includes(ProductSolution.PERFORMANCE_MONITORING)}
         />
       )}
-      {products.includes(ProductSolution.SESSION_REPLAY) && (
-        <Product
-          label={t('Session Replay')}
-          description={t(
-            'Video-like reproductions of user sessions with debugging context to help you confirm issue impact and troubleshoot faster.'
-          )}
-          docLink="https://docs.sentry.io/platforms/javascript/guides/react/session-replay/"
-          onClick={() => handleClickProduct(ProductSolution.SESSION_REPLAY)}
-          disabled={disabledProducts[ProductSolution.SESSION_REPLAY]}
-          checked={urlProducts.includes(ProductSolution.SESSION_REPLAY)}
-        />
-      )}
       {products.includes(ProductSolution.PROFILING) && (
         <Product
           label={t('Profiling')}
@@ -418,6 +418,18 @@ export function ProductSelection({
           checked={urlProducts.includes(ProductSolution.PROFILING)}
         />
       )}
+      {products.includes(ProductSolution.SESSION_REPLAY) && (
+        <Product
+          label={t('Session Replay')}
+          description={t(
+            'Video-like reproductions of user sessions with debugging context to help you confirm issue impact and troubleshoot faster.'
+          )}
+          docLink="https://docs.sentry.io/platforms/javascript/guides/react/session-replay/"
+          onClick={() => handleClickProduct(ProductSolution.SESSION_REPLAY)}
+          disabled={disabledProducts[ProductSolution.SESSION_REPLAY]}
+          checked={urlProducts.includes(ProductSolution.SESSION_REPLAY)}
+        />
+      )}
     </Products>
   );
 }
diff --git a/static/app/gettingStartedDocs/android/android.tsx b/static/app/gettingStartedDocs/android/android.tsx
index ec4ad41829ee8a..4790017db546aa 100644
--- a/static/app/gettingStartedDocs/android/android.tsx
+++ b/static/app/gettingStartedDocs/android/android.tsx
@@ -88,6 +88,14 @@ const getConfigurationSnippet = (params: Params) => `
   <!-- see https://docs.sentry.io/platforms/android/profiling/troubleshooting/ -->
   <meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="1.0" />`
       : ''
+  }${
+    params.isReplaySelected
+      ? `
+
+  <!-- record session replays for 100% of errors and 10% of sessions -->
+  <meta-data android:name="io.sentry.session-replay.on-error-sample-rate" android:value="1.0" />
+  <meta-data android:name="io.sentry.session-replay.session-sample-rate" android:value="0.1" />`
+      : ''
   }
 </application>`;
 
diff --git a/static/app/gettingStartedDocs/apple/ios.tsx b/static/app/gettingStartedDocs/apple/ios.tsx
index ca717ec398bf4e..4544d1e500e06f 100644
--- a/static/app/gettingStartedDocs/apple/ios.tsx
+++ b/static/app/gettingStartedDocs/apple/ios.tsx
@@ -86,6 +86,16 @@ func application(_ application: UIApplication,
         // We recommend adjusting this value in production.
         options.profilesSampleRate = 1.0`
             : ''
+        }${
+          params.isReplaySelected
+            ? `
+
+        // Record Session Replays for 100% of Errors and 10% of Sessions
+        options.sessionReplay.onErrorSampleRate = 1.0
+        options.sessionReplay.sessionSampleRate = 0.1
+        // We recommend the ~5x more performant experimental view renderer
+        options.sessionReplay.enableExperimentalViewRenderer = true`
+            : ''
         }
     }${
       params.isProfilingSelected &&
@@ -135,6 +145,16 @@ struct SwiftUIApp: App {
             // We recommend adjusting this value in production.
             options.profilesSampleRate = 1.0`
                 : ''
+            }${
+              params.isReplaySelected
+                ? `
+
+            // Record Session Replays for 100% of Errors and 10% of Sessions
+            options.sessionReplay.onErrorSampleRate = 1.0
+            options.sessionReplay.sessionSampleRate = 0.1
+            // We recommend the ~5x more performant experimental view renderer
+            options.sessionReplay.enableExperimentalViewRenderer = true`
+                : ''
             }
         }${
           params.isProfilingSelected &&
diff --git a/static/app/gettingStartedDocs/react-native/react-native.tsx b/static/app/gettingStartedDocs/react-native/react-native.tsx
index f2c9eb52d58898..c31a9ab25dcda6 100644
--- a/static/app/gettingStartedDocs/react-native/react-native.tsx
+++ b/static/app/gettingStartedDocs/react-native/react-native.tsx
@@ -73,6 +73,14 @@ Sentry.init({
   // Here, we'll capture profiles for 100% of transactions.
   profilesSampleRate: 1.0,`
       : ''
+  }${
+    params.isReplaySelected
+      ? `
+  // Record Session Replays for 10% of Sessions and 100% of Errors
+  replaysSessionSampleRate: 0.1,
+  replaysOnErrorSampleRate: 1.0,
+  integrations: [Sentry.mobileReplayIntegration()],`
+      : ''
   }
 });`;
 


Code review comments:
diff_hunk: @@ -135,6 +145,16 @@ struct SwiftUIApp: App {
             // We recommend adjusting this value in production.
             options.profilesSampleRate = 1.0`
                 : ''
+            }${
+              params.isReplaySelected
+                ? `
+
+            // Record Session Replays for 100% of Errors and 10% of Sessions
+            options.sessionReplay.onErrorSampleRate = 1.0
+            options.sessionReplay.sessionSampleRate = 0.1
+            // We recommend the ~5x more performant experimental view renderer
path: static/app/gettingStartedDocs/apple/ios.tsx
text: @author:
we need to decide if we want to point this out here. IMO we should, or we postpone this PR for iOS (and RN, see below)

@user1:
Make sense to me as well.

diff_hunk: @@ -418,6 +418,18 @@ export function ProductSelection({
           checked={urlProducts.includes(ProductSolution.PROFILING)}
         />
       )}
+      {products.includes(ProductSolution.SESSION_REPLAY) && (
+        <Product
+          label={t('Session Replay')}
+          description={t(
+            'Video-like reproductions of user sessions with debugging context to help you confirm issue impact and troubleshoot faster.'
+          )}
+          docLink="https://docs.sentry.io/platforms/javascript/guides/react/session-replay/"
path: static/app/components/onboarding/productSelection.tsx
text: @user1:
i know the other links are also platform-specific too, but curious why these links are platform-specific and not linking to the general product docs

@author:
good point - IMO makes sense to link to product docs for all of these (in a separate PR?)

@user1:
works for me!

@author:
split it out to https://github.com/getsentry/sentry/pull/87412