Skip to content

Feat/support for Enriched flag analytics - #487

Merged
ioannisj merged 19 commits into
PostHog:mainfrom
jeremiahseun:feat/enriched-flag-analytic
Mar 11, 2026
Merged

ioannisj merged 19 commits into
PostHog:mainfrom
jeremiahseun:feat/enriched-flag-analytic

Conversation

@jeremiahseun

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

This PR adds support for Enriched Flag Analytics, resolving #478. These changes allow developers to track more granular user interactions with feature flags.

Specifically, it adds:

  • captureFeatureView(_:): Captures a $feature_view event for the specified flag.
  • captureFeatureInteraction(_:): Captures a $feature_interaction event and sets a person property ($feature_interaction/[feature_flag] = true) to track that the interaction has occurred.

These events enable deeper insights into flag performance and user engagement within PostHog.

💚 How did you test it?

I implemented a comprehensive test suite in PostHogEnrichedAnalyticsTest.swift covering:

  • Correct event names and properties for both view and interaction calls.
  • Verification of person property updates during interaction capture.
  • Proper handling of opt-out and disabled SDK states.

During testing, I identified and fixed a scenario where lifecycle events (like Application Installed) interfered with batch counts. This was resolved by disabling captureApplicationLifecycleEvents in the test configuration, ensuring stable and deterministic test results.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file
  • Added the release label to the PR

jeremiahseun and others added 12 commits February 18, 2026 14:30
- Added `captureDeepLinks` option to `PostHogConfig` (default: true).
- Implemented `PostHogDeepLinkIntegration` to automatically track deep link opens and referrer information.
- Swizzles `UIApplicationDelegate` and `UISceneDelegate` methods to capture `Deep Link Opened` events.
- Captures `$referrer` and `$referring_domain` properties when available.
Added a guide on how to test the automatic deep link capture feature.
Added a guide on how to test the automatic deep link capture feature.
Added a guide on how to test the automatic deep link capture feature.
Add and improve deep-link handling and testability: introduce buildDeepLinkProperties and refactor trackDeepLink, enhance swizzling (including scene(_:willConnectTo:options:) handling) and move swizzled/fallback implementations onto NSObject for injection. Add unit tests (PostHogDeepLinkIntegrationTests) and an example Info.plist for PostHogExample. Update Xcode project to include new files, set INFOPLIST_FILE, disable GENERATE_INFOPLIST_FILE, and add runpath entries. Add TESTING compiler define for debug in Package.swift. Also: fix SwiftUI target class name extraction in autocapture, adjust Session Replay test imports and NSNull handling, and trim manual testing steps from TESTING_DEEP_LINKS.md.
feat: Automatically capture deep link events
…matically"

This reverts commit 995939a, reversing
changes made to 43af806.
@jeremiahseun
jeremiahseun requested a review from a team as a code owner February 20, 2026 10:52
Comment thread PostHog/PostHogSDK.swift Resolved
@marandaneto
marandaneto requested a review from a team February 20, 2026 10:59
Add optional flagVariant parameter to captureFeatureView and captureFeatureInteraction. Build event properties to include feature_flag and, when available as a string, feature_flag_variant. User properties now include a "$feature_view/<flag>" or "$feature_interaction/<flag>" entry set to the resolved variant (falls back to getFeatureFlag(... ) or true). Update tests to call the new signatures and assert the user property is set.
Comment thread PostHog/PostHogSDK.swift Outdated
"feature_flag": flag,
]

let variant: Any = flagVariant ?? getFeatureFlag(flag, sendEvent: false) ?? true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should we assume a variant value here? I think it would be better to guard at the top, log and return no-op. Same for captureFeatureView()

@marandaneto since you reviewed the Android implementation, wdyt?

// Get the variant value
guard let variant = flagVariant ?? getFeatureFlag(flag, sendEvent: false) else {
    // No variant available, don't capture the event and log
    hedgeLog("...")
    return
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nope, if theres no variant that means its just a normal flag so defaults to true similar to android impl

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

actually, i think we shouldve called getFeatureFlagPayload instead
https://posthog.com/docs/libraries/js/usage#multivariate-feature-flags
i think android is wrong as well then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

unresolved because i am unsure
the goal is to default the variant if not provided
but it should not default to true if getFeatureFlag returns nil

@ioannisj ioannisj Feb 20, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

which also calls https://github.com/PostHog/posthog-js/blob/755c2d7c73250e130e7975050d4e628fa1b811b3/packages/react/src/hooks/useFeatureFlagVariantKey.ts#L13
so the current implementation meets the JS SDK
the only issue is that if somebody calls captureInteraction(x)/captureFeature(x) and x does not exist, its still gonna be captured instead of no-op, not sure if this is the correct implementation

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the flag should exist locally otherwise we should bail out
the suggestion @ioannisj mentioned would work #487 (comment)
@jeremiahseun mind fixing this so we can get this merged?
we prob need to fix this on android as well

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Alright then

@ioannisj

Copy link
Copy Markdown
Contributor

@jeremiahseun Loog good. Left a comment on unit tests. Also don't forget to run pnpm changeset

Do not record feature view/interaction events when no variant is available. In PostHogSDK.swift the code now prefers an explicitly passed variant and falls back to a flag lookup, but will early-return (with a log) if neither provides a value instead of defaulting to true. Tests in PostHogEnrichedAnalyticsTest.swift were updated to pass an explicit "control" variant where needed, to expect feature_flag_variant as a string, and to add cases asserting no events are captured when no variant is available. This prevents emitting meaningless feature events and aligns the $set values to the variant string.
@jeremiahseun

Copy link
Copy Markdown
Contributor Author

You can check it now @ioannisj @marandaneto

@ioannisj
ioannisj enabled auto-merge (squash) March 11, 2026 10:57
@ioannisj
ioannisj disabled auto-merge March 11, 2026 11:19
@ioannisj
ioannisj merged commit 8f44e92 into PostHog:main Mar 11, 2026
28 of 30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants