Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0190ce7
include to project
Nov 20, 2025
5ba7f64
YODEVMOB-2581 posthog events
Nov 20, 2025
f2bb73f
add isForceSendFlag in param getFeatureFlag
Nov 20, 2025
0d8b70a
updated https://github.com/PostHog/posthog-android/pull/319
Nov 21, 2025
6bbe0a9
add sendFeatureFlagEvent in param getFeatureFlag
Nov 24, 2025
42dab4a
add sendFeatureFlagEvent in param getFeatureFlag
Nov 24, 2025
c3cf5f2
add sendFeatureFlagEvent in param getFeatureFlag
Nov 24, 2025
c09e765
add sendFeatureFlagEvent in param getFeatureFlag
Nov 24, 2025
90c3359
add sendFeatureFlagEvent in param getFeatureFlag
Nov 25, 2025
8387163
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Nov 25, 2025
41b0653
add sendFeatureFlagEvent in param getFeatureFlag
Nov 25, 2025
521ba4c
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Nov 25, 2025
c097384
fix format
Nov 26, 2025
b87eeb1
Add tests
Nov 26, 2025
b6ebb30
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Nov 26, 2025
573cb19
fix tests
Nov 26, 2025
c5d1ded
Merge commit 'b6ebb3049bc8fe539854228781fc9e144a0b8188' into bugfix/f…
Nov 26, 2025
bf3882c
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Nov 26, 2025
bcfda73
add changelog
Nov 28, 2025
6c991fc
Merge commit 'bf3882cf2fd7d59224984179572e65ebde2df181' into bugfix/f…
Nov 28, 2025
033df5b
run format code
Nov 28, 2025
b43109a
fix posthog.api
Dec 1, 2025
9ebf7e2
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 1, 2025
cbb2170
changelog
Dec 1, 2025
fbda2ca
Merge commit '9ebf7e240a17c1a9d4876c0f2c5b6508826fbe5d' into bugfix/f…
Dec 1, 2025
3d01822
Merge remote-tracking branch 'origin/main' into bugfix/filter_events
Dec 1, 2025
af87c91
Merge remote-tracking branch 'origin/main' into bugfix/filter_events
Dec 2, 2025
edaf17c
change log
Dec 2, 2025
f951693
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
a2d0100
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
2460f97
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
19757a2
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
69cbdc5
format
marandaneto Dec 2, 2025
6b1dd3a
Merge remote-tracking branch 'origin/main' into bugfix/filter_events
Dec 2, 2025
2c5c623
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
fa09a12
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 2, 2025
85590a4
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 3, 2025
e56a8ca
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 3, 2025
c67c691
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 4, 2025
481a031
Merge branch 'main' into bugfix/filter_events
KopeikinaDarya Dec 4, 2025
1ec548a
Merge branch 'main' into bugfix/filter_events
marandaneto Dec 8, 2025
b753a1b
fix changelog
marandaneto Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions posthog-android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## Next

