Skip to content

Nested JsonObject properties are serialized as empty objects #299

@Maikkelinen

Description

@Maikkelinen

Description:
Nested JsonObject values within track event properties are sent to Segment servers as empty objects {}, while the equivalent structure works correctly with the Swift SDK (analytics-swift).

Environment:

  • analytics-kotlin version: 1.24.1 (also reproduced on 1.22.0)
  • Android API: 35
  • Kotlin: 2.0.21
  • kotlinx.serialization: (bundled with SDK)
  • Device: Pixel emulator (sdk_gphone64_arm64), Android 15

Steps to Reproduce:

  val props = buildJsonObject {
      putJsonObject("selected_values") {
          putJsonArray("key") {
              add(JsonPrimitive("value_1"))
              add(JsonPrimitive("value_2"))
          }
      }
      put("skipped", false)
  }
  // Log confirms correct structure:
  // {"selected_values":{"key":["value_1","value_2"]},"skipped":false}
  Log.i("Debug", "payload: $props")

  analytics.track("Tracking Event", props)

Expected Result:

Segment receives:

  {
    "properties": {
      "selected_values": {
        "key": ["value_1", "value_2"]
      },
      "skipped": false
    }
  }

Actual Result:

Segment raw data shows:

  {
    "properties": {
      "selected_values": {},
      "skipped": false
    },
    "context": {
      "protocols": {
        "omitted": ["selected_values.key"]
      }
    }
  }

The nested object arrives empty and the nested field appears in protocols.omitted.

Additional context:

  • The JsonObject is correct in memory — logging .toString() before passing to analytics.track() shows the full nested structure
  • We tried multiple approaches: buildJsonObject with putJsonObject/putJsonArray, JsonObject(map) constructor, and re-parsing via Json.parseToJsonElement() — all produce the same empty result on the server
  • The identical event structure sent from analytics-swift (iOS) works correctly — the same Segment source and tracking plan receives the nested object with all data intact
  • Flat properties (strings, booleans, numbers) work fine — only nested objects are affected

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions