Skip to content

Conversation

@apsinghhhh1
Copy link

Fix Flattened Parameter Handling in posthog-js

Overview

This PR improves how posthog-js processes flattened and nested parameters. Previously, deeply nested or multi-encoded values (for example, UTM parameters or complex query strings) were not being decoded and reconstructed correctly. This resulted in incorrect or missing properties in event payloads.

The update ensures parameters are fully normalized, decoded, and merged before being sent to PostHog.


Problem

Flattened parameters received from URLs or encoded tracking payloads often contain:

  • Nested values represented in flattened form
  • Values encoded multiple times
  • Objects that need reconstruction
  • Parameters that merge inconsistently across callers

Because the library didn’t recursively decode or unflatten these structures, some analytics events ended up with incomplete or incorrect data.

This PR addresses that issue by ensuring robust decoding and reconstruction.


Changes

  • Added support for multi-layer decoding of nested parameters
  • Improved logic to normalize and reconstruct flattened objects
  • Ensured merged params follow consistent, predictable behavior
  • Maintained backward compatibility with existing API behavior

Libraries Affected

  • posthog-js (web)
  • posthog-js-lite
  • posthog-node
  • posthog-react-native
  • @posthog/react
  • @posthog/ai
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin

Checklist

  • Added tests for new decoding and reconstruction logic
  • Ensured behavior is consistent across platforms
  • No breaking changes introduced
  • No unnecessary bundle-size impact

Releasing

  • Ran pnpm changeset to generate a changeset file
  • Added the release label to publish new versions of affected packages

@vercel
Copy link

vercel bot commented Dec 5, 2025

@apsinghhhh1 is attempting to deploy a commit to the PostHog Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (4)

  1. packages/browser/src/utils/request-utils.ts, line 175 (link)

    logic: new URL() isn't supported in IE11, but the browserslist specifies "IE 11" support. The old code avoided URL() with a comment: "NOTE: Once we get rid of IE11/op_mini we can start using URLSearchParams"

  2. packages/browser/src/utils/request-utils.ts, line 210 (link)

    logic: returns undefined when param doesn't exist (due to optional chaining on possibly empty object), but the function signature says it returns string. This breaks the API contract of the original implementation which always returned a string (empty string for missing params).

  3. packages/browser/src/utils/request-utils.ts, line 141-148 (link)

    style: if decoded = "value&key2=value2", then firstPart = "value" and this assigns finalParams[key] = "value". But then line 151 recursively extracts {key2: "value2"} into finalParams, overwriting the first assignment if the nested params happen to have a key that matches the parent key. Consider if this behavior is intentional.

  4. packages/browser/src/utils/request-utils.ts, line 54 (link)

    syntax: unused variable prev - can be removed

1 file reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant