Skip to content

Allow passing groups to feature flags #2010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

SferaDev
Copy link

@SferaDev SferaDev commented Jun 11, 2025

Changes

  • Add support for group evaluation in feature flags and capture events

Closes #2012

Checklist

  • Tests for new code (see advice on the tests we use)
  • Accounted for the impact of any changes across different browsers
  • Accounted for backwards compatibility of any changes (no breaking changes in posthog-js!)
  • Took care not to unnecessarily increase the bundle size

Copy link

vercel bot commented Jun 11, 2025

@SferaDev is attempting to deploy a commit to the PostHog Team on Vercel.

A member of the Team first needs to authorize it.

@SferaDev SferaDev marked this pull request as ready for review June 12, 2025 08:55
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Implements group-based feature flag evaluation in PostHog JS SDK, allowing feature flags to be evaluated in the context of specific groups (e.g., organizations) rather than just user context.

  • Added optional groups parameter to useFeatureFlagEnabled, useFeatureFlagPayload, and useFeatureFlagVariantKey hooks for per-evaluation group context
  • Critical bug: groups parameter not being passed to getFeatureFlagPayload() calls despite being in dependency array
  • Modified PostHogFeature component to support group-based flag evaluation through new groups prop
  • Enhanced capture events to include group context when evaluating feature flags
  • Added comprehensive test coverage for group-based feature flag functionality

11 files reviewed, 9 comments
Edit PR Review Bot Settings | Greptile

})
}, [client, flag])
}, [client, flag, options])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: including 'options' in deps array may cause infinite re-renders if object is recreated on each render

Comment on lines 14 to 16
return client.onFeatureFlags(() => {
setFeatureFlagPayload(client.getFeatureFlagPayload(flag))
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: The groups option is not being passed to getFeatureFlagPayload() here, which means group-based evaluation won't work despite the parameter being added to the function signature

Suggested change
return client.onFeatureFlags(() => {
setFeatureFlagPayload(client.getFeatureFlagPayload(flag))
})
return client.onFeatureFlags(() => {
setFeatureFlagPayload(client.getFeatureFlagPayload(flag, options?.groups))
})

Comment on lines 10 to 12
const [featureFlagVariantKey, setFeatureFlagVariantKey] = useState<string | boolean | undefined>(() =>
client.getFeatureFlag(flag)
client.getFeatureFlag(flag, { send_event: false, ...options })
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider memoizing options object with useMemo to prevent unnecessary re-renders when passing inline objects

export function useFeatureFlagPayload(
flag: string,
options?: { groups?: Record<string, string> }
): JsonType {
const client = usePostHog()

const [featureFlagPayload, setFeatureFlagPayload] = useState<JsonType>(() => client.getFeatureFlagPayload(flag))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Initial call to getFeatureFlagPayload() is missing the groups option, causing inconsistency with subsequent updates

Suggested change
const [featureFlagPayload, setFeatureFlagPayload] = useState<JsonType>(() => client.getFeatureFlagPayload(flag))
const [featureFlagPayload, setFeatureFlagPayload] = useState<JsonType>(() => client.getFeatureFlagPayload(flag, options?.groups))

})
}, [client, flag])
}, [client, flag, options])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Adding 'options' to deps array could cause infinite loops if options object is created inline - needs memoization

Comment on lines +1128 to +1130
const eventPayload =
jest.mocked(posthog._requestQueue!.enqueue).mock.calls[0]?.[0] ||
jest.mocked(posthog._send_retriable_request as any).mock.calls[0][0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider refactoring this payload extraction logic into a test helper function since it's used multiple times

}): JSX.Element {
const clickTrackedRef = useRef(false)
const visibilityTrackedRef = useRef(false)
const posthog = usePostHog()
const variant = useFeatureFlagVariantKey(flag)
const variant = useFeatureFlagVariantKey(flag, { groups })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider moving variant call up to parent component to avoid duplicate feature flag evaluations (already called in lines 28-29)

Comment on lines +35 to +38
// Return different values when groups are passed to test the functionality
if (flag === 'group_specific_flag' && options.groups.team === '123') {
return 'group_variant'
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Magic string 'group_variant' should be defined as a constant at the top of the file

Comment on lines +475 to 476
* @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_called event to PostHog. If {groups: {group_type: group_key}}, we will use the group key to evaluate the flag.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: JSDoc param type doesn't match updated TypeScript type (Object|String vs { send_event?: boolean; groups?: Record<string, string> })

Suggested change
* @param {Object|String} options (optional) If {send_event: false}, we won't send an $feature_flag_called event to PostHog. If {groups: {group_type: group_key}}, we will use the group key to evaluate the flag.
*/
* @param {{ send_event?: boolean; groups?: Record<string, string> }} options (optional) If {send_event: false}, we won't send an $feature_flag_called event to PostHog. If {groups: {group_type: group_key}}, we will use the group key to evaluate the flag.
*/

@posthog-bot
Copy link
Collaborator

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow evaluating feature flags with groups
2 participants