From 371fe3ecdb8fa8723c8b448ad40e4c885afcf331 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Wed, 23 Oct 2024 11:14:29 +0100 Subject: [PATCH 01/20] Add flag to send server hash instead of distinct id --- src/constants.ts | 6 ++++++ src/posthog-core.ts | 7 +++++-- src/types.ts | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 89cda8f3b..e434fbff1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -49,6 +49,12 @@ export const ENABLE_PERSON_PROCESSING = '$epp' export const TOOLBAR_ID = '__POSTHOG_TOOLBAR__' export const TOOLBAR_CONTAINER_CLASS = 'toolbar-global-fade-container' +/** + * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION + * sentinel value for distinct id, signals that the server should replace it with a hash + * */ +export const SENTINEL_COOKIELESS_SERVER_HASH = '$sentinel_cookieless_server_hash' + export const WEB_EXPERIMENTS = '$web_experiments' // These are properties that are reserved and will not be automatically included in events diff --git a/src/posthog-core.ts b/src/posthog-core.ts index c2bced9f5..c92724b7a 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -19,6 +19,7 @@ import { PEOPLE_DISTINCT_ID_KEY, USER_STATE, ENABLE_PERSON_PROCESSING, + SENTINEL_COOKIELESS_SERVER_HASH, } from './constants' import { SessionRecording } from './extensions/replay/sessionrecording' import { Decide } from './decide' @@ -510,8 +511,10 @@ export class PostHog { if (!this.get_distinct_id()) { // There is no need to set the distinct id // or the device id if something was already stored - // in the persitence - const uuid = this.config.get_device_id(uuidv7()) + // in the persistence + const uuid = this.config.__use_cookieless_server_hash + ? SENTINEL_COOKIELESS_SERVER_HASH + : this.config.get_device_id(uuidv7()) this.register_once( { diff --git a/src/types.ts b/src/types.ts index 303b501b1..5b6e5040d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -344,6 +344,12 @@ export interface PostHogConfig { * enables the new RemoteConfig approach to loading config instead of decide * */ __preview_remote_config?: boolean + + /** + * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION + * whether to send a sentinel distinct id value, which will be replaced on the server by a hash + * */ + __use_cookieless_server_hash?: boolean } export interface OptInOutCapturingOptions { From fe50c1b8fcbfe7096efacfb15c06ae4339a9fad3 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Wed, 23 Oct 2024 18:31:00 +0100 Subject: [PATCH 02/20] Use SENTINEL_COOKIELESS_SERVER_HASH for session ids too --- src/sessionid.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sessionid.ts b/src/sessionid.ts index b9b7c63c0..513593db6 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -1,5 +1,5 @@ import { PostHogPersistence } from './posthog-persistence' -import { SESSION_ID } from './constants' +import { SENTINEL_COOKIELESS_SERVER_HASH, SESSION_ID } from './constants' import { sessionStore } from './storage' import { PostHogConfig, SessionIdChangedCallback } from './types' import { uuid7ToTimestampMs, uuidv7 } from './uuidv7' @@ -230,7 +230,11 @@ export class SessionIdManager { const noSessionId = !sessionId const activityTimeout = !readOnly && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs if (noSessionId || activityTimeout || sessionPastMaximumLength) { - sessionId = this._sessionIdGenerator() + if (this.config.__use_cookieless_server_hash) { + sessionId = SENTINEL_COOKIELESS_SERVER_HASH + } else { + sessionId = this._sessionIdGenerator() + } windowId = this._windowIdGenerator() logger.info('new session ID generated', { sessionId, From e0d4a491e8a066e14185f37b75c471b83160c759 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 5 Nov 2024 17:01:26 +0100 Subject: [PATCH 03/20] WIP --- playground/nextjs/package.json | 2 +- playground/nextjs/pnpm-lock.yaml | 14 ++++++++++---- playground/nextjs/src/posthog.ts | 1 + src/posthog-core.ts | 17 ++++++++++++----- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/playground/nextjs/package.json b/playground/nextjs/package.json index 9f2d195b3..c5c0641e8 100644 --- a/playground/nextjs/package.json +++ b/playground/nextjs/package.json @@ -22,7 +22,7 @@ "eslint-config-next": "13.1.6", "hls.js": "^1.5.15", "next": "13.5.6", - "posthog-js": "1.166.0", + "posthog-js": "1.178.0", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "4.9.5" diff --git a/playground/nextjs/pnpm-lock.yaml b/playground/nextjs/pnpm-lock.yaml index afaaeebc1..99d7065f4 100644 --- a/playground/nextjs/pnpm-lock.yaml +++ b/playground/nextjs/pnpm-lock.yaml @@ -33,8 +33,8 @@ dependencies: specifier: 13.5.6 version: 13.5.6(react-dom@18.2.0)(react@18.2.0) posthog-js: - specifier: 1.166.0 - version: 1.166.0 + specifier: 1.178.0 + version: 1.178.0 react: specifier: 18.2.0 version: 18.2.0 @@ -706,6 +706,11 @@ packages: engines: {node: '>= 0.6'} dev: false + /core-js@3.39.0: + resolution: {integrity: sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==} + requiresBuild: true + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2312,9 +2317,10 @@ packages: source-map-js: 1.2.1 dev: true - /posthog-js@1.166.0: - resolution: {integrity: sha512-om7rhbgP3OzJDJ3wdrp6cuKVWC+7iiFeVv+g8uaZPLI6zvzuaNdq4a3s0ltnfBpROlZrWw4oJknoVwj7I3hVTQ==} + /posthog-js@1.178.0: + resolution: {integrity: sha512-ILD4flNh72d5dycc4ZouKORlaVr+pDzl5TlZr1JgP0NBAoduHjhE7XZYwk7zdYkry7u0qAIpfv2306zJCW2vGg==} dependencies: + core-js: 3.39.0 fflate: 0.4.8 preact: 10.24.1 web-vitals: 4.2.3 diff --git a/playground/nextjs/src/posthog.ts b/playground/nextjs/src/posthog.ts index 89de3feb1..7ab8c1543 100644 --- a/playground/nextjs/src/posthog.ts +++ b/playground/nextjs/src/posthog.ts @@ -65,6 +65,7 @@ if (typeof window !== 'undefined') { opt_in_site_apps: true, __preview_remote_config: true, ...configForConsent(), + __use_cookieless_server_hash: true, }) // Help with debugging ;(window as any).posthog = posthog diff --git a/src/posthog-core.ts b/src/posthog-core.ts index c92724b7a..d3d9fce7b 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -478,7 +478,7 @@ export class PostHog { // isUndefined doesn't provide typehint here so wouldn't reduce bundle as we'd need to assign // eslint-disable-next-line posthog-js/no-direct-undefined-check if (config.bootstrap?.distinctID !== undefined) { - const uuid = this.config.get_device_id(uuidv7()) + const uuid = this._create_device_id() const deviceID = config.bootstrap?.isIdentifiedID ? uuid : config.bootstrap.distinctID this.persistence.set_property(USER_STATE, config.bootstrap?.isIdentifiedID ? 'identified' : 'anonymous') this.register({ @@ -512,9 +512,7 @@ export class PostHog { // There is no need to set the distinct id // or the device id if something was already stored // in the persistence - const uuid = this.config.__use_cookieless_server_hash - ? SENTINEL_COOKIELESS_SERVER_HASH - : this.config.get_device_id(uuidv7()) + const uuid = this._create_device_id() this.register_once( { @@ -1536,7 +1534,9 @@ export class PostHog { this.surveys?.reset() this.persistence?.set_property(USER_STATE, 'anonymous') this.sessionManager?.resetSessionId() - const uuid = this.config.get_device_id(uuidv7()) + const uuid = this.config.__use_cookieless_server_hash + ? SENTINEL_COOKIELESS_SERVER_HASH + : this.config.get_device_id(uuidv7()) this.register_once( { distinct_id: uuid, @@ -2053,6 +2053,13 @@ export class PostHog { } } + private _create_device_id(): string { + if (this.config.__use_cookieless_server_hash) { + return SENTINEL_COOKIELESS_SERVER_HASH + } + return this.config.get_device_id(uuidv7()) + } + /** * Opt the user in to data capturing and cookies/localstorage for this PostHog instance * If the config.opt_out_persistence_by_default is set to false, the SDK persistence will be enabled. From 0460c6efcd90893231ce6c0de6d3c01c467cff81 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 5 Dec 2024 15:33:07 +0000 Subject: [PATCH 04/20] Driveby --- playground/nextjs/pages/_app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/nextjs/pages/_app.tsx b/playground/nextjs/pages/_app.tsx index 3d74c2fe6..8c16f2c3b 100644 --- a/playground/nextjs/pages/_app.tsx +++ b/playground/nextjs/pages/_app.tsx @@ -42,7 +42,7 @@ export default function App({ Component, pageProps }: AppProps) { {/* CSP - useful for testing our documented recommendations. NOTE: Unsafe is only needed for nextjs pre-loading */} Date: Thu, 5 Dec 2024 15:33:26 +0000 Subject: [PATCH 05/20] Package version --- playground/nextjs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/nextjs/package.json b/playground/nextjs/package.json index c5c0641e8..ad561b235 100644 --- a/playground/nextjs/package.json +++ b/playground/nextjs/package.json @@ -22,7 +22,7 @@ "eslint-config-next": "13.1.6", "hls.js": "^1.5.15", "next": "13.5.6", - "posthog-js": "1.178.0", + "posthog-js": "1.194.4", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "4.9.5" From b58f1c1aee709bbfa25cd8e858b410ba90b5fee2 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 11:42:59 +0000 Subject: [PATCH 06/20] Rename the sentinel const --- src/constants.ts | 4 ++-- src/posthog-core.ts | 6 +++--- src/sessionid.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index e434fbff1..cbc360d23 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -51,9 +51,9 @@ export const TOOLBAR_CONTAINER_CLASS = 'toolbar-global-fade-container' /** * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION - * sentinel value for distinct id, signals that the server should replace it with a hash + * Sentinel value for distinct id, device id, session id. Signals that the server should generate the value * */ -export const SENTINEL_COOKIELESS_SERVER_HASH = '$sentinel_cookieless_server_hash' +export const COOKIELESS_SENTINEL_VALUE = '$posthog_cklsh' export const WEB_EXPERIMENTS = '$web_experiments' diff --git a/src/posthog-core.ts b/src/posthog-core.ts index d3d9fce7b..5a6e72406 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -19,7 +19,7 @@ import { PEOPLE_DISTINCT_ID_KEY, USER_STATE, ENABLE_PERSON_PROCESSING, - SENTINEL_COOKIELESS_SERVER_HASH, + COOKIELESS_SENTINEL_VALUE, } from './constants' import { SessionRecording } from './extensions/replay/sessionrecording' import { Decide } from './decide' @@ -1535,7 +1535,7 @@ export class PostHog { this.persistence?.set_property(USER_STATE, 'anonymous') this.sessionManager?.resetSessionId() const uuid = this.config.__use_cookieless_server_hash - ? SENTINEL_COOKIELESS_SERVER_HASH + ? COOKIELESS_SENTINEL_VALUE : this.config.get_device_id(uuidv7()) this.register_once( { @@ -2055,7 +2055,7 @@ export class PostHog { private _create_device_id(): string { if (this.config.__use_cookieless_server_hash) { - return SENTINEL_COOKIELESS_SERVER_HASH + return COOKIELESS_SENTINEL_VALUE } return this.config.get_device_id(uuidv7()) } diff --git a/src/sessionid.ts b/src/sessionid.ts index 513593db6..83d906c58 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -1,5 +1,5 @@ import { PostHogPersistence } from './posthog-persistence' -import { SENTINEL_COOKIELESS_SERVER_HASH, SESSION_ID } from './constants' +import { COOKIELESS_SENTINEL_VALUE, SESSION_ID } from './constants' import { sessionStore } from './storage' import { PostHogConfig, SessionIdChangedCallback } from './types' import { uuid7ToTimestampMs, uuidv7 } from './uuidv7' @@ -231,7 +231,7 @@ export class SessionIdManager { const activityTimeout = !readOnly && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs if (noSessionId || activityTimeout || sessionPastMaximumLength) { if (this.config.__use_cookieless_server_hash) { - sessionId = SENTINEL_COOKIELESS_SERVER_HASH + sessionId = COOKIELESS_SENTINEL_VALUE } else { sessionId = this._sessionIdGenerator() } From b1045fb2e0f5f5b5109eaeb71c9a3f56e01abd44 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 11:46:48 +0000 Subject: [PATCH 07/20] Comments and naming --- src/posthog-core.ts | 4 ++-- src/sessionid.ts | 2 +- src/types.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 5a6e72406..28cec800c 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -1534,7 +1534,7 @@ export class PostHog { this.surveys?.reset() this.persistence?.set_property(USER_STATE, 'anonymous') this.sessionManager?.resetSessionId() - const uuid = this.config.__use_cookieless_server_hash + const uuid = this.config.__preview_experimental_cookieless_mode ? COOKIELESS_SENTINEL_VALUE : this.config.get_device_id(uuidv7()) this.register_once( @@ -2054,7 +2054,7 @@ export class PostHog { } private _create_device_id(): string { - if (this.config.__use_cookieless_server_hash) { + if (this.config.__preview_experimental_cookieless_mode) { return COOKIELESS_SENTINEL_VALUE } return this.config.get_device_id(uuidv7()) diff --git a/src/sessionid.ts b/src/sessionid.ts index 83d906c58..4519fe4c3 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -230,7 +230,7 @@ export class SessionIdManager { const noSessionId = !sessionId const activityTimeout = !readOnly && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs if (noSessionId || activityTimeout || sessionPastMaximumLength) { - if (this.config.__use_cookieless_server_hash) { + if (this.config.__preview_experimental_cookieless_mode) { sessionId = COOKIELESS_SENTINEL_VALUE } else { sessionId = this._sessionIdGenerator() diff --git a/src/types.ts b/src/types.ts index 5b6e5040d..02d2d709b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -347,9 +347,9 @@ export interface PostHogConfig { /** * PREVIEW - MAY CHANGE WITHOUT WARNING - DO NOT USE IN PRODUCTION - * whether to send a sentinel distinct id value, which will be replaced on the server by a hash + * whether to send a sentinel value for distinct id, device id, and session id, which will be replaced server-side by a cookieless hash * */ - __use_cookieless_server_hash?: boolean + __preview_experimental_cookieless_mode?: boolean } export interface OptInOutCapturingOptions { From a55d8b255c66ffc997daa7d9b78e2202e7f51d78 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 12:02:46 +0000 Subject: [PATCH 08/20] Send null for session id and window id --- src/sessionid.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/sessionid.ts b/src/sessionid.ts index 4519fe4c3..b2e31d759 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -1,5 +1,5 @@ import { PostHogPersistence } from './posthog-persistence' -import { COOKIELESS_SENTINEL_VALUE, SESSION_ID } from './constants' +import { SESSION_ID } from './constants' import { sessionStore } from './storage' import { PostHogConfig, SessionIdChangedCallback } from './types' import { uuid7ToTimestampMs, uuidv7 } from './uuidv7' @@ -215,6 +215,14 @@ export class SessionIdManager { * @param {Number} timestamp (optional) Defaults to the current time. The timestamp to be stored with the sessionId (used when determining if a new sessionId should be generated) */ checkAndGetSessionAndWindowId(readOnly = false, _timestamp: number | null = null) { + if (this.config.__preview_experimental_cookieless_mode) { + return { + sessionId: undefined, + windowId: undefined, + sessionStartTimestamp: undefined, + lastActivityTimestamp: undefined, + } + } const timestamp = _timestamp || new Date().getTime() // eslint-disable-next-line prefer-const @@ -230,11 +238,7 @@ export class SessionIdManager { const noSessionId = !sessionId const activityTimeout = !readOnly && Math.abs(timestamp - lastTimestamp) > this.sessionTimeoutMs if (noSessionId || activityTimeout || sessionPastMaximumLength) { - if (this.config.__preview_experimental_cookieless_mode) { - sessionId = COOKIELESS_SENTINEL_VALUE - } else { - sessionId = this._sessionIdGenerator() - } + sessionId = this._sessionIdGenerator() windowId = this._windowIdGenerator() logger.info('new session ID generated', { sessionId, From ac7cd3999d37402853ede18278d1d49e0658e999 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 12:23:21 +0000 Subject: [PATCH 09/20] typescript --- src/entrypoints/tracing-headers.ts | 8 ++++++-- src/extensions/replay/sessionrecording.ts | 11 +++++++---- src/sessionid.ts | 8 ++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/entrypoints/tracing-headers.ts b/src/entrypoints/tracing-headers.ts index 06abc4e01..a4148a45f 100644 --- a/src/entrypoints/tracing-headers.ts +++ b/src/entrypoints/tracing-headers.ts @@ -4,8 +4,12 @@ import { assignableWindow, window } from '../utils/globals' const addTracingHeaders = (sessionManager: SessionIdManager, req: Request) => { const { sessionId, windowId } = sessionManager.checkAndGetSessionAndWindowId(true) - req.headers.set('X-POSTHOG-SESSION-ID', sessionId) - req.headers.set('X-POSTHOG-WINDOW-ID', windowId) + if (sessionId) { + req.headers.set('X-POSTHOG-SESSION-ID', sessionId) + } + if (windowId) { + req.headers.set('X-POSTHOG-WINDOW-ID', windowId) + } } const patchFetch = (sessionManager: SessionIdManager): (() => void) => { diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index 030501aab..0200c6832 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -97,8 +97,8 @@ type SessionRecordingStatus = 'disabled' | 'sampled' | 'active' | 'buffering' | export interface SnapshotBuffer { size: number data: any[] - sessionId: string - windowId: string + sessionId: string | null + windowId: string | null } interface QueuedRRWebEvent { @@ -252,8 +252,8 @@ export class SessionRecording { private _linkedFlagSeen: boolean = false private _lastActivityTimestamp: number = Date.now() - private windowId: string - private sessionId: string + private windowId: string | null + private sessionId: string | null private _linkedFlag: string | FlagVariant | null = null private _fullSnapshotTimer?: ReturnType @@ -315,6 +315,9 @@ export class SessionRecording { private get sessionDuration(): number | null { const mostRecentSnapshot = this.buffer?.data[this.buffer?.data.length - 1] const { sessionStartTimestamp } = this.sessionManager.checkAndGetSessionAndWindowId(true) + if (sessionStartTimestamp == null) { + return null + } return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null } diff --git a/src/sessionid.ts b/src/sessionid.ts index b2e31d759..0ef93b2b8 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -217,10 +217,10 @@ export class SessionIdManager { checkAndGetSessionAndWindowId(readOnly = false, _timestamp: number | null = null) { if (this.config.__preview_experimental_cookieless_mode) { return { - sessionId: undefined, - windowId: undefined, - sessionStartTimestamp: undefined, - lastActivityTimestamp: undefined, + sessionId: null, + windowId: null, + sessionStartTimestamp: null, + lastActivityTimestamp: null, } } const timestamp = _timestamp || new Date().getTime() From b3c862f6b9b79c0ae17360b81c72925e9161cf5a Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 13:35:29 +0000 Subject: [PATCH 10/20] bump posthog in next playground --- playground/nextjs/package.json | 2 +- playground/nextjs/pnpm-lock.yaml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playground/nextjs/package.json b/playground/nextjs/package.json index ad561b235..f40a3ad69 100644 --- a/playground/nextjs/package.json +++ b/playground/nextjs/package.json @@ -22,7 +22,7 @@ "eslint-config-next": "13.1.6", "hls.js": "^1.5.15", "next": "13.5.6", - "posthog-js": "1.194.4", + "posthog-js": "1.194.6", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "4.9.5" diff --git a/playground/nextjs/pnpm-lock.yaml b/playground/nextjs/pnpm-lock.yaml index 99d7065f4..dd947ffcf 100644 --- a/playground/nextjs/pnpm-lock.yaml +++ b/playground/nextjs/pnpm-lock.yaml @@ -33,8 +33,8 @@ dependencies: specifier: 13.5.6 version: 13.5.6(react-dom@18.2.0)(react@18.2.0) posthog-js: - specifier: 1.178.0 - version: 1.178.0 + specifier: 1.194.6 + version: 1.194.6 react: specifier: 18.2.0 version: 18.2.0 @@ -2317,8 +2317,8 @@ packages: source-map-js: 1.2.1 dev: true - /posthog-js@1.178.0: - resolution: {integrity: sha512-ILD4flNh72d5dycc4ZouKORlaVr+pDzl5TlZr1JgP0NBAoduHjhE7XZYwk7zdYkry7u0qAIpfv2306zJCW2vGg==} + /posthog-js@1.194.6: + resolution: {integrity: sha512-5g5n7FjWLha/QWVTeWeMErGff21v4/V3wYCZ2z8vAbHaCyHkaDBEbuM756jMFBQMsq3HJcDX9mlxi2HhAHxq2A==} dependencies: core-js: 3.39.0 fflate: 0.4.8 From 71d5093637845478937ccdd8d2a6c5dec29efd2f Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Tue, 10 Dec 2024 16:44:42 +0000 Subject: [PATCH 11/20] Add a test --- src/__tests__/cookieless.test.ts | 72 ++++++++++++++++++++++++++++++++ src/posthog-core.ts | 17 ++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 src/__tests__/cookieless.test.ts diff --git a/src/__tests__/cookieless.test.ts b/src/__tests__/cookieless.test.ts new file mode 100644 index 000000000..9ad89ccd7 --- /dev/null +++ b/src/__tests__/cookieless.test.ts @@ -0,0 +1,72 @@ +import { defaultPostHog } from './helpers/posthog-instance' +import type { PostHogConfig } from '../types' +import { uuidv7 } from '../uuidv7' + +describe('cookieless', () => { + const eventName = 'custom_event' + const eventProperties = { + event: 'prop', + } + const identifiedDistinctId = 'user-1' + const setup = (config: Partial = {}, token: string = uuidv7()) => { + const beforeSendMock = jest.fn().mockImplementation((e) => e) + const posthog = defaultPostHog().init(token, { ...config, before_send: beforeSendMock }, token)! + posthog.debug() + return { posthog, beforeSendMock } + } + + it('should send events with the sentinel distinct id', () => { + const { posthog, beforeSendMock } = setup({ + persistence: 'memory', + __preview_experimental_cookieless_mode: true, + }) + + posthog.capture(eventName, eventProperties) + expect(beforeSendMock).toBeCalledTimes(1) + let event = beforeSendMock.mock.calls[0][0] + expect(event.properties.distinct_id).toBe('$posthog_cklsh') + expect(event.properties.$anon_distinct_id).toBe(undefined) + expect(event.properties.$device_id).toBe(null) + expect(event.properties.$session_id).toBe(null) + expect(event.properties.$window_id).toBe(null) + expect(event.properties.$cookieless).toEqual(true) + expect(document.cookie).toBe('') + + // simulate user giving cookie consent + posthog.set_config({ persistence: 'localStorage+cookie' }) + + // send an event after consent + posthog.capture(eventName, eventProperties) + expect(beforeSendMock).toBeCalledTimes(2) + event = beforeSendMock.mock.calls[1][0] + expect(event.properties.distinct_id).toBe('$posthog_cklsh') + expect(event.properties.$anon_distinct_id).toBe(undefined) + expect(event.properties.$device_id).toBe(null) + expect(event.properties.$session_id).toBe(null) + expect(event.properties.$window_id).toBe(null) + expect(event.properties.$cookieless).toEqual(true) + expect(document.cookie).not.toBe('') + + // a user identifying + posthog.identify(identifiedDistinctId) + expect(beforeSendMock).toBeCalledTimes(3) + event = beforeSendMock.mock.calls[2][0] + expect(event.properties.distinct_id).toBe(identifiedDistinctId) + expect(event.properties.$anon_distinct_id).toBe('$posthog_cklsh') + expect(event.properties.$device_id).toBe(null) + expect(event.properties.$session_id).toBe(null) + expect(event.properties.$window_id).toBe(null) + expect(event.properties.$cookieless).toEqual(true) + + // an event after identifying + posthog.capture(eventName, eventProperties) + expect(beforeSendMock).toBeCalledTimes(4) + event = beforeSendMock.mock.calls[3][0] + expect(event.properties.distinct_id).toBe(identifiedDistinctId) + expect(event.properties.$anon_distinct_id).toBe(undefined) + expect(event.properties.$device_id).toBe(null) + expect(event.properties.$session_id).toBe(null) + expect(event.properties.$window_id).toBe(null) + expect(event.properties.$cookieless).toEqual(true) + }) +}) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 28cec800c..0932048cf 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -508,7 +508,15 @@ export class PostHog { this.featureFlags.receivedFeatureFlags({ featureFlags: activeFlags, featureFlagPayloads }) } - if (!this.get_distinct_id()) { + if (this.config.__preview_experimental_cookieless_mode) { + this.register_once( + { + distinct_id: COOKIELESS_SENTINEL_VALUE, + $device_id: null, + }, + '' + ) + } else if (!this.get_distinct_id()) { // There is no need to set the distinct id // or the device id if something was already stored // in the persistence @@ -916,6 +924,10 @@ export class PostHog { let properties = { ...event_properties } properties['token'] = this.config.token + if (this.config.__preview_experimental_cookieless_mode) { + properties['$cookieless'] = true + } + if (event_name === '$snapshot') { const persistenceProps = { ...this.persistence.properties(), ...this.sessionPersistence.properties() } properties['distinct_id'] = persistenceProps.distinct_id @@ -2054,9 +2066,6 @@ export class PostHog { } private _create_device_id(): string { - if (this.config.__preview_experimental_cookieless_mode) { - return COOKIELESS_SENTINEL_VALUE - } return this.config.get_device_id(uuidv7()) } From 7a2f555f75cd56c8ad4b7d7d58bd12ded1add42a Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 12 Dec 2024 10:17:22 +0000 Subject: [PATCH 12/20] Revert get device id changes --- src/posthog-core.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 0932048cf..27c9e2f53 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -478,7 +478,7 @@ export class PostHog { // isUndefined doesn't provide typehint here so wouldn't reduce bundle as we'd need to assign // eslint-disable-next-line posthog-js/no-direct-undefined-check if (config.bootstrap?.distinctID !== undefined) { - const uuid = this._create_device_id() + const uuid = this.config.get_device_id(uuidv7()) const deviceID = config.bootstrap?.isIdentifiedID ? uuid : config.bootstrap.distinctID this.persistence.set_property(USER_STATE, config.bootstrap?.isIdentifiedID ? 'identified' : 'anonymous') this.register({ @@ -520,7 +520,7 @@ export class PostHog { // There is no need to set the distinct id // or the device id if something was already stored // in the persistence - const uuid = this._create_device_id() + const uuid = this.config.get_device_id(uuidv7()) this.register_once( { @@ -2065,10 +2065,6 @@ export class PostHog { } } - private _create_device_id(): string { - return this.config.get_device_id(uuidv7()) - } - /** * Opt the user in to data capturing and cookies/localstorage for this PostHog instance * If the config.opt_out_persistence_by_default is set to false, the SDK persistence will be enabled. From 5e1facc2b75eed60b13f3c7c06f53b8cea3e7c21 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 12 Dec 2024 10:21:01 +0000 Subject: [PATCH 13/20] Add a comment --- src/posthog-core.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 27c9e2f53..f51ae83b8 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -925,7 +925,10 @@ export class PostHog { properties['token'] = this.config.token if (this.config.__preview_experimental_cookieless_mode) { - properties['$cookieless'] = true + // Set a flag to tell the plugin server to use cookieless server hash mode + // on naming: $cklsh = cookieless server hash + // I didn't call it $cookieless, as it's possible to use cookies in this mode (after consent is given) + properties['$cklsh'] = true } if (event_name === '$snapshot') { From dcd2d7f5be3778999dda488e3a2f94ca7cabdd49 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 12 Dec 2024 10:28:17 +0000 Subject: [PATCH 14/20] Remove cklsh from next playground --- playground/nextjs/src/posthog.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/playground/nextjs/src/posthog.ts b/playground/nextjs/src/posthog.ts index 7ab8c1543..89de3feb1 100644 --- a/playground/nextjs/src/posthog.ts +++ b/playground/nextjs/src/posthog.ts @@ -65,7 +65,6 @@ if (typeof window !== 'undefined') { opt_in_site_apps: true, __preview_remote_config: true, ...configForConsent(), - __use_cookieless_server_hash: true, }) // Help with debugging ;(window as any).posthog = posthog From f9b12957016790f7cb0fd187537b3c6336b0c5fc Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Thu, 12 Dec 2024 10:35:24 +0000 Subject: [PATCH 15/20] Handle reset --- src/__tests__/cookieless.test.ts | 24 ++++++++++++++++++++---- src/posthog-core.ts | 28 ++++++++++++++++++---------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/__tests__/cookieless.test.ts b/src/__tests__/cookieless.test.ts index 9ad89ccd7..95f056620 100644 --- a/src/__tests__/cookieless.test.ts +++ b/src/__tests__/cookieless.test.ts @@ -29,7 +29,7 @@ describe('cookieless', () => { expect(event.properties.$device_id).toBe(null) expect(event.properties.$session_id).toBe(null) expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cookieless).toEqual(true) + expect(event.properties.$cklsh).toEqual(true) expect(document.cookie).toBe('') // simulate user giving cookie consent @@ -44,7 +44,7 @@ describe('cookieless', () => { expect(event.properties.$device_id).toBe(null) expect(event.properties.$session_id).toBe(null) expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cookieless).toEqual(true) + expect(event.properties.$cklsh).toEqual(true) expect(document.cookie).not.toBe('') // a user identifying @@ -56,7 +56,7 @@ describe('cookieless', () => { expect(event.properties.$device_id).toBe(null) expect(event.properties.$session_id).toBe(null) expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cookieless).toEqual(true) + expect(event.properties.$cklsh).toEqual(true) // an event after identifying posthog.capture(eventName, eventProperties) @@ -67,6 +67,22 @@ describe('cookieless', () => { expect(event.properties.$device_id).toBe(null) expect(event.properties.$session_id).toBe(null) expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cookieless).toEqual(true) + expect(event.properties.$cklsh).toEqual(true) + + // reset + posthog.reset() + posthog.set_config({ persistence: 'memory' }) + + // an event after reset + posthog.capture(eventName, eventProperties) + expect(beforeSendMock).toBeCalledTimes(5) + event = beforeSendMock.mock.calls[4][0] + expect(event.properties.distinct_id).toBe('$posthog_cklsh') + expect(event.properties.$anon_distinct_id).toBe(undefined) + expect(event.properties.$device_id).toBe(null) + expect(event.properties.$session_id).toBe(null) + expect(event.properties.$window_id).toBe(null) + expect(event.properties.$cklsh).toEqual(true) + expect(document.cookie).toBe('') }) }) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index f51ae83b8..3bcb564b5 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -1549,16 +1549,24 @@ export class PostHog { this.surveys?.reset() this.persistence?.set_property(USER_STATE, 'anonymous') this.sessionManager?.resetSessionId() - const uuid = this.config.__preview_experimental_cookieless_mode - ? COOKIELESS_SENTINEL_VALUE - : this.config.get_device_id(uuidv7()) - this.register_once( - { - distinct_id: uuid, - $device_id: reset_device_id ? uuid : device_id, - }, - '' - ) + if (this.config.__preview_experimental_cookieless_mode) { + this.register_once( + { + distinct_id: COOKIELESS_SENTINEL_VALUE, + $device_id: null, + }, + '' + ) + } else { + const uuid = this.config.get_device_id(uuidv7()) + this.register_once( + { + distinct_id: uuid, + $device_id: reset_device_id ? uuid : device_id, + }, + '' + ) + } } /** From 0afe187b5a6c87ad7a241df11ed2c437e2e4d550 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 13 Dec 2024 12:41:32 +0000 Subject: [PATCH 16/20] Don't enable session id manager or replay when in cookieless mode --- src/__tests__/cookieless.test.ts | 30 +++++++++++------------ src/constants.ts | 1 + src/extensions/replay/sessionrecording.ts | 11 ++++++--- src/posthog-core.ts | 19 ++++++++------ src/sessionid.ts | 12 ++++----- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/__tests__/cookieless.test.ts b/src/__tests__/cookieless.test.ts index 95f056620..da1f55ba2 100644 --- a/src/__tests__/cookieless.test.ts +++ b/src/__tests__/cookieless.test.ts @@ -27,9 +27,9 @@ describe('cookieless', () => { expect(event.properties.distinct_id).toBe('$posthog_cklsh') expect(event.properties.$anon_distinct_id).toBe(undefined) expect(event.properties.$device_id).toBe(null) - expect(event.properties.$session_id).toBe(null) - expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cklsh).toEqual(true) + expect(event.properties.$session_id).toBe(undefined) + expect(event.properties.$window_id).toBe(undefined) + expect(event.properties.$cklsh_mode).toEqual(true) expect(document.cookie).toBe('') // simulate user giving cookie consent @@ -42,9 +42,9 @@ describe('cookieless', () => { expect(event.properties.distinct_id).toBe('$posthog_cklsh') expect(event.properties.$anon_distinct_id).toBe(undefined) expect(event.properties.$device_id).toBe(null) - expect(event.properties.$session_id).toBe(null) - expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cklsh).toEqual(true) + expect(event.properties.$session_id).toBe(undefined) + expect(event.properties.$window_id).toBe(undefined) + expect(event.properties.$cklsh_mode).toEqual(true) expect(document.cookie).not.toBe('') // a user identifying @@ -54,9 +54,9 @@ describe('cookieless', () => { expect(event.properties.distinct_id).toBe(identifiedDistinctId) expect(event.properties.$anon_distinct_id).toBe('$posthog_cklsh') expect(event.properties.$device_id).toBe(null) - expect(event.properties.$session_id).toBe(null) - expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cklsh).toEqual(true) + expect(event.properties.$session_id).toBe(undefined) + expect(event.properties.$window_id).toBe(undefined) + expect(event.properties.$cklsh_mode).toEqual(true) // an event after identifying posthog.capture(eventName, eventProperties) @@ -65,9 +65,9 @@ describe('cookieless', () => { expect(event.properties.distinct_id).toBe(identifiedDistinctId) expect(event.properties.$anon_distinct_id).toBe(undefined) expect(event.properties.$device_id).toBe(null) - expect(event.properties.$session_id).toBe(null) - expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cklsh).toEqual(true) + expect(event.properties.$session_id).toBe(undefined) + expect(event.properties.$window_id).toBe(undefined) + expect(event.properties.$cklsh_mode).toEqual(true) // reset posthog.reset() @@ -80,9 +80,9 @@ describe('cookieless', () => { expect(event.properties.distinct_id).toBe('$posthog_cklsh') expect(event.properties.$anon_distinct_id).toBe(undefined) expect(event.properties.$device_id).toBe(null) - expect(event.properties.$session_id).toBe(null) - expect(event.properties.$window_id).toBe(null) - expect(event.properties.$cklsh).toEqual(true) + expect(event.properties.$session_id).toBe(undefined) + expect(event.properties.$window_id).toBe(undefined) + expect(event.properties.$cklsh_mode).toEqual(true) expect(document.cookie).toBe('') }) }) diff --git a/src/constants.ts b/src/constants.ts index cbc360d23..34b7a8bad 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -54,6 +54,7 @@ export const TOOLBAR_CONTAINER_CLASS = 'toolbar-global-fade-container' * Sentinel value for distinct id, device id, session id. Signals that the server should generate the value * */ export const COOKIELESS_SENTINEL_VALUE = '$posthog_cklsh' +export const COOKIELESS_MODE_FLAG_PROPERTY = '$cklsh_mode' export const WEB_EXPERIMENTS = '$web_experiments' diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index 0200c6832..a94350534 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -97,8 +97,8 @@ type SessionRecordingStatus = 'disabled' | 'sampled' | 'active' | 'buffering' | export interface SnapshotBuffer { size: number data: any[] - sessionId: string | null - windowId: string | null + sessionId: string + windowId: string } interface QueuedRRWebEvent { @@ -252,8 +252,8 @@ export class SessionRecording { private _linkedFlagSeen: boolean = false private _lastActivityTimestamp: number = Date.now() - private windowId: string | null - private sessionId: string | null + private windowId: string + private sessionId: string private _linkedFlag: string | FlagVariant | null = null private _fullSnapshotTimer?: ReturnType @@ -452,6 +452,9 @@ export class SessionRecording { logger.error('started without valid sessionManager') throw new Error(LOGGER_PREFIX + ' started without valid sessionManager. This is a bug.') } + if (this.instance.config.__preview_experimental_cookieless_mode) { + throw new Error(LOGGER_PREFIX + ' cannot be used with __preview_experimental_cookieless_mode.') + } // we know there's a sessionManager, so don't need to start without a session id const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId() diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 3bcb564b5..84e42334d 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -20,6 +20,7 @@ import { USER_STATE, ENABLE_PERSON_PROCESSING, COOKIELESS_SENTINEL_VALUE, + COOKIELESS_MODE_FLAG_PROPERTY, } from './constants' import { SessionRecording } from './extensions/replay/sessionrecording' import { Decide } from './decide' @@ -430,16 +431,20 @@ export class PostHog { this._retryQueue = new RetryQueue(this) this.__request_queue = [] - this.sessionManager = new SessionIdManager(this) - this.sessionPropsManager = new SessionPropsManager(this.sessionManager, this.persistence) + if (!this.config.__preview_experimental_cookieless_mode) { + this.sessionManager = new SessionIdManager(this) + this.sessionPropsManager = new SessionPropsManager(this.sessionManager, this.persistence) + } new TracingHeaders(this).startIfEnabledOrStop() this.siteApps = new SiteApps(this) this.siteApps?.init() - this.sessionRecording = new SessionRecording(this) - this.sessionRecording.startIfEnabledOrStop() + if (!this.config.__preview_experimental_cookieless_mode) { + this.sessionRecording = new SessionRecording(this) + this.sessionRecording.startIfEnabledOrStop() + } if (!this.config.disable_scroll_properties) { this.scrollManager.startMeasuringScrollPosition() @@ -926,9 +931,7 @@ export class PostHog { if (this.config.__preview_experimental_cookieless_mode) { // Set a flag to tell the plugin server to use cookieless server hash mode - // on naming: $cklsh = cookieless server hash - // I didn't call it $cookieless, as it's possible to use cookies in this mode (after consent is given) - properties['$cklsh'] = true + properties[COOKIELESS_MODE_FLAG_PROPERTY] = true } if (event_name === '$snapshot') { @@ -946,7 +949,7 @@ export class PostHog { const infoProperties = Info.properties() - if (this.sessionManager) { + if (this.sessionManager && !this.config.__preview_experimental_cookieless_mode) { const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId() properties['$session_id'] = sessionId properties['$window_id'] = windowId diff --git a/src/sessionid.ts b/src/sessionid.ts index 0ef93b2b8..bab3e88d5 100644 --- a/src/sessionid.ts +++ b/src/sessionid.ts @@ -37,6 +37,9 @@ export class SessionIdManager { if (!instance.persistence) { throw new Error('SessionIdManager requires a PostHogPersistence instance') } + if (instance.config.__preview_experimental_cookieless_mode) { + throw new Error('SessionIdManager cannot be used with __preview_experimental_cookieless_mode') + } this.config = instance.config this.persistence = instance.persistence @@ -216,12 +219,9 @@ export class SessionIdManager { */ checkAndGetSessionAndWindowId(readOnly = false, _timestamp: number | null = null) { if (this.config.__preview_experimental_cookieless_mode) { - return { - sessionId: null, - windowId: null, - sessionStartTimestamp: null, - lastActivityTimestamp: null, - } + throw new Error( + 'checkAndGetSessionAndWindowId should not be called in __preview_experimental_cookieless_mode' + ) } const timestamp = _timestamp || new Date().getTime() From 7b7cc825756682a6b466826f020ecdef452a7f7e Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 13 Dec 2024 12:55:00 +0000 Subject: [PATCH 17/20] Make tracing headers support optional SessionIdManager --- src/entrypoints/tracing-headers.ts | 12 +++++------- src/extensions/tracing-headers.ts | 4 ++-- src/utils/globals.ts | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/entrypoints/tracing-headers.ts b/src/entrypoints/tracing-headers.ts index a4148a45f..18acbe3a0 100644 --- a/src/entrypoints/tracing-headers.ts +++ b/src/entrypoints/tracing-headers.ts @@ -2,17 +2,15 @@ import { SessionIdManager } from '../sessionid' import { patch } from '../extensions/replay/rrweb-plugins/patch' import { assignableWindow, window } from '../utils/globals' -const addTracingHeaders = (sessionManager: SessionIdManager, req: Request) => { - const { sessionId, windowId } = sessionManager.checkAndGetSessionAndWindowId(true) - if (sessionId) { +const addTracingHeaders = (sessionManager: SessionIdManager | undefined, req: Request) => { + if (sessionManager) { + const { sessionId, windowId } = sessionManager.checkAndGetSessionAndWindowId(true) req.headers.set('X-POSTHOG-SESSION-ID', sessionId) - } - if (windowId) { req.headers.set('X-POSTHOG-WINDOW-ID', windowId) } } -const patchFetch = (sessionManager: SessionIdManager): (() => void) => { +const patchFetch = (sessionManager?: SessionIdManager): (() => void) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore return patch(window, 'fetch', (originalFetch: typeof fetch) => { @@ -28,7 +26,7 @@ const patchFetch = (sessionManager: SessionIdManager): (() => void) => { }) } -const patchXHR = (sessionManager: SessionIdManager): (() => void) => { +const patchXHR = (sessionManager?: SessionIdManager): (() => void) => { return patch( // we can assert this is present because we've checked previously window!.XMLHttpRequest.prototype, diff --git a/src/extensions/tracing-headers.ts b/src/extensions/tracing-headers.ts index b8867af5c..5474f7961 100644 --- a/src/extensions/tracing-headers.ts +++ b/src/extensions/tracing-headers.ts @@ -39,10 +39,10 @@ export class TracingHeaders { private _startCapturing = () => { // NB: we can assert sessionManager is present only because we've checked previously if (isUndefined(this._restoreXHRPatch)) { - assignableWindow.__PosthogExtensions__?.tracingHeadersPatchFns?._patchXHR(this.instance.sessionManager!) + assignableWindow.__PosthogExtensions__?.tracingHeadersPatchFns?._patchXHR(this.instance.sessionManager) } if (isUndefined(this._restoreFetchPatch)) { - assignableWindow.__PosthogExtensions__?.tracingHeadersPatchFns?._patchFetch(this.instance.sessionManager!) + assignableWindow.__PosthogExtensions__?.tracingHeadersPatchFns?._patchFetch(this.instance.sessionManager) } } } diff --git a/src/utils/globals.ts b/src/utils/globals.ts index a2e2479fa..487d78193 100644 --- a/src/utils/globals.ts +++ b/src/utils/globals.ts @@ -79,8 +79,8 @@ interface PostHogExtensions { onINP: (metric: any) => void } tracingHeadersPatchFns?: { - _patchFetch: (sessionManager: SessionIdManager) => () => void - _patchXHR: (sessionManager: any) => () => void + _patchFetch: (sessionManager?: SessionIdManager) => () => void + _patchXHR: (sessionManager?: SessionIdManager) => () => void } initDeadClicksAutocapture?: ( ph: PostHog, From 93af8022409e164d0b593ba0e49ccc697fcb0fd4 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 13 Dec 2024 13:04:17 +0000 Subject: [PATCH 18/20] Revert session duration --- src/extensions/replay/sessionrecording.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/extensions/replay/sessionrecording.ts b/src/extensions/replay/sessionrecording.ts index a94350534..822fdb413 100644 --- a/src/extensions/replay/sessionrecording.ts +++ b/src/extensions/replay/sessionrecording.ts @@ -315,9 +315,6 @@ export class SessionRecording { private get sessionDuration(): number | null { const mostRecentSnapshot = this.buffer?.data[this.buffer?.data.length - 1] const { sessionStartTimestamp } = this.sessionManager.checkAndGetSessionAndWindowId(true) - if (sessionStartTimestamp == null) { - return null - } return mostRecentSnapshot ? mostRecentSnapshot.timestamp - sessionStartTimestamp : null } From 490ab5fa7c076dd19050f2601e28b905396dbf3b Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 13 Dec 2024 13:12:21 +0000 Subject: [PATCH 19/20] Remove unnecessary comment --- src/extensions/tracing-headers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extensions/tracing-headers.ts b/src/extensions/tracing-headers.ts index 5474f7961..d3706dd65 100644 --- a/src/extensions/tracing-headers.ts +++ b/src/extensions/tracing-headers.ts @@ -37,7 +37,6 @@ export class TracingHeaders { } private _startCapturing = () => { - // NB: we can assert sessionManager is present only because we've checked previously if (isUndefined(this._restoreXHRPatch)) { assignableWindow.__PosthogExtensions__?.tracingHeadersPatchFns?._patchXHR(this.instance.sessionManager) } From bc9c76b4019c2884fc3bede896b88ec5bf6b9a93 Mon Sep 17 00:00:00 2001 From: Robbie Coomber Date: Fri, 13 Dec 2024 13:13:41 +0000 Subject: [PATCH 20/20] Remove check --- src/posthog-core.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posthog-core.ts b/src/posthog-core.ts index 84e42334d..ddede2ea3 100644 --- a/src/posthog-core.ts +++ b/src/posthog-core.ts @@ -949,7 +949,7 @@ export class PostHog { const infoProperties = Info.properties() - if (this.sessionManager && !this.config.__preview_experimental_cookieless_mode) { + if (this.sessionManager) { const { sessionId, windowId } = this.sessionManager.checkAndGetSessionAndWindowId() properties['$session_id'] = sessionId properties['$window_id'] = windowId