- feat: add `sendFeatureFlagEvent` properties in function getFeatureFlag() for override config's
sendFeatureFlagEvent ([#319](https://github.com/PostHog/posthog-android/pull/319))

## 3.27.2 - 2025-12-03

- fix: NoSuchMethodError PostHogAndroidConfig ([#342](https://github.com/PostHog/posthog-android/pull/342))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ public class PostHogFake : PostHogInterface {
override fun isFeatureEnabled(
key: String,
defaultValue: Boolean,
sendFeatureFlagEvent: Boolean?,
): Boolean {
return false
}

override fun getFeatureFlag(
key: String,
defaultValue: Any?,
sendFeatureFlagEvent: Boolean?,
): Any? {
return null
}
Expand Down
16 changes: 8 additions & 8 deletions posthog/api/posthog.api
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ public final class com/posthog/PostHog : com/posthog/PostHogStateless, com/posth
public fun endSession ()V
public fun flush ()V
public fun getConfig ()Lcom/posthog/PostHogConfig;
public fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;)Ljava/lang/Object;
public fun getFeatureFlagPayload (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public fun getSessionId ()Ljava/util/UUID;
public fun group (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V
public fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V
public fun isFeatureEnabled (Ljava/lang/String;Z)Z
public fun isFeatureEnabled (Ljava/lang/String;ZLjava/lang/Boolean;)Z
public fun isOptOut ()Z
public fun isSessionActive ()Z
public fun isSessionReplayActive ()Z
Expand Down Expand Up @@ -53,12 +53,12 @@ public final class com/posthog/PostHog$Companion : com/posthog/PostHogInterface
public fun endSession ()V
public fun flush ()V
public fun getConfig ()Lcom/posthog/PostHogConfig;
public fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;)Ljava/lang/Object;
public fun getFeatureFlagPayload (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public fun getSessionId ()Ljava/util/UUID;
public fun group (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V
public fun identify (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V
public fun isFeatureEnabled (Ljava/lang/String;Z)Z
public fun isFeatureEnabled (Ljava/lang/String;ZLjava/lang/Boolean;)Z
public fun isOptOut ()Z
public fun isSessionActive ()Z
public fun isSessionReplayActive ()Z
Expand Down Expand Up @@ -272,11 +272,11 @@ public abstract interface class com/posthog/PostHogInterface : com/posthog/PostH
public abstract fun distinctId ()Ljava/lang/String;
public abstract fun endSession ()V
public abstract fun getConfig ()Lcom/posthog/PostHogConfig;
public abstract fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public abstract fun getFeatureFlag (Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;)Ljava/lang/Object;
public abstract fun getFeatureFlagPayload (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
public abstract fun getSessionId ()Ljava/util/UUID;
public abstract fun group (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V
public abstract fun isFeatureEnabled (Ljava/lang/String;Z)Z
public abstract fun isFeatureEnabled (Ljava/lang/String;ZLjava/lang/Boolean;)Z
public abstract fun isSessionActive ()Z
public abstract fun isSessionReplayActive ()Z
public abstract fun register (Ljava/lang/String;Ljava/lang/Object;)V
Expand All @@ -296,10 +296,10 @@ public abstract interface class com/posthog/PostHogInterface : com/posthog/PostH
public final class com/posthog/PostHogInterface$DefaultImpls {
public static synthetic fun capture$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/util/Date;ILjava/lang/Object;)V
public static synthetic fun captureException$default (Lcom/posthog/PostHogInterface;Ljava/lang/Throwable;Ljava/util/Map;ILjava/lang/Object;)V
public static synthetic fun getFeatureFlag$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
public static synthetic fun getFeatureFlag$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Boolean;ILjava/lang/Object;)Ljava/lang/Object;
public static synthetic fun getFeatureFlagPayload$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)Ljava/lang/Object;
public static synthetic fun group$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)V
public static synthetic fun isFeatureEnabled$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;ZILjava/lang/Object;)Z
public static synthetic fun isFeatureEnabled$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;ZLjava/lang/Boolean;ILjava/lang/Object;)Z
public static synthetic fun reloadFeatureFlags$default (Lcom/posthog/PostHogInterface;Lcom/posthog/PostHogOnFeatureFlags;ILjava/lang/Object;)V
public static synthetic fun resetGroupPropertiesForFlags$default (Lcom/posthog/PostHogInterface;Ljava/lang/String;ZILjava/lang/Object;)V
public static synthetic fun resetPersonPropertiesForFlags$default (Lcom/posthog/PostHogInterface;ZILjava/lang/Object;)V
Expand Down
124 changes: 85 additions & 39 deletions posthog/src/main/java/com/posthog/PostHog.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public class PostHog private constructor(
config.logger.log("Setup called despite already being setup!")
return
}
config.logger = if (config.logger is PostHogNoOpLogger) PostHogPrintLogger(config) else config.logger
config.logger =
if (config.logger is PostHogNoOpLogger) PostHogPrintLogger(config) else config.logger

if (!apiKeys.add(config.apiKey)) {
config.logger.log("API Key: ${config.apiKey} already has a PostHog instance.")
Expand All @@ -92,8 +93,22 @@ public class PostHog private constructor(
val cachePreferences = config.cachePreferences ?: memoryPreferences
config.cachePreferences = cachePreferences
val api = PostHogApi(config)
val queue = config.queueProvider(config, api, PostHogApiEndpoint.BATCH, config.storagePrefix, queueExecutor)
val replayQueue = config.queueProvider(config, api, PostHogApiEndpoint.SNAPSHOT, config.replayStoragePrefix, replayExecutor)
val queue =
config.queueProvider(
config,
api,
PostHogApiEndpoint.BATCH,
config.storagePrefix,
queueExecutor,
)
val replayQueue =
config.queueProvider(
config,
api,
PostHogApiEndpoint.SNAPSHOT,
config.replayStoragePrefix,
replayExecutor,
)
val featureFlags =
config.remoteConfigProvider(config, api, remoteConfigExecutor) {
getDefaultPersonProperties()
Expand Down Expand Up @@ -178,7 +193,12 @@ public class PostHog private constructor(
// only because of testing in isolation, this flag is always enabled
if (reloadFeatureFlags) {
when {
config.remoteConfig -> loadRemoteConfigRequest(internalOnFeatureFlagsLoaded, config.onFeatureFlags)
config.remoteConfig ->
loadRemoteConfigRequest(
internalOnFeatureFlagsLoaded,
config.onFeatureFlags,
)

config.preloadFeatureFlags -> reloadFeatureFlags(config.onFeatureFlags)
}
}
Expand Down Expand Up @@ -731,8 +751,9 @@ public class PostHog private constructor(
get() {
synchronized(personProcessingLock) {
if (!isPersonProcessingLoaded) {
isPersonProcessingEnabled = getPreferences().getValue(PERSON_PROCESSING) as? Boolean
?: false
isPersonProcessingEnabled =
getPreferences().getValue(PERSON_PROCESSING) as? Boolean
?: false
isPersonProcessingLoaded = true
}
}
Expand Down Expand Up @@ -805,7 +826,10 @@ public class PostHog private constructor(
if (!isEnabled()) {
return
}
loadFeatureFlagsRequest(internalOnFeatureFlags = internalOnFeatureFlagsLoaded, onFeatureFlags = onFeatureFlags)
loadFeatureFlagsRequest(
internalOnFeatureFlags = internalOnFeatureFlagsLoaded,
onFeatureFlags = onFeatureFlags,
)
}

private fun loadFeatureFlagsRequest(
Expand Down Expand Up @@ -850,14 +874,21 @@ public class PostHog private constructor(
anonymousId = this.anonymousId
}

remoteConfig?.loadRemoteConfig(distinctId, anonymousId = anonymousId, groups, internalOnFeatureFlags, onFeatureFlags)
remoteConfig?.loadRemoteConfig(
distinctId,
anonymousId = anonymousId,
groups,
internalOnFeatureFlags,
onFeatureFlags,
)
}

public override fun isFeatureEnabled(
key: String,
defaultValue: Boolean,
sendFeatureFlagEvent: Boolean?,
): Boolean {
val value = getFeatureFlag(key, defaultValue)
val value = getFeatureFlag(key, defaultValue, sendFeatureFlagEvent)

if (value is Boolean) {
return value
Expand All @@ -873,51 +904,59 @@ public class PostHog private constructor(
private fun sendFeatureFlagCalled(
key: String,
value: Any?,
sendFeatureFlagEvent: Boolean?,
) {
var shouldSendFeatureFlagEvent = true
synchronized(featureFlagsCalledLock) {
val values = featureFlagsCalled[key] ?: mutableListOf()
if (values.contains(value)) {
shouldSendFeatureFlagEvent = false
} else {
values.add(value)
featureFlagsCalled[key] = values
val effectiveSendFeatureFlagEvent =
sendFeatureFlagEvent
?: config?.sendFeatureFlagEvent
?: false

if (effectiveSendFeatureFlagEvent) {
var shouldSendFeatureFlagEvent = true
synchronized(featureFlagsCalledLock) {
val values = featureFlagsCalled[key] ?: mutableListOf()
if (values.contains(value)) {
shouldSendFeatureFlagEvent = false
} else {
values.add(value)
featureFlagsCalled[key] = values
}
}
}

if (config?.sendFeatureFlagEvent == true && shouldSendFeatureFlagEvent) {
remoteConfig?.let {
val flagDetails = it.getFlagDetails(key)
val requestId = it.getRequestId()
val evaluatedAt = it.getEvaluatedAt()

val props = mutableMapOf<String, Any>()
props["\$feature_flag"] = key
// value should never be nullabe anyway
props["\$feature_flag_response"] = value ?: ""
requestId?.let { props["\$feature_flag_request_id"] = it }
evaluatedAt?.let { props["\$feature_flag_evaluated_at"] = it }
flagDetails?.let {
props["\$feature_flag_id"] = it.metadata.id
props["\$feature_flag_version"] = it.metadata.version
props["\$feature_flag_reason"] = it.reason?.description ?: ""
if (shouldSendFeatureFlagEvent) {
remoteConfig?.let {
val flagDetails = it.getFlagDetails(key)
val requestId = it.getRequestId()
val evaluatedAt = it.getEvaluatedAt()

val props = mutableMapOf<String, Any>()
props["\$feature_flag"] = key
// value should never be nullabe anyway
props["\$feature_flag_response"] = value ?: ""
requestId?.let { props["\$feature_flag_request_id"] = it }
evaluatedAt?.let { props["\$feature_flag_evaluated_at"] = it }
flagDetails?.let {
props["\$feature_flag_id"] = it.metadata.id
props["\$feature_flag_version"] = it.metadata.version
props["\$feature_flag_reason"] = it.reason?.description ?: ""
}
capture(PostHogEventName.FEATURE_FLAG_CALLED.event, properties = props)
}
capture("\$feature_flag_called", properties = props)
}
}
}

public override fun getFeatureFlag(
key: String,
defaultValue: Any?,
sendFeatureFlagEvent: Boolean?,
): Any? {
if (!isEnabled()) {
return defaultValue
}
val value = remoteConfig?.getFeatureFlag(key, defaultValue) ?: defaultValue

sendFeatureFlagCalled(key, value)

sendFeatureFlagCalled(key, value, sendFeatureFlagEvent)
return value
}

Expand Down Expand Up @@ -1261,12 +1300,19 @@ public class PostHog private constructor(
public override fun isFeatureEnabled(
key: String,
defaultValue: Boolean,
): Boolean = shared.isFeatureEnabled(key, defaultValue = defaultValue)
sendFeatureFlagEvent: Boolean?,
): Boolean =
shared.isFeatureEnabled(
key,
defaultValue = defaultValue,
sendFeatureFlagEvent = sendFeatureFlagEvent,
)

public override fun getFeatureFlag(
key: String,
defaultValue: Any?,
): Any? = shared.getFeatureFlag(key, defaultValue = defaultValue)
sendFeatureFlagEvent: Boolean?,
): Any? = shared.getFeatureFlag(key, defaultValue = defaultValue, sendFeatureFlagEvent)

public override fun getFeatureFlagPayload(
key: String,
Expand Down
4 changes: 4 additions & 0 deletions posthog/src/main/java/com/posthog/PostHogInterface.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,25 @@ public interface PostHogInterface : PostHogCoreInterface {
* Docs https://posthog.com/docs/feature-flags and https://posthog.com/docs/experiments
* @param key the Key
* @param defaultValue the default value if not found, false if not given
* @param sendFeatureFlagEvent (optional) If false, we won't send an $feature_flag_call event to PostHog.
*/
public fun isFeatureEnabled(
key: String,
defaultValue: Boolean = false,
sendFeatureFlagEvent: Boolean? = null,
): Boolean

/**
* Returns the feature flag
* Docs https://posthog.com/docs/feature-flags and https://posthog.com/docs/experiments
* @param key the Key
* @param defaultValue the default value if not found
* @param sendFeatureFlagEvent (optional) If false, we won't send an $feature_flag_call event to PostHog.
*/
public fun getFeatureFlag(
key: String,
defaultValue: Any? = null,
sendFeatureFlagEvent: Boolean? = null,
): Any?

/**
Expand Down
2 changes: 1 addition & 1 deletion posthog/src/main/java/com/posthog/PostHogStateless.kt
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ public open class PostHogStateless protected constructor(
requestId?.let { props["\$feature_flag_request_id"] = it }
evaluatedAt?.let { props["\$feature_flag_evaluated_at"] = it }

captureStateless("\$feature_flag_called", distinctId, properties = props)
captureStateless(PostHogEventName.FEATURE_FLAG_CALLED.event, distinctId, properties = props)
}
}
}
Expand Down
Loading
Loading