- <>
-
- PostHog offers several tools to let you control the number of recordings you collect and which users
- you collect recordings for.{' '}
-
- Learn more in our docs
-
-
-
- Requires posthog-js version 1.88.2 or greater
-
-
- Sampling
- {
- updateCurrentTeam({ session_recording_sample_rate: v })
- }}
- dropdownMatchSelectWidth={false}
- options={[
- {
- label: '100% (no sampling)',
- value: '1.00',
- },
- {
- label: '95%',
- value: '0.95',
- },
- {
- label: '90%',
- value: '0.90',
- },
- {
- label: '85%',
- value: '0.85',
- },
- {
- label: '80%',
- value: '0.80',
- },
- {
- label: '75%',
- value: '0.75',
- },
- {
- label: '70%',
- value: '0.70',
- },
- {
- label: '65%',
- value: '0.65',
- },
- {
- label: '60%',
- value: '0.60',
- },
- {
- label: '55%',
- value: '0.55',
- },
- {
- label: '50%',
- value: '0.50',
- },
- {
- label: '45%',
- value: '0.45',
- },
- {
- label: '40%',
- value: '0.40',
- },
- {
- label: '35%',
- value: '0.35',
- },
- {
- label: '30%',
- value: '0.30',
- },
- {
- label: '25%',
- value: '0.25',
- },
- {
- label: '20%',
- value: '0.20',
- },
- {
- label: '15%',
- value: '0.15',
- },
- {
- label: '10%',
- value: '0.10',
- },
- {
- label: '5%',
- value: '0.05',
- },
- {
- label: '0% (replay disabled)',
- value: '0.00',
- },
- ]}
- value={
- typeof currentTeam?.session_recording_sample_rate === 'string'
- ? currentTeam?.session_recording_sample_rate
- : '1.00'
- }
- />
-
-
- Use this setting to restrict the percentage of sessions that will be recorded. This is useful if you
- want to reduce the amount of data you collect. 100% means all sessions will be collected. 50% means
- roughly half of sessions will be collected.
-
-
- Minimum session duration (seconds)
- {
- updateCurrentTeam({ session_recording_minimum_duration_milliseconds: v })
- }}
- options={SESSION_REPLAY_MINIMUM_DURATION_OPTIONS}
- value={currentTeam?.session_recording_minimum_duration_milliseconds}
- />
-
-
- Setting a minimum session duration will ensure that only sessions that last longer than that value
- are collected. This helps you avoid collecting sessions that are too short to be useful.
-
-
-
Enable recordings using feature flag
-
-
{
- updateCurrentTeam({ session_recording_linked_flag: { id, key } })
+ return costControlFeaturesEnabled ? (
+ <>
+
+ PostHog offers several tools to let you control the number of recordings you collect and which users you
+ collect recordings for.{' '}
+
+ Learn more in our docs
+
+
+
+ Requires posthog-js version 1.88.2 or greater
+
+ {(featureFlags[FEATURE_FLAGS.SESSION_RECORDING_SAMPLING] || samplingControlFeatureEnabled) && (
+ <>
+
+ Sampling
+ {
+ updateCurrentTeam({ session_recording_sample_rate: v })
+ }}
+ dropdownMatchSelectWidth={false}
+ options={[
+ {
+ label: '100% (no sampling)',
+ value: '1.00',
+ },
+ {
+ label: '95%',
+ value: '0.95',
+ },
+ {
+ label: '90%',
+ value: '0.90',
+ },
+ {
+ label: '85%',
+ value: '0.85',
+ },
+ {
+ label: '80%',
+ value: '0.80',
+ },
+ {
+ label: '75%',
+ value: '0.75',
+ },
+ {
+ label: '70%',
+ value: '0.70',
+ },
+ {
+ label: '65%',
+ value: '0.65',
+ },
+ {
+ label: '60%',
+ value: '0.60',
+ },
+ {
+ label: '55%',
+ value: '0.55',
+ },
+ {
+ label: '50%',
+ value: '0.50',
+ },
+ {
+ label: '45%',
+ value: '0.45',
+ },
+ {
+ label: '40%',
+ value: '0.40',
+ },
+ {
+ label: '35%',
+ value: '0.35',
+ },
+ {
+ label: '30%',
+ value: '0.30',
+ },
+ {
+ label: '25%',
+ value: '0.25',
+ },
+ {
+ label: '20%',
+ value: '0.20',
+ },
+ {
+ label: '15%',
+ value: '0.15',
+ },
+ {
+ label: '10%',
+ value: '0.10',
+ },
+ {
+ label: '5%',
+ value: '0.05',
+ },
+ {
+ label: '0% (replay disabled)',
+ value: '0.00',
+ },
+ ]}
+ value={
+ typeof currentTeam?.session_recording_sample_rate === 'string'
+ ? currentTeam?.session_recording_sample_rate
+ : '1.00'
+ }
+ />
+
+
+ Use this setting to restrict the percentage of sessions that will be recorded. This is useful if
+ you want to reduce the amount of data you collect. 100% means all sessions will be collected.
+ 50% means roughly half of sessions will be collected.
+
+ >
+ )}
+ {(featureFlags[FEATURE_FLAGS.SESSION_RECORDING_SAMPLING] || recordingDurationMinimumFeatureEnabled) && (
+ <>
+
+ Minimum session duration (seconds)
+ {
+ updateCurrentTeam({ session_recording_minimum_duration_milliseconds: v })
}}
+ options={SESSION_REPLAY_MINIMUM_DURATION_OPTIONS}
+ value={currentTeam?.session_recording_minimum_duration_milliseconds}
/>
- {currentTeam?.session_recording_linked_flag && (
- }
- size="small"
- onClick={() => updateCurrentTeam({ session_recording_linked_flag: null })}
- title="Clear selected flag"
+
+
+ Setting a minimum session duration will ensure that only sessions that last longer than that
+ value are collected. This helps you avoid collecting sessions that are too short to be useful.
+
+ >
+ )}
+ {(featureFlags[FEATURE_FLAGS.SESSION_RECORDING_SAMPLING] || featureFlagRecordingFeatureEnabled) && (
+ <>
+
+
Enable recordings using feature flag
+
+ {
+ updateCurrentTeam({ session_recording_linked_flag: { id, key } })
+ }}
/>
- )}
+ {currentTeam?.session_recording_linked_flag && (
+ }
+ size="small"
+ type="secondary"
+ onClick={() => updateCurrentTeam({ session_recording_linked_flag: null })}
+ title="Clear selected flag"
+ />
+ )}
+
-
-
- Linking a flag means that recordings will only be collected for users who have the flag enabled.
- Only supports release toggles (boolean flags).
-
- >
-
+
+ Linking a flag means that recordings will only be collected for users who have the flag enabled.
+ Only supports release toggles (boolean flags).
+
+ >
+ )}
+ >
+ ) : (
+ <>>
)
}
diff --git a/frontend/src/scenes/settings/settingsLogic.ts b/frontend/src/scenes/settings/settingsLogic.ts
index 8af9bb55f8475..f727e2a2dfe50 100644
--- a/frontend/src/scenes/settings/settingsLogic.ts
+++ b/frontend/src/scenes/settings/settingsLogic.ts
@@ -3,6 +3,7 @@ import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { copyToClipboard } from 'lib/utils/copyToClipboard'
import { urls } from 'scenes/urls'
+import { userLogic } from 'scenes/userLogic'
import type { settingsLogicType } from './settingsLogicType'
import { SettingsMap } from './SettingsMap'
@@ -13,7 +14,7 @@ export const settingsLogic = kea
([
key((props) => props.logicKey ?? 'global'),
path((key) => ['scenes', 'settings', 'settingsLogic', key]),
connect({
- values: [featureFlagLogic, ['featureFlags']],
+ values: [featureFlagLogic, ['featureFlags'], userLogic, ['hasAvailableFeature']],
}),
actions({
@@ -65,8 +66,8 @@ export const settingsLogic = kea([
},
],
settings: [
- (s) => [s.selectedLevel, s.selectedSectionId, s.sections, s.featureFlags],
- (selectedLevel, selectedSectionId, sections, featureFlags): Setting[] => {
+ (s) => [s.selectedLevel, s.selectedSectionId, s.sections, s.featureFlags, s.hasAvailableFeature],
+ (selectedLevel, selectedSectionId, sections, featureFlags, hasAvailableFeature): Setting[] => {
let settings: Setting[] = []
if (!selectedSectionId) {
@@ -77,7 +78,19 @@ export const settingsLogic = kea([
settings = sections.find((x) => x.id === selectedSectionId)?.settings || []
}
- return settings.filter((x) => (x.flag ? featureFlags[FEATURE_FLAGS[x.flag]] : true))
+ return settings.filter((x) => {
+ if (x.flag && x.features) {
+ return (
+ x.features.some((feat) => hasAvailableFeature(feat)) || featureFlags[FEATURE_FLAGS[x.flag]]
+ )
+ } else if (x.features) {
+ return x.features.some((feat) => hasAvailableFeature(feat))
+ } else if (x.flag) {
+ return featureFlags[FEATURE_FLAGS[x.flag]]
+ }
+
+ return true
+ })
},
],
}),
diff --git a/frontend/src/scenes/settings/types.ts b/frontend/src/scenes/settings/types.ts
index d57e2273fc765..6dad2d9f75193 100644
--- a/frontend/src/scenes/settings/types.ts
+++ b/frontend/src/scenes/settings/types.ts
@@ -1,5 +1,7 @@
import { EitherMembershipLevel, FEATURE_FLAGS } from 'lib/constants'
+import { AvailableFeature } from '~/types'
+
export type SettingsLogicProps = {
logicKey?: string
// Optional - if given, renders only the given level
@@ -78,6 +80,7 @@ export type Setting = {
description?: JSX.Element | string
component: JSX.Element
flag?: keyof typeof FEATURE_FLAGS
+ features?: AvailableFeature[]
}
export type SettingSection = {
diff --git a/frontend/src/types.ts b/frontend/src/types.ts
index 36483bbdd9eb5..efdb944d97756 100644
--- a/frontend/src/types.ts
+++ b/frontend/src/types.ts
@@ -41,7 +41,7 @@ import { NodeKind } from './queries/schema'
export type Optional = Omit & { [K in keyof T]?: T[K] }
-// Keep this in sync with backend constants (constants.py)
+// Keep this in sync with backend constants/features/{product_name}.yml
export enum AvailableFeature {
EVENTS = 'events',
TRACKED_USERS = 'tracked_users',
@@ -91,6 +91,9 @@ export enum AvailableFeature {
SURVEYS_STYLING = 'surveys_styling',
SURVEYS_TEXT_HTML = 'surveys_text_html',
SURVEYS_MULTIPLE_QUESTIONS = 'surveys_multiple_questions',
+ SESSION_REPLAY_SAMPLING = 'session_replay_sampling',
+ RECORDING_DURATION_MINIMUM = 'replay_recording_duration_minimum',
+ FEATURE_FLAG_BASED_RECORDING = 'replay_feature_flag_based_recording',
}
export enum ProductKey {