Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/strict-identify-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'posthog-js': minor
---

Reject the strings "undefined" and "null" in posthog.identify(). All invalid distinct IDs now log a critical console error (always visible, not debug-only).
29 changes: 29 additions & 0 deletions packages/browser/src/__tests__/identify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,35 @@ describe('identify', () => {
)
})

describe('invalid distinct_id', () => {
it.each([
['undefined', undefined, 'Unique user id has not been set in posthog.identify'],
['null', null, 'Unique user id has not been set in posthog.identify'],
['empty string', '', 'Unique user id has not been set in posthog.identify'],
['whitespace only', ' ', 'Unique user id has not been set in posthog.identify'],
['false', false, 'Unique user id has not been set in posthog.identify'],
[
'the string "undefined"',
'undefined',
'The string "undefined" was set in posthog.identify which indicates an error. This ID should be unique to the user and not a hardcoded string.',
],
[
'the string "null"',
'null',
'The string "null" was set in posthog.identify which indicates an error. This ID should be unique to the user and not a hardcoded string.',
],
])('should reject %s and log a critical error', async (_label, invalidId, expectedMessage) => {
const token = uuidv7()
const beforeSendMock = jest.fn().mockImplementation((e) => e)
const posthog = await createPosthogInstance(token, { before_send: beforeSendMock })

posthog.identify(invalidId as any)

expect(beforeSendMock).not.toHaveBeenCalled()
expect(mockLogger.critical).toHaveBeenCalledWith(expectedMessage)
})
})

it('should send $is_identified = true with the identify event and following events', async () => {
// arrange
const token = uuidv7()
Expand Down
37 changes: 21 additions & 16 deletions packages/browser/src/posthog-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2290,6 +2290,26 @@ export class PostHog implements PostHogInterface {
)
}

private _validateIdentifyId(id: string | undefined): id is string {
if (!id || isEmptyString(id)) {
logger.critical('Unique user id has not been set in posthog.identify')
return false
}
if (id === COOKIELESS_SENTINEL_VALUE) {
logger.critical(
`The string "${id}" was set in posthog.identify which indicates an error. This ID is only used as a sentinel value.`
)
return false
}
if (isDistinctIdStringLike(id) || ['undefined', 'null'].includes(id.toLowerCase())) {
logger.critical(
`The string "${id}" was set in posthog.identify which indicates an error. This ID should be unique to the user and not a hardcoded string.`
)
return false
}
return true
}

/**
* Associates a user with a unique identifier instead of an auto-generated ID.
* Learn more about [identifying users](/docs/product-analytics/identify)
Expand Down Expand Up @@ -2342,22 +2362,7 @@ export class PostHog implements PostHogInterface {
)
}

//if the new_distinct_id has not been set ignore the identify event
if (!new_distinct_id) {
logger.error('Unique user id has not been set in posthog.identify')
return
}

if (isDistinctIdStringLike(new_distinct_id)) {
logger.critical(
`The string "${new_distinct_id}" was set in posthog.identify which indicates an error. This ID should be unique to the user and not a hardcoded string.`
)
return
}
if (new_distinct_id === COOKIELESS_SENTINEL_VALUE) {
logger.critical(
`The string "${COOKIELESS_SENTINEL_VALUE}" was set in posthog.identify which indicates an error. This ID is only used as a sentinel value.`
)
if (!this._validateIdentifyId(new_distinct_id)) {
return
}

Expand Down
1 change: 1 addition & 0 deletions packages/browser/terser-mangled-names.json
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@
"_urlTriggerStatus",
"_urlTriggers",
"_validateEmail",
"_validateIdentifyId",
"_validateSampleRate",
"_visibilityChangeListener",
"_visibilityStateListener",
Expand Down
Loading