Skip to content

Commit

Permalink
feat: Remotely enable heatmaps via decide (#1154)
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite authored Apr 24, 2024
1 parent 940412c commit a352739
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 3 deletions.
35 changes: 35 additions & 0 deletions src/__tests__/heatmaps.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createPosthogInstance } from './helpers/posthog-instance'
import { uuidv7 } from '../uuidv7'
import { PostHog } from '../posthog-core'
import { DecideResponse } from '../types'
jest.mock('../utils/logger')

describe('heatmaps', () => {
Expand Down Expand Up @@ -105,4 +106,38 @@ describe('heatmaps', () => {
)
expect(posthog.heatmaps?.['buffer']).not.toEqual(undefined)
})

describe('afterDecideResponse()', () => {
it('should not be enabled before the decide response', () => {
expect(posthog.heatmaps!.isEnabled).toBe(false)
})

it('should be enabled if client config option is enabled', () => {
posthog.config.__preview_heatmaps = true
expect(posthog.heatmaps!.isEnabled).toBe(true)
})

it.each([
// Client not defined
[undefined, false, false],
[undefined, true, true],
[undefined, false, false],
// Client false
[false, false, false],
[false, true, false],

// Client true
[true, false, true],
[true, true, true],
])(
'when client side config is %p and remote opt in is %p - heatmaps enabled should be %p',
(clientSideOptIn, serverSideOptIn, expected) => {
posthog.config.__preview_heatmaps = clientSideOptIn
posthog.heatmaps!.afterDecideResponse({
heatmaps: serverSideOptIn,
} as DecideResponse)
expect(posthog.heatmaps!.isEnabled).toBe(expected)
}
)
})
})
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const ALIAS_ID_KEY = '__alias'
export const CAMPAIGN_IDS_KEY = '__cmpns'
export const EVENT_TIMERS_KEY = '__timers'
export const AUTOCAPTURE_DISABLED_SERVER_SIDE = '$autocapture_disabled_server_side'
export const HEATMAPS_ENABLED_SERVER_SIDE = '$heatmaps_enabled_server_side'
export const SESSION_RECORDING_ENABLED_SERVER_SIDE = '$session_recording_enabled_server_side'
export const CONSOLE_LOG_RECORDING_ENABLED_SERVER_SIDE = '$console_log_recording_enabled_server_side'
export const SESSION_RECORDING_NETWORK_PAYLOAD_CAPTURE = '$session_recording_network_payload_capture'
Expand Down Expand Up @@ -39,6 +40,7 @@ export const PERSISTENCE_RESERVED_PROPERTIES = [
CAMPAIGN_IDS_KEY,
EVENT_TIMERS_KEY,
SESSION_RECORDING_ENABLED_SERVER_SIDE,
HEATMAPS_ENABLED_SERVER_SIDE,
SESSION_ID,
ENABLED_FEATURE_FLAGS,
USER_STATE,
Expand Down
24 changes: 21 additions & 3 deletions src/heatmaps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { includes, registerEvent } from './utils'
import RageClick from './extensions/rageclick'
import { Properties } from './types'
import { DecideResponse, Properties } from './types'
import { PostHog } from './posthog-core'

import { document, window } from './utils/globals'
import { getParentElement, isTag } from './autocapture-utils'
import { HEATMAPS_ENABLED_SERVER_SIDE } from './constants'
import { isUndefined } from './utils/type-utils'

type HeatmapEventBuffer =
| {
Expand Down Expand Up @@ -40,7 +42,7 @@ function elementInToolbar(el: Element): boolean {
export class Heatmaps {
instance: PostHog
rageclicks = new RageClick()
_isDisabledServerSide: boolean | null = null
_enabledServerSide: boolean = false
_initialized = false
_mouseMoveTimeout: number | undefined

Expand All @@ -49,6 +51,7 @@ export class Heatmaps {

constructor(instance: PostHog) {
this.instance = instance
this._enabledServerSide = !!this.instance.persistence?.props[HEATMAPS_ENABLED_SERVER_SIDE]
}

public startIfEnabled(): void {
Expand All @@ -58,7 +61,22 @@ export class Heatmaps {
}

public get isEnabled(): boolean {
return !!this.instance.config.__preview_heatmaps
return !isUndefined(this.instance.config.__preview_heatmaps)
? this.instance.config.__preview_heatmaps
: this._enabledServerSide
}

public afterDecideResponse(response: DecideResponse) {
const optIn = !!response['heatmaps']

if (this.instance.persistence) {
this.instance.persistence.register({
[HEATMAPS_ENABLED_SERVER_SIDE]: optIn,
})
}
// store this in-memory in case persistence is disabled
this._enabledServerSide = optIn
this.startIfEnabled()
}

public getAndClearBuffer(): HeatmapEventBuffer {
Expand Down
1 change: 1 addition & 0 deletions src/posthog-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ export class PostHog {

this.sessionRecording?.afterDecideResponse(response)
this.autocapture?.afterDecideResponse(response)
this.heatmaps?.afterDecideResponse(response)
this.surveys?.afterDecideResponse(response)
}

Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ export interface DecideResponse {
toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */
isAuthenticated: boolean
siteApps: { id: number; url: string }[]
heatmaps?: boolean
}

export type FeatureFlagsCallback = (
Expand Down

0 comments on commit a352739

Please sign in to comment.