From 1d5906fd703df92a2dc1f75c3063c273db2f85de Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Thu, 30 Apr 2026 12:37:41 +0200 Subject: [PATCH] fix: no-op setup without api key --- .changeset/fresh-keys-bow.md | 6 ++++++ .../com/posthog/android/PostHogAndroid.kt | 9 +++++++++ .../posthog/android/PostHogAndroidConfig.kt | 2 +- .../android/PostHogAndroidConfigJavaTest.java | 14 +++++++++++++ .../android/PostHogAndroidConfigTest.kt | 7 +++++++ .../com/posthog/android/PostHogAndroidTest.kt | 20 +++++++++++++++++++ posthog/src/main/java/com/posthog/PostHog.kt | 1 + .../main/java/com/posthog/PostHogConfig.kt | 4 ++-- .../main/java/com/posthog/PostHogStateless.kt | 1 + .../java/com/posthog/PostHogConfigTest.kt | 7 +++++++ .../java/com/posthog/PostHogStatelessTest.kt | 3 ++- .../src/test/java/com/posthog/PostHogTest.kt | 19 ++++++++++++++++++ 12 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 .changeset/fresh-keys-bow.md create mode 100644 posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigJavaTest.java diff --git a/.changeset/fresh-keys-bow.md b/.changeset/fresh-keys-bow.md new file mode 100644 index 000000000..8d03268e9 --- /dev/null +++ b/.changeset/fresh-keys-bow.md @@ -0,0 +1,6 @@ +--- +"posthog": patch +"posthog-android": patch +--- + +No-op SDK setup when the API key is null, empty, or whitespace after trimming. diff --git a/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt b/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt index 2505fb131..cf65f686c 100644 --- a/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt +++ b/posthog-android/src/main/java/com/posthog/android/PostHogAndroid.kt @@ -47,6 +47,11 @@ public class PostHogAndroid private constructor() { config: T, ) { synchronized(lock) { + if (config.apiKey.isEmpty()) { + PostHog.setup(config) + return + } + setAndroidConfig(context.appContext(), config) PostHog.setup(config) @@ -69,6 +74,10 @@ public class PostHogAndroid private constructor() { context: Context, config: T, ): PostHogInterface { + if (config.apiKey.isEmpty()) { + return PostHog.with(config) + } + setAndroidConfig(context.appContext(), config) return PostHog.with(config) } diff --git a/posthog-android/src/main/java/com/posthog/android/PostHogAndroidConfig.kt b/posthog-android/src/main/java/com/posthog/android/PostHogAndroidConfig.kt index f2302f5c3..614930dfe 100644 --- a/posthog-android/src/main/java/com/posthog/android/PostHogAndroidConfig.kt +++ b/posthog-android/src/main/java/com/posthog/android/PostHogAndroidConfig.kt @@ -13,7 +13,7 @@ import com.posthog.android.replay.PostHogSessionReplayConfig public open class PostHogAndroidConfig @JvmOverloads constructor( - apiKey: String, + apiKey: String?, host: String = DEFAULT_HOST, public var captureApplicationLifecycleEvents: Boolean = true, public var captureDeepLinks: Boolean = true, diff --git a/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigJavaTest.java b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigJavaTest.java new file mode 100644 index 000000000..c5efc48fd --- /dev/null +++ b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigJavaTest.java @@ -0,0 +1,14 @@ +package com.posthog.android; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class PostHogAndroidConfigJavaTest { + @Test + public void nullApiKeyFromJavaDefaultsToEmptyString() { + PostHogAndroidConfig config = new PostHogAndroidConfig(null); + + assertEquals("", config.getApiKey()); + } +} diff --git a/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigTest.kt b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigTest.kt index 122ba6415..c2af8c12b 100644 --- a/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigTest.kt +++ b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidConfigTest.kt @@ -12,6 +12,13 @@ internal class PostHogAndroidConfigTest { assertEquals(API_KEY, config.apiKey) } + @Test + fun `defaults null api key to empty string`() { + val config = PostHogAndroidConfig(null) + + assertEquals("", config.apiKey) + } + @Test fun `captureApplicationLifecycleEvents should be enabled by default`() { assertTrue(config.captureApplicationLifecycleEvents) diff --git a/posthog-android/src/test/java/com/posthog/android/PostHogAndroidTest.kt b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidTest.kt index e4ab9f59c..8c62fda60 100644 --- a/posthog-android/src/test/java/com/posthog/android/PostHogAndroidTest.kt +++ b/posthog-android/src/test/java/com/posthog/android/PostHogAndroidTest.kt @@ -39,6 +39,26 @@ internal class PostHogAndroidTest { tmpDir.root.deleteRecursively() } + @Test + fun `setup no-ops for null api key`() { + val config = PostHogAndroidConfig(null) + + PostHogAndroid.setup(context, config) + + assertNull(config.cachePreferences) + assertTrue(config.integrations.isEmpty()) + } + + @Test + fun `setup no-ops for empty trimmed api key`() { + val config = PostHogAndroidConfig(" \n\t ") + + PostHogAndroid.setup(context, config) + + assertNull(config.cachePreferences) + assertTrue(config.integrations.isEmpty()) + } + @Test fun `sets Android Logger if System logger`() { val config = PostHogAndroidConfig(API_KEY) diff --git a/posthog/src/main/java/com/posthog/PostHog.kt b/posthog/src/main/java/com/posthog/PostHog.kt index 82c6a68ce..8994d9bb3 100644 --- a/posthog/src/main/java/com/posthog/PostHog.kt +++ b/posthog/src/main/java/com/posthog/PostHog.kt @@ -101,6 +101,7 @@ public class PostHog private constructor( if (config.apiKey.isEmpty()) { config.logger.log("apiKey is empty after trimming whitespace; check your project API key") + return } if (!apiKeys.add(config.apiKey)) { diff --git a/posthog/src/main/java/com/posthog/PostHogConfig.kt b/posthog/src/main/java/com/posthog/PostHogConfig.kt index 5f6f4e61b..fe57b995e 100644 --- a/posthog/src/main/java/com/posthog/PostHogConfig.kt +++ b/posthog/src/main/java/com/posthog/PostHogConfig.kt @@ -31,7 +31,7 @@ public open class PostHogConfig( /** * The PostHog API Key */ - apiKey: String, + apiKey: String?, /** * The PostHog Host * Defaults to https://us.i.posthog.com @@ -328,7 +328,7 @@ public open class PostHogConfig( /** * The PostHog API Key */ - public val apiKey: String = apiKey.trim() + public val apiKey: String = apiKey?.trim().orEmpty() /** * The PostHog Host diff --git a/posthog/src/main/java/com/posthog/PostHogStateless.kt b/posthog/src/main/java/com/posthog/PostHogStateless.kt index 313163d73..ecf9e3696 100644 --- a/posthog/src/main/java/com/posthog/PostHogStateless.kt +++ b/posthog/src/main/java/com/posthog/PostHogStateless.kt @@ -55,6 +55,7 @@ public open class PostHogStateless protected constructor( if (config.apiKey.isEmpty()) { config.logger.log("apiKey is empty after trimming whitespace; check your project API key") + return } if (!apiKeys.add(config.apiKey)) { diff --git a/posthog/src/test/java/com/posthog/PostHogConfigTest.kt b/posthog/src/test/java/com/posthog/PostHogConfigTest.kt index 86bd00efa..6d5f8199b 100644 --- a/posthog/src/test/java/com/posthog/PostHogConfigTest.kt +++ b/posthog/src/test/java/com/posthog/PostHogConfigTest.kt @@ -23,6 +23,13 @@ internal class PostHogConfigTest { assertEquals("https://eu.i.posthog.com/", config.host) } + @Test + fun `defaults null api key to empty string`() { + val config = PostHogConfig(null, "https://api.posthog.com") + + assertEquals("", config.apiKey) + } + @Test fun `defaults a blank host after trimming whitespace`() { val config = PostHogConfig(API_KEY, " \n\t ") diff --git a/posthog/src/test/java/com/posthog/PostHogStatelessTest.kt b/posthog/src/test/java/com/posthog/PostHogStatelessTest.kt index 98f6355ce..f39da0eb9 100644 --- a/posthog/src/test/java/com/posthog/PostHogStatelessTest.kt +++ b/posthog/src/test/java/com/posthog/PostHogStatelessTest.kt @@ -237,13 +237,14 @@ internal class PostHogStatelessTest { } @Test - fun `setup logs empty trimmed api key after logger initialization`() { + fun `setup no-ops for empty trimmed api key after logger initialization`() { sut = createStatelessInstance() val mockLogger = MockLogger() config = PostHogConfig(" \n\t ", "https://api.posthog.com").apply { logger = mockLogger } sut.setup(config) + assertFalse(sut.isEnabledPublic()) assertTrue(mockLogger.messages.any { it.contains("apiKey is empty after trimming whitespace") }) } diff --git a/posthog/src/test/java/com/posthog/PostHogTest.kt b/posthog/src/test/java/com/posthog/PostHogTest.kt index 79b6052e8..4809311ab 100644 --- a/posthog/src/test/java/com/posthog/PostHogTest.kt +++ b/posthog/src/test/java/com/posthog/PostHogTest.kt @@ -126,6 +126,25 @@ internal class PostHogTest { sut.close() } + @Test + fun `setup no-ops for empty trimmed api key`() { + val config = PostHogConfig(" \n\t ", "https://api.posthog.com") + val sut = + PostHog.withInternal( + config, + queueExecutor, + replayQueueExecutor, + remoteConfigExecutor, + cachedEventsExecutor, + reloadFeatureFlags = true, + ) + + assertTrue(config.integrations.isEmpty()) + assertNull(config.cachePreferences) + + sut.close() + } + @Test fun `setup adds integration by default`() { val http = mockHttp()