diff --git a/plugin-server/src/utils/db/utils.ts b/plugin-server/src/utils/db/utils.ts index 6f7eeedfafaaa..7fe9e90d09aad 100644 --- a/plugin-server/src/utils/db/utils.ts +++ b/plugin-server/src/utils/db/utils.ts @@ -65,6 +65,7 @@ export const eventToPersonProperties = new Set([ '$current_url', '$pathname', '$os', + '$os_name', // $os_name is a special case, it's treated as an alias of $os! '$os_version', '$referring_domain', '$referrer', @@ -117,6 +118,18 @@ export function personInitialAndUTMProperties(properties: Properties): Propertie if (maybeSetOnce.length > 0) { propertiesCopy.$set_once = { ...Object.fromEntries(maybeSetOnce), ...(properties.$set_once || {}) } } + + if (propertiesCopy.$os_name) { + // For the purposes of $initial properties, $os_name is treated as a fallback alias of $os, starting August 2024 + // It's as special case due to _some_ SDKs using $os_name: https://github.com/PostHog/posthog-js-lite/issues/244 + propertiesCopy.$os ??= propertiesCopy.$os_name + propertiesCopy.$set.$os ??= propertiesCopy.$os_name + propertiesCopy.$set_once.$initial_os ??= propertiesCopy.$os_name + // Make sure $os_name is not used in $set/$set_once, as that hasn't been a thing before + delete propertiesCopy.$set.$os_name + delete propertiesCopy.$set_once.$initial_os_name + } + return propertiesCopy } diff --git a/plugin-server/tests/utils/db/utils.test.ts b/plugin-server/tests/utils/db/utils.test.ts index ec82e38c35fc6..1afcf4a06481e 100644 --- a/plugin-server/tests/utils/db/utils.test.ts +++ b/plugin-server/tests/utils/db/utils.test.ts @@ -108,4 +108,28 @@ describe('personInitialAndUTMProperties()', () => { $set: { $current_url: 'https://test.com' }, }) }) + + it('treats $os_name as fallback for $os', () => { + const propertiesOsNameOnly = { + $os_name: 'Android', + } + expect(personInitialAndUTMProperties(propertiesOsNameOnly)).toEqual({ + $os: 'Android', + $os_name: 'Android', + $set_once: { $initial_os: 'Android' }, + $set: { $os: 'Android' }, + }) + + // Also test that $os takes precedence, with $os_name preserved (although this should not happen in the wild) + const propertiesBothOsKeys = { + $os: 'Windows', + $os_name: 'Android', + } + expect(personInitialAndUTMProperties(propertiesBothOsKeys)).toEqual({ + $os: 'Windows', + $os_name: 'Android', + $set_once: { $initial_os: 'Windows' }, + $set: { $os: 'Windows' }, + }) + }) })