From 6328914e835a263a1ed7432a2459d8143c55947f Mon Sep 17 00:00:00 2001 From: Igor Macedo Quintanilha Date: Wed, 21 Jan 2026 21:42:05 -0300 Subject: [PATCH 1/3] feat(feature-flags): add posthog-server user agent for server-side SDK detection This adds support for the `posthog-server/*` user agent pattern, allowing client-side SDKs (like posthog-android, posthog-ios) running in server mode to be properly detected as server-side runtime. When a client SDK is used on the server (e.g., Android SDK in a backend service), it can now send `posthog-server/{version}` as the user agent to receive server-only feature flags. Related: https://github.com/PostHog/posthog-android/pull/382 --- rust/feature-flags/src/handler/types.rs | 8 ++++++++ rust/feature-flags/src/utils/user_agent.rs | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/rust/feature-flags/src/handler/types.rs b/rust/feature-flags/src/handler/types.rs index a34c038f5beff..7ff439217c73b 100644 --- a/rust/feature-flags/src/handler/types.rs +++ b/rust/feature-flags/src/handler/types.rs @@ -96,6 +96,8 @@ pub enum Library { PosthogReactNative, /// posthog-flutter SDK PosthogFlutter, + /// posthog-server SDK (generic server-side for client SDKs running in server mode) + PosthogServer, /// Unknown or unrecognized SDK Other, } @@ -120,6 +122,7 @@ impl Library { Library::PosthogIos => "posthog-ios", Library::PosthogReactNative => "posthog-react-native", Library::PosthogFlutter => "posthog-flutter", + Library::PosthogServer => "posthog-server", Library::Other => "other", } } @@ -141,6 +144,7 @@ impl Library { Library::PosthogIos, Library::PosthogReactNative, Library::PosthogFlutter, + Library::PosthogServer, ]; } @@ -236,6 +240,8 @@ mod tests { #[case("posthog-java/1.2.0", Library::PosthogJava)] #[case("posthog-dotnet/1.0.0", Library::PosthogDotnet)] #[case("posthog-elixir/0.2.0", Library::PosthogElixir)] + #[case("posthog-server/1.0.0", Library::PosthogServer)] + #[case("posthog-server/3.2.1 (Android SDK)", Library::PosthogServer)] // Client-side SDKs #[case("posthog-js/1.88.0", Library::PosthogJs)] #[case("posthog-android/3.0.0", Library::PosthogAndroid)] @@ -322,6 +328,7 @@ mod tests { #[case(Library::PosthogIos, "posthog-ios")] #[case(Library::PosthogReactNative, "posthog-react-native")] #[case(Library::PosthogFlutter, "posthog-flutter")] + #[case(Library::PosthogServer, "posthog-server")] #[case(Library::Other, "other")] fn test_library_display(#[case] library: Library, #[case] expected: &str) { assert_eq!(library.to_string(), expected); @@ -341,6 +348,7 @@ mod tests { #[case(Library::PosthogIos, "\"posthog-ios\"")] #[case(Library::PosthogReactNative, "\"posthog-react-native\"")] #[case(Library::PosthogFlutter, "\"posthog-flutter\"")] + #[case(Library::PosthogServer, "\"posthog-server\"")] #[case(Library::Other, "\"other\"")] fn test_library_serialization(#[case] library: Library, #[case] expected_json: &str) { assert_eq!(serde_json::to_string(&library).unwrap(), expected_json); diff --git a/rust/feature-flags/src/utils/user_agent.rs b/rust/feature-flags/src/utils/user_agent.rs index 5a4e53012f19d..00bfe853a00de 100644 --- a/rust/feature-flags/src/utils/user_agent.rs +++ b/rust/feature-flags/src/utils/user_agent.rs @@ -98,6 +98,8 @@ impl UserAgentInfo { "node" => ("posthog-node", RuntimeType::Server), "dotnet" => ("posthog-dotnet", RuntimeType::Server), "elixir" => ("posthog-elixir", RuntimeType::Server), + // Generic server-side SDK (for client SDKs running in server mode) + "server" => ("posthog-server", RuntimeType::Server), // Client-side SDKs (mobile and browser) "js" => ("posthog-js", RuntimeType::Client), "android" => ("posthog-android", RuntimeType::Client), @@ -231,6 +233,18 @@ mod tests { Some("0.2.0"), RuntimeType::Server )] + #[case( + "posthog-server/1.0.0", + Some("posthog-server"), + Some("1.0.0"), + RuntimeType::Server + )] + #[case( + "posthog-server/3.2.1 (Android SDK)", + Some("posthog-server"), + Some("3.2.1"), + RuntimeType::Server + )] #[case( "posthog-js/1.88.0", Some("posthog-js"), @@ -341,6 +355,7 @@ mod tests { #[case(Some("posthog-node/2.2.0"), "posthog-node")] #[case(Some("posthog-dotnet/1.0.0"), "posthog-dotnet")] #[case(Some("posthog-elixir/0.2.0"), "posthog-elixir")] + #[case(Some("posthog-server/1.0.0"), "posthog-server")] #[case( Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"), "browser" @@ -366,6 +381,7 @@ mod tests { #[case("posthog-python/3.0.0", Some("posthog-python"))] #[case("posthog-node/1.2.3", Some("posthog-node"))] #[case("posthog-android/3.0.0", Some("posthog-android"))] + #[case("posthog-server/1.0.0", Some("posthog-server"))] #[case("Mozilla/5.0 (Windows NT 10.0; Win64; x64)", Some("web"))] #[case("Chrome/120.0.0.0 Safari/537.36", Some("web"))] #[case("curl/7.68.0", None)] From 1f7d956b6d802d567aecf47ddb126b062da3f05c Mon Sep 17 00:00:00 2001 From: Igor Macedo Quintanilha Date: Thu, 22 Jan 2026 12:54:15 -0300 Subject: [PATCH 2/3] fix(feature-flags): rename posthog-server to posthog-java-server Address PR review feedback to use a more specific SDK name. --- rust/feature-flags/src/handler/types.rs | 16 ++++++++-------- rust/feature-flags/src/utils/user_agent.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust/feature-flags/src/handler/types.rs b/rust/feature-flags/src/handler/types.rs index 7ff439217c73b..390a7774beb68 100644 --- a/rust/feature-flags/src/handler/types.rs +++ b/rust/feature-flags/src/handler/types.rs @@ -96,8 +96,8 @@ pub enum Library { PosthogReactNative, /// posthog-flutter SDK PosthogFlutter, - /// posthog-server SDK (generic server-side for client SDKs running in server mode) - PosthogServer, + /// posthog-java-server SDK (server-side mode for posthog-java SDK) + PosthogJavaServer, /// Unknown or unrecognized SDK Other, } @@ -122,7 +122,7 @@ impl Library { Library::PosthogIos => "posthog-ios", Library::PosthogReactNative => "posthog-react-native", Library::PosthogFlutter => "posthog-flutter", - Library::PosthogServer => "posthog-server", + Library::PosthogJavaServer => "posthog-java-server", Library::Other => "other", } } @@ -144,7 +144,7 @@ impl Library { Library::PosthogIos, Library::PosthogReactNative, Library::PosthogFlutter, - Library::PosthogServer, + Library::PosthogJavaServer, ]; } @@ -240,8 +240,8 @@ mod tests { #[case("posthog-java/1.2.0", Library::PosthogJava)] #[case("posthog-dotnet/1.0.0", Library::PosthogDotnet)] #[case("posthog-elixir/0.2.0", Library::PosthogElixir)] - #[case("posthog-server/1.0.0", Library::PosthogServer)] - #[case("posthog-server/3.2.1 (Android SDK)", Library::PosthogServer)] + #[case("posthog-java-server/1.0.0", Library::PosthogJavaServer)] + #[case("posthog-java-server/3.2.1 (Android SDK)", Library::PosthogJavaServer)] // Client-side SDKs #[case("posthog-js/1.88.0", Library::PosthogJs)] #[case("posthog-android/3.0.0", Library::PosthogAndroid)] @@ -328,7 +328,7 @@ mod tests { #[case(Library::PosthogIos, "posthog-ios")] #[case(Library::PosthogReactNative, "posthog-react-native")] #[case(Library::PosthogFlutter, "posthog-flutter")] - #[case(Library::PosthogServer, "posthog-server")] + #[case(Library::PosthogJavaServer, "posthog-java-server")] #[case(Library::Other, "other")] fn test_library_display(#[case] library: Library, #[case] expected: &str) { assert_eq!(library.to_string(), expected); @@ -348,7 +348,7 @@ mod tests { #[case(Library::PosthogIos, "\"posthog-ios\"")] #[case(Library::PosthogReactNative, "\"posthog-react-native\"")] #[case(Library::PosthogFlutter, "\"posthog-flutter\"")] - #[case(Library::PosthogServer, "\"posthog-server\"")] + #[case(Library::PosthogJavaServer, "\"posthog-java-server\"")] #[case(Library::Other, "\"other\"")] fn test_library_serialization(#[case] library: Library, #[case] expected_json: &str) { assert_eq!(serde_json::to_string(&library).unwrap(), expected_json); diff --git a/rust/feature-flags/src/utils/user_agent.rs b/rust/feature-flags/src/utils/user_agent.rs index 00bfe853a00de..e802fd82388a2 100644 --- a/rust/feature-flags/src/utils/user_agent.rs +++ b/rust/feature-flags/src/utils/user_agent.rs @@ -98,8 +98,8 @@ impl UserAgentInfo { "node" => ("posthog-node", RuntimeType::Server), "dotnet" => ("posthog-dotnet", RuntimeType::Server), "elixir" => ("posthog-elixir", RuntimeType::Server), - // Generic server-side SDK (for client SDKs running in server mode) - "server" => ("posthog-server", RuntimeType::Server), + // Generic server-side SDK (for client SDKs running in server mode, e.g., posthog-java) + "java-server" => ("posthog-java-server", RuntimeType::Server), // Client-side SDKs (mobile and browser) "js" => ("posthog-js", RuntimeType::Client), "android" => ("posthog-android", RuntimeType::Client), @@ -234,14 +234,14 @@ mod tests { RuntimeType::Server )] #[case( - "posthog-server/1.0.0", - Some("posthog-server"), + "posthog-java-server/1.0.0", + Some("posthog-java-server"), Some("1.0.0"), RuntimeType::Server )] #[case( - "posthog-server/3.2.1 (Android SDK)", - Some("posthog-server"), + "posthog-java-server/3.2.1 (Android SDK)", + Some("posthog-java-server"), Some("3.2.1"), RuntimeType::Server )] @@ -355,7 +355,7 @@ mod tests { #[case(Some("posthog-node/2.2.0"), "posthog-node")] #[case(Some("posthog-dotnet/1.0.0"), "posthog-dotnet")] #[case(Some("posthog-elixir/0.2.0"), "posthog-elixir")] - #[case(Some("posthog-server/1.0.0"), "posthog-server")] + #[case(Some("posthog-java-server/1.0.0"), "posthog-java-server")] #[case( Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"), "browser" @@ -381,7 +381,7 @@ mod tests { #[case("posthog-python/3.0.0", Some("posthog-python"))] #[case("posthog-node/1.2.3", Some("posthog-node"))] #[case("posthog-android/3.0.0", Some("posthog-android"))] - #[case("posthog-server/1.0.0", Some("posthog-server"))] + #[case("posthog-java-server/1.0.0", Some("posthog-java-server"))] #[case("Mozilla/5.0 (Windows NT 10.0; Win64; x64)", Some("web"))] #[case("Chrome/120.0.0.0 Safari/537.36", Some("web"))] #[case("curl/7.68.0", None)] From 3db920f5dc437b041487dd7eb077cf726bfdfc0c Mon Sep 17 00:00:00 2001 From: Igor Macedo Quintanilha Date: Thu, 22 Jan 2026 22:13:59 -0300 Subject: [PATCH 3/3] fix(feature-flags): use posthog-server instead of posthog-java-server Track posthog-server user agent (deprecated, users migrating to posthog-java). --- rust/feature-flags/src/handler/types.rs | 16 ++++++++-------- rust/feature-flags/src/utils/user_agent.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust/feature-flags/src/handler/types.rs b/rust/feature-flags/src/handler/types.rs index 390a7774beb68..d4a29dfcbbe41 100644 --- a/rust/feature-flags/src/handler/types.rs +++ b/rust/feature-flags/src/handler/types.rs @@ -96,8 +96,8 @@ pub enum Library { PosthogReactNative, /// posthog-flutter SDK PosthogFlutter, - /// posthog-java-server SDK (server-side mode for posthog-java SDK) - PosthogJavaServer, + /// posthog-server SDK (deprecated: users are migrating to posthog-java) + PosthogServer, /// Unknown or unrecognized SDK Other, } @@ -122,7 +122,7 @@ impl Library { Library::PosthogIos => "posthog-ios", Library::PosthogReactNative => "posthog-react-native", Library::PosthogFlutter => "posthog-flutter", - Library::PosthogJavaServer => "posthog-java-server", + Library::PosthogServer => "posthog-server", Library::Other => "other", } } @@ -144,7 +144,7 @@ impl Library { Library::PosthogIos, Library::PosthogReactNative, Library::PosthogFlutter, - Library::PosthogJavaServer, + Library::PosthogServer, ]; } @@ -240,8 +240,8 @@ mod tests { #[case("posthog-java/1.2.0", Library::PosthogJava)] #[case("posthog-dotnet/1.0.0", Library::PosthogDotnet)] #[case("posthog-elixir/0.2.0", Library::PosthogElixir)] - #[case("posthog-java-server/1.0.0", Library::PosthogJavaServer)] - #[case("posthog-java-server/3.2.1 (Android SDK)", Library::PosthogJavaServer)] + #[case("posthog-server/1.0.0", Library::PosthogServer)] + #[case("posthog-server/3.2.1 (Android SDK)", Library::PosthogServer)] // Client-side SDKs #[case("posthog-js/1.88.0", Library::PosthogJs)] #[case("posthog-android/3.0.0", Library::PosthogAndroid)] @@ -328,7 +328,7 @@ mod tests { #[case(Library::PosthogIos, "posthog-ios")] #[case(Library::PosthogReactNative, "posthog-react-native")] #[case(Library::PosthogFlutter, "posthog-flutter")] - #[case(Library::PosthogJavaServer, "posthog-java-server")] + #[case(Library::PosthogServer, "posthog-server")] #[case(Library::Other, "other")] fn test_library_display(#[case] library: Library, #[case] expected: &str) { assert_eq!(library.to_string(), expected); @@ -348,7 +348,7 @@ mod tests { #[case(Library::PosthogIos, "\"posthog-ios\"")] #[case(Library::PosthogReactNative, "\"posthog-react-native\"")] #[case(Library::PosthogFlutter, "\"posthog-flutter\"")] - #[case(Library::PosthogJavaServer, "\"posthog-java-server\"")] + #[case(Library::PosthogServer, "\"posthog-server\"")] #[case(Library::Other, "\"other\"")] fn test_library_serialization(#[case] library: Library, #[case] expected_json: &str) { assert_eq!(serde_json::to_string(&library).unwrap(), expected_json); diff --git a/rust/feature-flags/src/utils/user_agent.rs b/rust/feature-flags/src/utils/user_agent.rs index e802fd82388a2..4add0852aa6f2 100644 --- a/rust/feature-flags/src/utils/user_agent.rs +++ b/rust/feature-flags/src/utils/user_agent.rs @@ -98,8 +98,8 @@ impl UserAgentInfo { "node" => ("posthog-node", RuntimeType::Server), "dotnet" => ("posthog-dotnet", RuntimeType::Server), "elixir" => ("posthog-elixir", RuntimeType::Server), - // Generic server-side SDK (for client SDKs running in server mode, e.g., posthog-java) - "java-server" => ("posthog-java-server", RuntimeType::Server), + // Deprecated: posthog-server users are migrating to posthog-java + "server" => ("posthog-server", RuntimeType::Server), // Client-side SDKs (mobile and browser) "js" => ("posthog-js", RuntimeType::Client), "android" => ("posthog-android", RuntimeType::Client), @@ -234,14 +234,14 @@ mod tests { RuntimeType::Server )] #[case( - "posthog-java-server/1.0.0", - Some("posthog-java-server"), + "posthog-server/1.0.0", + Some("posthog-server"), Some("1.0.0"), RuntimeType::Server )] #[case( - "posthog-java-server/3.2.1 (Android SDK)", - Some("posthog-java-server"), + "posthog-server/3.2.1 (Android SDK)", + Some("posthog-server"), Some("3.2.1"), RuntimeType::Server )] @@ -355,7 +355,7 @@ mod tests { #[case(Some("posthog-node/2.2.0"), "posthog-node")] #[case(Some("posthog-dotnet/1.0.0"), "posthog-dotnet")] #[case(Some("posthog-elixir/0.2.0"), "posthog-elixir")] - #[case(Some("posthog-java-server/1.0.0"), "posthog-java-server")] + #[case(Some("posthog-server/1.0.0"), "posthog-server")] #[case( Some("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"), "browser" @@ -381,7 +381,7 @@ mod tests { #[case("posthog-python/3.0.0", Some("posthog-python"))] #[case("posthog-node/1.2.3", Some("posthog-node"))] #[case("posthog-android/3.0.0", Some("posthog-android"))] - #[case("posthog-java-server/1.0.0", Some("posthog-java-server"))] + #[case("posthog-server/1.0.0", Some("posthog-server"))] #[case("Mozilla/5.0 (Windows NT 10.0; Win64; x64)", Some("web"))] #[case("Chrome/120.0.0.0 Safari/537.36", Some("web"))] #[case("curl/7.68.0", None)]