diff --git a/src/__tests__/extensions/surveys/action-matcher.test.ts b/src/__tests__/extensions/surveys/action-matcher.test.ts
index c7ef574f2..021088470 100644
--- a/src/__tests__/extensions/surveys/action-matcher.test.ts
+++ b/src/__tests__/extensions/surveys/action-matcher.test.ts
@@ -1,6 +1,6 @@
///
-import { ActionType, ActionStepStringMatching } from '../../../posthog-surveys-types'
+import { SurveyActionType, ActionStepStringMatching } from '../../../posthog-surveys-types'
import { PostHogPersistence } from '../../../posthog-persistence'
import { PostHog } from '../../../posthog-core'
import { CaptureResult, PostHogConfig } from '../../../types'
@@ -45,7 +45,7 @@ describe('action-matcher', () => {
eventName: string,
currentUrl?: string,
urlMatch?: ActionStepStringMatching
- ): ActionType => {
+ ): SurveyActionType => {
return {
id: id,
name: `${eventName || 'user defined '} action`,
@@ -68,7 +68,7 @@ describe('action-matcher', () => {
}
it('can match action on event name', () => {
- const pageViewAction = createAction(3, '$mypageview') as unknown as ActionType
+ const pageViewAction = createAction(3, '$mypageview') as unknown as SurveyActionType
const actionMatcher = new ActionMatcher(instance)
actionMatcher.register([pageViewAction])
let pageViewActionMatched = false
diff --git a/src/__tests__/utils/survey-event-receiver.test.ts b/src/__tests__/utils/survey-event-receiver.test.ts
index d36ff33e4..4ee51ed51 100644
--- a/src/__tests__/utils/survey-event-receiver.test.ts
+++ b/src/__tests__/utils/survey-event-receiver.test.ts
@@ -4,7 +4,7 @@ import {
SurveyType,
SurveyQuestionType,
Survey,
- ActionType,
+ SurveyActionType,
ActionStepStringMatching,
} from '../../posthog-surveys-types'
import { PostHogPersistence } from '../../posthog-persistence'
@@ -209,7 +209,7 @@ describe('survey-event-receiver', () => {
eventName: string,
currentUrl?: string,
urlMatch?: ActionStepStringMatching
- ): ActionType => {
+ ): SurveyActionType => {
return {
id: id,
name: `${eventName || 'user defined '} action`,
@@ -238,7 +238,7 @@ describe('survey-event-receiver', () => {
type: SurveyType.Popover,
questions: [{ type: SurveyQuestionType.Open, question: 'what is a bokoblin?' }],
conditions: {
- actions: [createAction(2, '$autocapture') as unknown as ActionType],
+ actions: [createAction(2, '$autocapture') as unknown as SurveyActionType],
},
} as unknown as Survey
@@ -249,7 +249,7 @@ describe('survey-event-receiver', () => {
type: SurveyType.Popover,
questions: [{ type: SurveyQuestionType.Open, question: 'what is a bokoblin?' }],
conditions: {
- actions: [createAction(3, '$pageview') as unknown as ActionType],
+ actions: [createAction(3, '$pageview') as unknown as SurveyActionType],
},
} as unknown as Survey
@@ -262,7 +262,7 @@ describe('survey-event-receiver', () => {
questions: [{ type: SurveyQuestionType.Open, question: 'what is a bokoblin?' }],
conditions: {
actions: {
- values: [createAction(3, '$mypageview') as unknown as ActionType],
+ values: [createAction(3, '$mypageview') as unknown as SurveyActionType],
},
},
} as unknown as Survey
diff --git a/src/extensions/surveys.tsx b/src/extensions/surveys.tsx
index b1fec5638..f4bbffa31 100644
--- a/src/extensions/surveys.tsx
+++ b/src/extensions/surveys.tsx
@@ -211,7 +211,7 @@ export class SurveyManager {
)
}
- public callSurveysAndEvaluateDisplayLogic = (forceReload: boolean = false): void => {
+ public callSurveysAndEvaluateDisplayLogic = (): void => {
this.posthog?.getActiveMatchingSurveys((surveys) => {
const nonAPISurveys = surveys.filter((survey) => survey.type !== 'api')
@@ -240,7 +240,7 @@ export class SurveyManager {
this.handlePopoverSurvey(survey)
}
})
- }, forceReload)
+ })
}
private addSurveyToFocus = (id: string): void => {
@@ -350,11 +350,11 @@ export function generateSurveys(posthog: PostHog) {
}
const surveyManager = new SurveyManager(posthog)
- surveyManager.callSurveysAndEvaluateDisplayLogic(true)
+ surveyManager.callSurveysAndEvaluateDisplayLogic()
// recalculate surveys every second to check if URL or selectors have changed
setInterval(() => {
- surveyManager.callSurveysAndEvaluateDisplayLogic(false)
+ surveyManager.callSurveysAndEvaluateDisplayLogic()
}, 1000)
return surveyManager
}
diff --git a/src/extensions/surveys/action-matcher.ts b/src/extensions/surveys/action-matcher.ts
index a6d4ceb0a..82bb125a0 100644
--- a/src/extensions/surveys/action-matcher.ts
+++ b/src/extensions/surveys/action-matcher.ts
@@ -1,5 +1,5 @@
import { PostHog } from '../../posthog-core'
-import { ActionStepStringMatching, ActionStepType, ActionType, SurveyElement } from '../../posthog-surveys-types'
+import { ActionStepStringMatching, ActionStepType, SurveyActionType, SurveyElement } from '../../posthog-surveys-types'
import { SimpleEventEmitter } from '../../utils/simple-event-emitter'
import { CaptureResult } from '../../types'
import { isUndefined } from '../../utils/type-utils'
@@ -7,7 +7,7 @@ import { window } from '../../utils/globals'
import { isUrlMatchingRegex } from '../../utils/request-utils'
export class ActionMatcher {
- private readonly actionRegistry?: Set
+ private readonly actionRegistry?: Set
private readonly instance?: PostHog
private readonly actionEvents: Set
private _debugEventEmitter = new SimpleEventEmitter()
@@ -15,7 +15,7 @@ export class ActionMatcher {
constructor(instance?: PostHog) {
this.instance = instance
this.actionEvents = new Set()
- this.actionRegistry = new Set()
+ this.actionRegistry = new Set()
}
init() {
@@ -27,7 +27,7 @@ export class ActionMatcher {
}
}
- register(actions: ActionType[]): void {
+ register(actions: SurveyActionType[]): void {
if (isUndefined(this.instance?._addCaptureHook)) {
return
}
@@ -74,7 +74,7 @@ export class ActionMatcher {
this.onAction('actionCaptured', (data) => callback(data))
}
- private checkAction(event?: CaptureResult, action?: ActionType): boolean {
+ private checkAction(event?: CaptureResult, action?: SurveyActionType): boolean {
if (action?.steps == null) {
return false
}
diff --git a/src/posthog-surveys.ts b/src/posthog-surveys.ts
index f33fe4f4a..723119a9c 100644
--- a/src/posthog-surveys.ts
+++ b/src/posthog-surveys.ts
@@ -12,7 +12,7 @@ import { SurveyEventReceiver } from './utils/survey-event-receiver'
import { assignableWindow, document, window } from './utils/globals'
import { RemoteConfig } from './types'
import { createLogger } from './utils/logger'
-import { isNullish } from './utils/type-utils'
+import { isArray, isNullish } from './utils/type-utils'
import { getSurveySeenStorageKeys } from './extensions/surveys/surveys-utils'
const logger = createLogger('[Surveys]')
@@ -59,10 +59,12 @@ function getRatingBucketForResponseValue(responseValue: number, scale: number) {
}
export class PostHogSurveys {
- private _decideServerResponse?: boolean
+ private _surveysRemoteEnabled?: boolean
public _surveyEventReceiver: SurveyEventReceiver | null
private _surveyManager: any
+ private surveys?: Survey[]
+
constructor(private readonly instance: PostHog) {
// we set this to undefined here because we need the persistence storage for this type
// but that's not initialized until loadIfEnabled is called.
@@ -70,7 +72,13 @@ export class PostHogSurveys {
}
onRemoteConfig(response: RemoteConfig) {
- this._decideServerResponse = !!response['surveys']
+ if (isArray(response['surveys'])) {
+ this.surveys = response['surveys']
+ this._surveysRemoteEnabled = this.surveys.length > 0
+ } else {
+ this._surveysRemoteEnabled = !!response['surveys']
+ }
+
this.loadIfEnabled()
}
@@ -83,7 +91,7 @@ export class PostHogSurveys {
loadIfEnabled() {
const surveysGenerator = assignableWindow?.__PosthogExtensions__?.generateSurveys
- if (!this.instance.config.disable_surveys && this._decideServerResponse && !surveysGenerator) {
+ if (!this.instance.config.disable_surveys && this._surveysRemoteEnabled && !surveysGenerator) {
if (this._surveyEventReceiver == null) {
this._surveyEventReceiver = new SurveyEventReceiver(this.instance)
}
@@ -98,6 +106,38 @@ export class PostHogSurveys {
}
}
+ reloadSurveys(callback: (surveys: Survey[]) => void) {
+ // TODO: If we are using RemoteConfig - load it from there instead of API
+ this.instance._send_request({
+ url: this.instance.requestRouter.endpointFor('api', `/api/surveys/?token=${this.instance.config.token}`),
+ method: 'GET',
+ transport: 'XHR',
+ callback: (response) => {
+ if (response.statusCode !== 200 || !response.json) {
+ return callback([])
+ }
+ const surveys = response.json.surveys || []
+
+ const eventOrActionBasedSurveys = surveys.filter(
+ (survey: Survey) =>
+ (survey.conditions?.events &&
+ survey.conditions?.events?.values &&
+ survey.conditions?.events?.values?.length > 0) ||
+ (survey.conditions?.actions &&
+ survey.conditions?.actions?.values &&
+ survey.conditions?.actions?.values?.length > 0)
+ )
+
+ if (eventOrActionBasedSurveys.length > 0) {
+ this._surveyEventReceiver?.register(eventOrActionBasedSurveys)
+ }
+
+ this.instance.persistence?.register({ [SURVEYS]: surveys })
+ return callback(surveys)
+ },
+ })
+ }
+
getSurveys(callback: SurveyCallback, forceReload = false) {
// In case we manage to load the surveys script, but config says not to load surveys
// then we shouldn't return survey data
@@ -109,40 +149,16 @@ export class PostHogSurveys {
this._surveyEventReceiver = new SurveyEventReceiver(this.instance)
}
- const existingSurveys = this.instance.get_property(SURVEYS)
+ const existingSurveys = this.surveys ?? this.instance.get_property(SURVEYS)
- if (!existingSurveys || forceReload) {
- this.instance._send_request({
- url: this.instance.requestRouter.endpointFor(
- 'api',
- `/api/surveys/?token=${this.instance.config.token}`
- ),
- method: 'GET',
- transport: 'XHR',
- callback: (response) => {
- if (response.statusCode !== 200 || !response.json) {
- return callback([])
- }
- const surveys = response.json.surveys || []
-
- const eventOrActionBasedSurveys = surveys.filter(
- (survey: Survey) =>
- (survey.conditions?.events &&
- survey.conditions?.events?.values &&
- survey.conditions?.events?.values?.length > 0) ||
- (survey.conditions?.actions &&
- survey.conditions?.actions?.values &&
- survey.conditions?.actions?.values?.length > 0)
- )
-
- if (eventOrActionBasedSurveys.length > 0) {
- this._surveyEventReceiver?.register(eventOrActionBasedSurveys)
- }
+ console.log('existingSurveys', existingSurveys, forceReload)
- this.instance.persistence?.register({ [SURVEYS]: surveys })
- return callback(surveys)
- },
- })
+ if (forceReload) {
+ throw new Error('forceReload')
+ }
+
+ if (!existingSurveys || forceReload) {
+ this.reloadSurveys(callback)
} else {
return callback(existingSurveys)
}
diff --git a/src/types.ts b/src/types.ts
index 303b501b1..8041763ef 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,6 +1,7 @@
import { PostHog } from './posthog-core'
import type { SegmentAnalytics } from './extensions/segment-integration'
import { recordOptions } from './extensions/replay/sessionrecording-utils'
+import { Survey, SurveyType } from './posthog-surveys-types'
export type Property = any
export type Properties = Record
@@ -522,7 +523,8 @@ export interface RemoteConfig {
urlBlocklist?: SessionRecordingUrlTrigger[]
eventTriggers?: string[]
}
- surveys?: boolean
+ surveys?: boolean | Survey[]
+ survey_config?: Record // TODO: Type this better
toolbarParams: ToolbarParams
editorParams?: ToolbarParams /** @deprecated, renamed to toolbarParams, still present on older API responses */
toolbarVersion: 'toolbar' /** @deprecated, moved to toolbarParams */