From 917150b87d5c2ef78a8ec47f03c41028616af82c Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Tue, 2 Jun 2026 13:56:09 -0400 Subject: [PATCH 1/5] feat: emit $is_server property on captured events --- src/PostHog/Api/CapturedEvent.cs | 1 + src/PostHog/Api/PostHogApiClient.cs | 1 + src/PostHog/Api/PostHogProperties.cs | 5 ++++ tests/UnitTests/Api/CapturedEventTests.cs | 2 ++ tests/UnitTests/Features/FeatureFlagsTests.cs | 20 ++++++++++++++++ tests/UnitTests/PostHogClientTests.cs | 24 +++++++++++++++++++ 6 files changed, 53 insertions(+) diff --git a/src/PostHog/Api/CapturedEvent.cs b/src/PostHog/Api/CapturedEvent.cs index bebfbc89..650fe05d 100644 --- a/src/PostHog/Api/CapturedEvent.cs +++ b/src/PostHog/Api/CapturedEvent.cs @@ -32,6 +32,7 @@ public CapturedEvent( // Every event has to have these properties. Properties[PostHogProperties.DistinctId] = distinctId; // See `get_distinct_id` in PostHog/posthog api/capture.py line 321 Properties[PostHogProperties.Lib] = PostHogApiClient.LibraryName; + Properties[PostHogProperties.IsServer] = true; Properties[PostHogProperties.LibVersion] = VersionConstants.Version; Properties[PostHogProperties.GeoIpDisable] = Properties.GetValueOrDefault(PostHogProperties.GeoIpDisable, true); } diff --git a/src/PostHog/Api/PostHogApiClient.cs b/src/PostHog/Api/PostHogApiClient.cs index 1f1a5e22..494cde29 100644 --- a/src/PostHog/Api/PostHogApiClient.cs +++ b/src/PostHog/Api/PostHogApiClient.cs @@ -277,6 +277,7 @@ void PrepareAndMutatePayload(Dictionary payload) var properties = payload.GetOrAdd>("properties"); properties[PostHogProperties.Lib] = LibraryName; + properties[PostHogProperties.IsServer] = true; properties[PostHogProperties.LibVersion] = VersionConstants.Version; properties[PostHogProperties.Os] = RuntimeInformation.OSDescription; properties[PostHogProperties.Framework] = RuntimeInformation.FrameworkDescription; diff --git a/src/PostHog/Api/PostHogProperties.cs b/src/PostHog/Api/PostHogProperties.cs index 9f178a1d..b2957653 100644 --- a/src/PostHog/Api/PostHogProperties.cs +++ b/src/PostHog/Api/PostHogProperties.cs @@ -15,6 +15,11 @@ public static class PostHogProperties /// public const string Lib = "$lib"; + /// + /// The property name indicating that the event was captured by a server-side SDK. + /// + public const string IsServer = "$is_server"; + /// /// The property name for the client library version. /// diff --git a/tests/UnitTests/Api/CapturedEventTests.cs b/tests/UnitTests/Api/CapturedEventTests.cs index b475d4f2..8c110063 100644 --- a/tests/UnitTests/Api/CapturedEventTests.cs +++ b/tests/UnitTests/Api/CapturedEventTests.cs @@ -82,6 +82,8 @@ public void AddsLibraryProperties() Assert.True(capturedEvent.Properties.TryGetValue("$lib", out var lib)); Assert.Equal("posthog-dotnet", lib); + Assert.True(capturedEvent.Properties.TryGetValue("$is_server", out var isServer)); + Assert.Equal(true, isServer); Assert.True(capturedEvent.Properties.ContainsKey("$lib_version")); } diff --git a/tests/UnitTests/Features/FeatureFlagsTests.cs b/tests/UnitTests/Features/FeatureFlagsTests.cs index b05fffac..c15fdf33 100644 --- a/tests/UnitTests/Features/FeatureFlagsTests.cs +++ b/tests/UnitTests/Features/FeatureFlagsTests.cs @@ -196,6 +196,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -214,6 +215,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -232,6 +234,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -289,6 +292,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -305,6 +309,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": true, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -321,6 +326,7 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": false, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -497,6 +503,7 @@ await client.IsFeatureEnabledAsync( "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "659df793-429a-4517-84ff-747dfc103e6c", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -548,6 +555,7 @@ public async Task CapturesFeatureFlagCalledEventWithRequestIdWhenPresent() "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -600,6 +608,7 @@ public async Task CapturesFeatureFlagCalledEventWithoutEvaluatedAtWhenNotPresent "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -728,6 +737,7 @@ public async Task CapturesFeatureFlagCalledEventWithAdditionalMetadataIdWhenPres "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2454,6 +2464,7 @@ public async Task CapturesFeatureFlagCalledEvent() "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2503,6 +2514,7 @@ public async Task CapturesFeatureFlagCalledEventWithGroupInformation() "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true, "$groups": { @@ -2568,6 +2580,7 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2584,6 +2597,7 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2600,6 +2614,7 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/another-flag-key": "flag-variant-2", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2616,6 +2631,7 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2672,6 +2688,7 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2688,6 +2705,7 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2704,6 +2722,7 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/another-flag-key": "flag-variant-2", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, @@ -2720,6 +2739,7 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true }, diff --git a/tests/UnitTests/PostHogClientTests.cs b/tests/UnitTests/PostHogClientTests.cs index b2241a68..434f0919 100644 --- a/tests/UnitTests/PostHogClientTests.cs +++ b/tests/UnitTests/PostHogClientTests.cs @@ -39,6 +39,7 @@ public async Task SendsCorrectPayload() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -69,6 +70,7 @@ public async Task SendsCorrectPayloadWithGeoIpEnabled() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -113,6 +115,7 @@ public async Task SendsCorrectPayloadWithPersonProperties() "join_date": "2024-01-21" }, "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -151,6 +154,7 @@ public async Task SendsCorrectPayloadWithSuperProperties() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -190,6 +194,7 @@ public async Task SendsCorrectPayload() "name": "PostHog" }, "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -225,6 +230,7 @@ public async Task SendsCorrectPayloadWithUserProvidedDistinctId() "name": "PostHog" }, "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", @@ -276,6 +282,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -295,6 +302,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -314,6 +322,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -333,6 +342,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -352,6 +362,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -371,6 +382,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -390,6 +402,7 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "third-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/flag1": true, @@ -434,6 +447,7 @@ public async Task CaptureWithCustomTimestampUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -472,6 +486,7 @@ public async Task CaptureWithTimestampAndPropertiesUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -509,6 +524,7 @@ public async Task CaptureWithTimestampAndGroupsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { @@ -549,6 +565,7 @@ public async Task CaptureWithTimestampAndFeatureFlagsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/test-flag": true, @@ -592,6 +609,7 @@ public async Task CaptureWithTimestampPropertiesAndGroupsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { @@ -635,6 +653,7 @@ public async Task CaptureWithAllParametersAndTimestampUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { @@ -685,6 +704,7 @@ public async Task CaptureWithTimestampParameterOverridesTimestampInProperties() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -760,6 +780,7 @@ public async Task CaptureWithSendFeatureFlagsTrueAndLocalEvaluationEnabledUsesLo "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$feature/local-flag": true, @@ -827,6 +848,7 @@ public async Task CaptureWithSendFeatureFlagsFalseDoesNotAddFeatureFlagsEvenWhen "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -889,6 +911,7 @@ public async Task CaptureDefaultsToNotSendingFeatureFlagsEvenWhenLocalEvaluation "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", + "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true }, @@ -925,6 +948,7 @@ public async Task CaptureExceptionWithDivideByZeroException() // based on PostHo Assert.Equal("System.DivideByZeroException", props.GetProperty("$exception_type").GetString()); Assert.Contains("divide by zero", props.GetProperty("$exception_message").GetString(), StringComparison.OrdinalIgnoreCase); Assert.Equal("posthog-dotnet", props.GetProperty("$lib").GetString()); + Assert.True(props.GetProperty("$is_server").GetBoolean()); Assert.Equal(VersionConstants.Version, props.GetProperty("$lib_version").GetString()); var firstException = GetFirstException(props); From e9d880c705579cf47ec064c6db7d475c3b70aee3 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Tue, 2 Jun 2026 15:51:40 -0400 Subject: [PATCH 2/5] feat: emit $is_server on exception events; add changeset --- .changeset/is-server-property.md | 5 +++++ src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/is-server-property.md diff --git a/.changeset/is-server-property.md b/.changeset/is-server-property.md new file mode 100644 index 00000000..24947183 --- /dev/null +++ b/.changeset/is-server-property.md @@ -0,0 +1,5 @@ +--- +"PostHog": patch +--- + +Emit `$is_server` property on captured events so PostHog can identify server-side events. diff --git a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs index c1cc453a..31a2b2e6 100644 --- a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs +++ b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs @@ -1,4 +1,5 @@ -using PostHog.Library; +using PostHog.Api; +using PostHog.Library; using PostHog.Versioning; using System.Runtime.InteropServices; using System.Text; @@ -24,6 +25,7 @@ public static Dictionary Build( properties["$exception_message"] = exception.Message; properties["$exception_level"] = "error"; properties["$lib"] = "posthog-dotnet"; + properties[PostHogProperties.IsServer] = true; properties["$lib_version"] = VersionConstants.Version; properties["$os"] = OperatingSystemInfo.Name; properties["$os_version"] = OperatingSystemInfo.Version; From 41ba54d13ffd88ebdf39736433d9d57f9ea5ba08 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Tue, 2 Jun 2026 17:34:44 -0400 Subject: [PATCH 3/5] feat: make $is_server configurable (default true) --- .changeset/is-server-property.md | 2 +- src/PostHog/Api/CapturedEvent.cs | 13 +++++-- src/PostHog/Api/PostHogApiClient.cs | 5 ++- src/PostHog/Config/PostHogOptions.cs | 14 ++++++++ .../ExceptionPropertiesBuilder.cs | 8 +++-- src/PostHog/PostHogClient.cs | 5 +-- tests/UnitTests/Api/CapturedEventTests.cs | 8 +++++ tests/UnitTests/PostHogClientTests.cs | 36 +++++++++++++++++++ 8 files changed, 83 insertions(+), 8 deletions(-) diff --git a/.changeset/is-server-property.md b/.changeset/is-server-property.md index 24947183..cb603e74 100644 --- a/.changeset/is-server-property.md +++ b/.changeset/is-server-property.md @@ -2,4 +2,4 @@ "PostHog": patch --- -Emit `$is_server` property on captured events so PostHog can identify server-side events. +Add a configurable `$is_server` event property (default `true`) so PostHog can identify server-side events. Set `PostHogOptions.IsServer` to `false` when using the SDK as a client/CLI so the device OS is attributed normally. diff --git a/src/PostHog/Api/CapturedEvent.cs b/src/PostHog/Api/CapturedEvent.cs index 650fe05d..1923d2a0 100644 --- a/src/PostHog/Api/CapturedEvent.cs +++ b/src/PostHog/Api/CapturedEvent.cs @@ -16,11 +16,17 @@ public class CapturedEvent /// The identifier for the user. /// The properties to associate with the event. /// The ISO 8601 timestamp. + /// + /// When true (the default), the event includes the $is_server property set to true. Set to + /// false (via ) when using the SDK as a client/CLI so the device OS + /// is attributed normally; the property is then omitted. + /// public CapturedEvent( string eventName, string distinctId, Dictionary? properties, - DateTimeOffset timestamp) + DateTimeOffset timestamp, + bool isServer = true) { Uuid = Guid.NewGuid().ToString(); EventName = eventName; @@ -32,7 +38,10 @@ public CapturedEvent( // Every event has to have these properties. Properties[PostHogProperties.DistinctId] = distinctId; // See `get_distinct_id` in PostHog/posthog api/capture.py line 321 Properties[PostHogProperties.Lib] = PostHogApiClient.LibraryName; - Properties[PostHogProperties.IsServer] = true; + if (isServer) + { + Properties[PostHogProperties.IsServer] = true; + } Properties[PostHogProperties.LibVersion] = VersionConstants.Version; Properties[PostHogProperties.GeoIpDisable] = Properties.GetValueOrDefault(PostHogProperties.GeoIpDisable, true); } diff --git a/src/PostHog/Api/PostHogApiClient.cs b/src/PostHog/Api/PostHogApiClient.cs index 494cde29..bbf711c0 100644 --- a/src/PostHog/Api/PostHogApiClient.cs +++ b/src/PostHog/Api/PostHogApiClient.cs @@ -277,7 +277,10 @@ void PrepareAndMutatePayload(Dictionary payload) var properties = payload.GetOrAdd>("properties"); properties[PostHogProperties.Lib] = LibraryName; - properties[PostHogProperties.IsServer] = true; + if (_options.Value.IsServer) + { + properties[PostHogProperties.IsServer] = true; + } properties[PostHogProperties.LibVersion] = VersionConstants.Version; properties[PostHogProperties.Os] = RuntimeInformation.OSDescription; properties[PostHogProperties.Framework] = RuntimeInformation.FrameworkDescription; diff --git a/src/PostHog/Config/PostHogOptions.cs b/src/PostHog/Config/PostHogOptions.cs index b8c143e9..c6a92e67 100644 --- a/src/PostHog/Config/PostHogOptions.cs +++ b/src/PostHog/Config/PostHogOptions.cs @@ -67,6 +67,20 @@ public string? ProjectApiKey /// public IReadOnlyList? EvaluationContexts { get; set; } + /// + /// Whether captured events are attributed to a server. (Default: true) + /// + /// + /// When true (the default), every captured event includes the $is_server property set to + /// true so PostHog identifies the event as server-side. Set this to false when using the SDK + /// as a client or CLI so the device's operating system is attributed normally instead of being treated as a + /// server. When false, the $is_server property is omitted entirely. + /// + /// var options = new PostHogOptions { ProjectToken = "phc_...", IsServer = false }; + /// + /// + public bool IsServer { get; set; } = true; + /// /// Whether this client is disabled and should no-op instead of sending data to PostHog. (Default: false) /// diff --git a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs index 31a2b2e6..6fdbfa8b 100644 --- a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs +++ b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs @@ -19,13 +19,17 @@ internal class ExceptionPropertiesBuilder public static Dictionary Build( Dictionary properties, - Exception exception) + Exception exception, + bool isServer = true) { properties["$exception_type"] = exception.GetType().FullName ?? exception.GetType().Name; properties["$exception_message"] = exception.Message; properties["$exception_level"] = "error"; properties["$lib"] = "posthog-dotnet"; - properties[PostHogProperties.IsServer] = true; + if (isServer) + { + properties[PostHogProperties.IsServer] = true; + } properties["$lib_version"] = VersionConstants.Version; properties["$os"] = OperatingSystemInfo.Name; properties["$os_version"] = OperatingSystemInfo.Version; diff --git a/src/PostHog/PostHogClient.cs b/src/PostHog/PostHogClient.cs index 68370e14..4f16f38a 100644 --- a/src/PostHog/PostHogClient.cs +++ b/src/PostHog/PostHogClient.cs @@ -304,7 +304,8 @@ bool CaptureCore( eventName, captureContext.DistinctId, captureContext.Properties, - timestamp: timestamp ?? _timeProvider.GetUtcNow()); + timestamp: timestamp ?? _timeProvider.GetUtcNow(), + isServer: _options.Value.IsServer); if (groups is { Count: > 0 }) { @@ -400,7 +401,7 @@ bool CaptureExceptionCore( } properties["$exception_personURL"] = $"{host}/project/{_options.Value.ProjectToken}/person/{identity.DistinctId}"; - properties = ExceptionPropertiesBuilder.Build(properties, exception); + properties = ExceptionPropertiesBuilder.Build(properties, exception, _options.Value.IsServer); return CaptureCore(identity.DistinctId, "$exception", properties, groups, sendFeatureFlags, flags, timestamp); } diff --git a/tests/UnitTests/Api/CapturedEventTests.cs b/tests/UnitTests/Api/CapturedEventTests.cs index 8c110063..88136ca0 100644 --- a/tests/UnitTests/Api/CapturedEventTests.cs +++ b/tests/UnitTests/Api/CapturedEventTests.cs @@ -87,6 +87,14 @@ public void AddsLibraryProperties() Assert.True(capturedEvent.Properties.ContainsKey("$lib_version")); } + [Fact] + public void OmitsIsServerWhenIsServerIsFalse() + { + var capturedEvent = new CapturedEvent("test-event", "user-1", null, DateTimeOffset.UtcNow, isServer: false); + + Assert.False(capturedEvent.Properties.ContainsKey("$is_server")); + } + [Fact] public void SetsGeoIpDisableToTrueByDefault() { diff --git a/tests/UnitTests/PostHogClientTests.cs b/tests/UnitTests/PostHogClientTests.cs index 434f0919..fe24e334 100644 --- a/tests/UnitTests/PostHogClientTests.cs +++ b/tests/UnitTests/PostHogClientTests.cs @@ -52,6 +52,42 @@ public async Task SendsCorrectPayload() """, received); } + [Fact] + public async Task OmitsIsServerWhenIsServerOptionIsFalse() + { + var container = new TestContainer(services => services.Configure(options => + { + options.ProjectToken = "fake-project-token"; + options.EnableCompression = false; + options.IsServer = false; + })); + container.FakeTimeProvider.SetUtcNow(new DateTimeOffset(2024, 1, 21, 19, 08, 23, TimeSpan.Zero)); + var requestHandler = container.FakeHttpMessageHandler.AddCaptureResponse(); + var client = container.Activate(); + + var result = await client.IdentifyAsync("some-distinct-id"); + + Assert.Equal(1, result.Status); + var received = requestHandler.GetReceivedRequestBody(indented: true); + Assert.DoesNotContain("$is_server", received, StringComparison.Ordinal); + Assert.Equal($$""" + { + "event": "$identify", + "distinct_id": "some-distinct-id", + "properties": { + "$lib": "posthog-dotnet", + "$lib_version": "{{VersionConstants.Version}}", + "$os": "{{RuntimeInformation.OSDescription}}", + "$framework": "{{RuntimeInformation.FrameworkDescription}}", + "$arch": "{{RuntimeInformation.ProcessArchitecture}}", + "$geoip_disable": true + }, + "api_key": "fake-project-token", + "timestamp": "2024-01-21T19:08:23\u002B00:00" + } + """, received); + } + [Fact] // Similar to PostHog/posthog-python test_basic_identify public async Task SendsCorrectPayloadWithGeoIpEnabled() { From 3abc22a7b005a4d49a8a19743296a4bfa4b98ee5 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Wed, 3 Jun 2026 10:52:44 -0400 Subject: [PATCH 4/5] chore: bump changeset to minor (new is_server option) --- .changeset/is-server-property.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/is-server-property.md b/.changeset/is-server-property.md index cb603e74..4645ba58 100644 --- a/.changeset/is-server-property.md +++ b/.changeset/is-server-property.md @@ -1,5 +1,5 @@ --- -"PostHog": patch +"PostHog": minor --- Add a configurable `$is_server` event property (default `true`) so PostHog can identify server-side events. Set `PostHogOptions.IsServer` to `false` when using the SDK as a client/CLI so the device OS is attributed normally. From ceb73900e41e120d433f24729524dc69b78a9345 Mon Sep 17 00:00:00 2001 From: Anna Garcia Date: Wed, 3 Jun 2026 14:02:58 -0400 Subject: [PATCH 5/5] refactor: stamp $is_server in CaptureCore, not CapturedEvent (no public API change) --- src/PostHog/Api/CapturedEvent.cs | 12 +-- src/PostHog/Api/PostHogApiClient.cs | 10 ++- .../ExceptionPropertiesBuilder.cs | 10 +-- src/PostHog/PostHogClient.cs | 11 ++- tests/UnitTests/Api/CapturedEventTests.cs | 10 --- tests/UnitTests/Features/FeatureFlagsTests.cs | 80 +++++++++---------- tests/UnitTests/PostHogClientTests.cs | 72 ++++++++--------- 7 files changed, 93 insertions(+), 112 deletions(-) diff --git a/src/PostHog/Api/CapturedEvent.cs b/src/PostHog/Api/CapturedEvent.cs index 1923d2a0..bebfbc89 100644 --- a/src/PostHog/Api/CapturedEvent.cs +++ b/src/PostHog/Api/CapturedEvent.cs @@ -16,17 +16,11 @@ public class CapturedEvent /// The identifier for the user. /// The properties to associate with the event. /// The ISO 8601 timestamp. - /// - /// When true (the default), the event includes the $is_server property set to true. Set to - /// false (via ) when using the SDK as a client/CLI so the device OS - /// is attributed normally; the property is then omitted. - /// public CapturedEvent( string eventName, string distinctId, Dictionary? properties, - DateTimeOffset timestamp, - bool isServer = true) + DateTimeOffset timestamp) { Uuid = Guid.NewGuid().ToString(); EventName = eventName; @@ -38,10 +32,6 @@ public CapturedEvent( // Every event has to have these properties. Properties[PostHogProperties.DistinctId] = distinctId; // See `get_distinct_id` in PostHog/posthog api/capture.py line 321 Properties[PostHogProperties.Lib] = PostHogApiClient.LibraryName; - if (isServer) - { - Properties[PostHogProperties.IsServer] = true; - } Properties[PostHogProperties.LibVersion] = VersionConstants.Version; Properties[PostHogProperties.GeoIpDisable] = Properties.GetValueOrDefault(PostHogProperties.GeoIpDisable, true); } diff --git a/src/PostHog/Api/PostHogApiClient.cs b/src/PostHog/Api/PostHogApiClient.cs index bbf711c0..f188d50a 100644 --- a/src/PostHog/Api/PostHogApiClient.cs +++ b/src/PostHog/Api/PostHogApiClient.cs @@ -277,10 +277,6 @@ void PrepareAndMutatePayload(Dictionary payload) var properties = payload.GetOrAdd>("properties"); properties[PostHogProperties.Lib] = LibraryName; - if (_options.Value.IsServer) - { - properties[PostHogProperties.IsServer] = true; - } properties[PostHogProperties.LibVersion] = VersionConstants.Version; properties[PostHogProperties.Os] = RuntimeInformation.OSDescription; properties[PostHogProperties.Framework] = RuntimeInformation.FrameworkDescription; @@ -289,6 +285,12 @@ void PrepareAndMutatePayload(Dictionary payload) properties.Merge(_options.Value.SuperProperties); + // Stamp $is_server last so a super property can't override the SDK's server/client classification. + if (_options.Value.IsServer) + { + properties[PostHogProperties.IsServer] = true; + } + payload["properties"] = properties; // Only set timestamp if one isn't already provided in properties diff --git a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs index 6fdbfa8b..c1cc453a 100644 --- a/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs +++ b/src/PostHog/ErrorTracking/ExceptionPropertiesBuilder.cs @@ -1,5 +1,4 @@ -using PostHog.Api; -using PostHog.Library; +using PostHog.Library; using PostHog.Versioning; using System.Runtime.InteropServices; using System.Text; @@ -19,17 +18,12 @@ internal class ExceptionPropertiesBuilder public static Dictionary Build( Dictionary properties, - Exception exception, - bool isServer = true) + Exception exception) { properties["$exception_type"] = exception.GetType().FullName ?? exception.GetType().Name; properties["$exception_message"] = exception.Message; properties["$exception_level"] = "error"; properties["$lib"] = "posthog-dotnet"; - if (isServer) - { - properties[PostHogProperties.IsServer] = true; - } properties["$lib_version"] = VersionConstants.Version; properties["$os"] = OperatingSystemInfo.Name; properties["$os_version"] = OperatingSystemInfo.Version; diff --git a/src/PostHog/PostHogClient.cs b/src/PostHog/PostHogClient.cs index 4f16f38a..ad9475e4 100644 --- a/src/PostHog/PostHogClient.cs +++ b/src/PostHog/PostHogClient.cs @@ -304,8 +304,7 @@ bool CaptureCore( eventName, captureContext.DistinctId, captureContext.Properties, - timestamp: timestamp ?? _timeProvider.GetUtcNow(), - isServer: _options.Value.IsServer); + timestamp: timestamp ?? _timeProvider.GetUtcNow()); if (groups is { Count: > 0 }) { @@ -314,6 +313,12 @@ bool CaptureCore( capturedEvent.Properties.Merge(_options.Value.SuperProperties); + // Stamp $is_server last so a super property can't override the SDK's server/client classification. + if (_options.Value.IsServer) + { + capturedEvent.Properties[PostHogProperties.IsServer] = true; + } + var batchItem = new BatchItem(BatchTask); if (_asyncBatchHandler.Enqueue(batchItem)) @@ -401,7 +406,7 @@ bool CaptureExceptionCore( } properties["$exception_personURL"] = $"{host}/project/{_options.Value.ProjectToken}/person/{identity.DistinctId}"; - properties = ExceptionPropertiesBuilder.Build(properties, exception, _options.Value.IsServer); + properties = ExceptionPropertiesBuilder.Build(properties, exception); return CaptureCore(identity.DistinctId, "$exception", properties, groups, sendFeatureFlags, flags, timestamp); } diff --git a/tests/UnitTests/Api/CapturedEventTests.cs b/tests/UnitTests/Api/CapturedEventTests.cs index 88136ca0..b475d4f2 100644 --- a/tests/UnitTests/Api/CapturedEventTests.cs +++ b/tests/UnitTests/Api/CapturedEventTests.cs @@ -82,19 +82,9 @@ public void AddsLibraryProperties() Assert.True(capturedEvent.Properties.TryGetValue("$lib", out var lib)); Assert.Equal("posthog-dotnet", lib); - Assert.True(capturedEvent.Properties.TryGetValue("$is_server", out var isServer)); - Assert.Equal(true, isServer); Assert.True(capturedEvent.Properties.ContainsKey("$lib_version")); } - [Fact] - public void OmitsIsServerWhenIsServerIsFalse() - { - var capturedEvent = new CapturedEvent("test-event", "user-1", null, DateTimeOffset.UtcNow, isServer: false); - - Assert.False(capturedEvent.Properties.ContainsKey("$is_server")); - } - [Fact] public void SetsGeoIpDisableToTrueByDefault() { diff --git a/tests/UnitTests/Features/FeatureFlagsTests.cs b/tests/UnitTests/Features/FeatureFlagsTests.cs index c15fdf33..5ce39774 100644 --- a/tests/UnitTests/Features/FeatureFlagsTests.cs +++ b/tests/UnitTests/Features/FeatureFlagsTests.cs @@ -196,9 +196,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -215,9 +215,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -234,9 +234,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -292,9 +292,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -309,9 +309,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": true, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -326,9 +326,9 @@ public async Task CapturesFeatureFlagCalledEventOnlyOncePerDistinctIdFlagKeyAndR "$feature/flag-key": false, "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -503,9 +503,9 @@ await client.IsFeatureEnabledAsync( "$feature_flag_definitions_loaded_at": 1705864103000, "distinct_id": "659df793-429a-4517-84ff-747dfc103e6c", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -555,9 +555,9 @@ public async Task CapturesFeatureFlagCalledEventWithRequestIdWhenPresent() "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -608,9 +608,9 @@ public async Task CapturesFeatureFlagCalledEventWithoutEvaluatedAtWhenNotPresent "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -737,9 +737,9 @@ public async Task CapturesFeatureFlagCalledEventWithAdditionalMetadataIdWhenPres "$feature_flag_evaluated_at": 1705862903000, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -2464,9 +2464,9 @@ public async Task CapturesFeatureFlagCalledEvent() "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -2514,13 +2514,13 @@ public async Task CapturesFeatureFlagCalledEventWithGroupInformation() "$feature/flag-key": true, "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", "$geoip_disable": true, "$groups": { "company": "id:5", "department": "id:3" - } + }, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -2580,9 +2580,9 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -2597,9 +2597,9 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:24\u002B00:00" }, @@ -2614,9 +2614,9 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/another-flag-key": "flag-variant-2", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:25\u002B00:00" }, @@ -2631,9 +2631,9 @@ await client.GetFeatureFlagAsync("another-flag-key", "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:27\u002B00:00" } @@ -2688,9 +2688,9 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }, @@ -2705,9 +2705,9 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:24\u002B00:00" }, @@ -2722,9 +2722,9 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/another-flag-key": "flag-variant-2", "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:25\u002B00:00" }, @@ -2739,9 +2739,9 @@ public async Task CapturesFeatureFlagCalledEventAgainIfCacheSlidingWindowExpirat "$feature/flag-key": "flag-variant-1", "distinct_id": "a-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{client.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:27\u002B00:00" } diff --git a/tests/UnitTests/PostHogClientTests.cs b/tests/UnitTests/PostHogClientTests.cs index fe24e334..4009ae0a 100644 --- a/tests/UnitTests/PostHogClientTests.cs +++ b/tests/UnitTests/PostHogClientTests.cs @@ -39,12 +39,12 @@ public async Task SendsCorrectPayload() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -106,12 +106,12 @@ public async Task SendsCorrectPayloadWithGeoIpEnabled() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", - "$geoip_disable": false + "$geoip_disable": false, + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -151,12 +151,12 @@ public async Task SendsCorrectPayloadWithPersonProperties() "join_date": "2024-01-21" }, "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -190,13 +190,13 @@ public async Task SendsCorrectPayloadWithSuperProperties() "distinct_id": "some-distinct-id", "properties": { "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", "$geoip_disable": true, - "source": "repo-name" + "source": "repo-name", + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -230,12 +230,12 @@ public async Task SendsCorrectPayload() "name": "PostHog" }, "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -266,12 +266,12 @@ public async Task SendsCorrectPayloadWithUserProvidedDistinctId() "name": "PostHog" }, "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$os": "{{RuntimeInformation.OSDescription}}", "$framework": "{{RuntimeInformation.FrameworkDescription}}", "$arch": "{{RuntimeInformation.ProcessArchitecture}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "api_key": "fake-project-token", "timestamp": "2024-01-21T19:08:23\u002B00:00" @@ -318,9 +318,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-0", @@ -338,9 +338,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-0", @@ -358,9 +358,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-1", @@ -378,9 +378,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-0", @@ -398,9 +398,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "some-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-0", @@ -418,9 +418,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "another-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-1", @@ -438,9 +438,9 @@ public async Task SendsEnrichedCapturedEventsWhenSendFeatureFlagsTrueButDoesNotM "properties": { "distinct_id": "third-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/flag1": true, "$feature/flag2": false, "$feature/flag3": "variant-2", @@ -483,9 +483,9 @@ public async Task CaptureWithCustomTimestampUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2023-12-25T10:30:45\u002B00:00" } @@ -522,9 +522,9 @@ public async Task CaptureWithTimestampAndPropertiesUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2023-12-25T10:30:45\u002B00:00" } @@ -560,12 +560,12 @@ public async Task CaptureWithTimestampAndGroupsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { "company": "acme-corp" - } + }, + "$is_server": true }, "timestamp": "2023-12-25T10:30:45\u002B00:00" } @@ -601,9 +601,9 @@ public async Task CaptureWithTimestampAndFeatureFlagsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/test-flag": true, "$active_feature_flags": [ "test-flag" @@ -645,12 +645,12 @@ public async Task CaptureWithTimestampPropertiesAndGroupsUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { "company": "acme-corp" - } + }, + "$is_server": true }, "timestamp": "2023-12-25T10:30:45\u002B00:00" } @@ -689,12 +689,12 @@ public async Task CaptureWithAllParametersAndTimestampUsesProvidedTimestamp() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, "$groups": { "company": "acme-corp" }, + "$is_server": true, "$feature/test-flag": true, "$active_feature_flags": [ "test-flag" @@ -740,9 +740,9 @@ public async Task CaptureWithTimestampParameterOverridesTimestampInProperties() "timestamp": "2023-12-25T10:30:45\u002B00:00", "distinct_id": "test-user", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2023-12-25T10:30:45\u002B00:00" } @@ -816,9 +816,9 @@ public async Task CaptureWithSendFeatureFlagsTrueAndLocalEvaluationEnabledUsesLo "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", "$geoip_disable": true, + "$is_server": true, "$feature/local-flag": true, "$feature/another-local-flag": true, "$active_feature_flags": [ @@ -884,9 +884,9 @@ public async Task CaptureWithSendFeatureFlagsFalseDoesNotAddFeatureFlagsEvenWhen "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" } @@ -947,9 +947,9 @@ public async Task CaptureDefaultsToNotSendingFeatureFlagsEvenWhenLocalEvaluation "properties": { "distinct_id": "test-distinct-id", "$lib": "posthog-dotnet", - "$is_server": true, "$lib_version": "{{VersionConstants.Version}}", - "$geoip_disable": true + "$geoip_disable": true, + "$is_server": true }, "timestamp": "2024-01-21T19:08:23\u002B00:00" }