Skip to content

Commit

Permalink
chore: deduplicate subsequent identify calls (#1649)
Browse files Browse the repository at this point in the history
* feat: deduplicate identify calls

* chore: cache identify on first call

* chore: pull hash fn off the class, add logging
  • Loading branch information
joshsny authored Jan 16, 2025
1 parent e0c4ba4 commit 3b5e599
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
16 changes: 16 additions & 0 deletions src/__tests__/posthog-core.identify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,22 @@ describe('identify()', () => {
)
expect(instance.featureFlags.setAnonymousDistinctId).not.toHaveBeenCalled()
})

it('does not call $set when duplicate properties are passed', () => {
instance.identify('a-new-id', { email: '[email protected]' }, { howOftenAmISet: 'once!' })
instance.identify('a-new-id', { email: '[email protected]' }, { howOftenAmISet: 'once!' })

expect(beforeSendMock).toHaveBeenCalledTimes(1)
expect(instance.featureFlags.setAnonymousDistinctId).not.toHaveBeenCalled()
})

it('calls $set when different properties are passed with the same distinct_id', () => {
instance.identify('a-new-id', { email: '[email protected]' }, { howOftenAmISet: 'once!' })
instance.identify('a-new-id', { email: '[email protected]' }, { howOftenAmISet: 'twice!' })

expect(beforeSendMock).toHaveBeenCalledTimes(2)
expect(instance.featureFlags.setAnonymousDistinctId).not.toHaveBeenCalled()
})
})

describe('invalid id passed', () => {
Expand Down
23 changes: 20 additions & 3 deletions src/posthog-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import { PostHogExceptions } from './posthog-exceptions'
import { SiteApps } from './site-apps'
import { DeadClicksAutocapture, isDeadClicksEnabledForAutocapture } from './extensions/dead-clicks-autocapture'
import { includes, isDistinctIdStringLike } from './utils/string-utils'
import { getIdentifyHash } from './utils/identify-utils'

/*
SIMPLE STYLE GUIDE:
Expand Down Expand Up @@ -281,6 +282,7 @@ export class PostHog {
analyticsDefaultEndpoint: string
version = Config.LIB_VERSION
_initialPersonProfilesConfig: 'always' | 'never' | 'identified_only' | null
_cachedIdentify: string | null

SentryIntegration: typeof SentryIntegration
sentryIntegration: (options?: SentryIntegrationOptions) => ReturnType<typeof sentryIntegration>
Expand Down Expand Up @@ -308,7 +310,7 @@ export class PostHog {
this.analyticsDefaultEndpoint = '/e/'
this._initialPageviewCaptured = false
this._initialPersonProfilesConfig = null

this._cachedIdentify = null
this.featureFlags = new PostHogFeatureFlags(this)
this.toolbar = new Toolbar(this)
this.scrollManager = new ScrollManager(this)
Expand Down Expand Up @@ -1435,9 +1437,21 @@ export class PostHog {
// let the reload feature flag request know to send this previous distinct id
// for flag consistency
this.featureFlags.setAnonymousDistinctId(previous_distinct_id)

this._cachedIdentify = getIdentifyHash(new_distinct_id, userPropertiesToSet, userPropertiesToSetOnce)
} else if (userPropertiesToSet || userPropertiesToSetOnce) {
// If the distinct_id is not changing, but we have user properties to set, we can go for a $set event
this.setPersonProperties(userPropertiesToSet, userPropertiesToSetOnce)
// If the distinct_id is not changing, but we have user properties to set, we can check if they have changed
// and if so, send a $set event

if (
this._cachedIdentify !== getIdentifyHash(new_distinct_id, userPropertiesToSet, userPropertiesToSetOnce)
) {
this.setPersonProperties(userPropertiesToSet, userPropertiesToSetOnce)

this._cachedIdentify = getIdentifyHash(new_distinct_id, userPropertiesToSet, userPropertiesToSetOnce)
} else {
logger.info('A duplicate posthog.identify call was made with the same properties. It has been ignored.')
}
}

// Reload active feature flags if the user identity changes.
Expand Down Expand Up @@ -1469,6 +1483,8 @@ export class PostHog {
// Update current user properties
this.setPersonPropertiesForFlags(userPropertiesToSet || {})

// if exactly this $set call has been sent before, don't send it again - determine based on hash of properties

this.capture('$set', { $set: userPropertiesToSet || {}, $set_once: userPropertiesToSetOnce || {} })
}

Expand Down Expand Up @@ -1573,6 +1589,7 @@ export class PostHog {
this.surveys?.reset()
this.persistence?.set_property(USER_STATE, 'anonymous')
this.sessionManager?.resetSessionId()
this._cachedIdentify = null
if (this.config.__preview_experimental_cookieless_mode) {
this.register_once(
{
Expand Down
10 changes: 10 additions & 0 deletions src/utils/identify-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { jsonStringify } from '../request'
import type { Properties } from '../types'

export function getIdentifyHash(
distinct_id: string,
userPropertiesToSet?: Properties,
userPropertiesToSetOnce?: Properties
): string {
return jsonStringify({ distinct_id, userPropertiesToSet, userPropertiesToSetOnce })
}

0 comments on commit 3b5e599

Please sign in to comment.