-
Notifications
You must be signed in to change notification settings - Fork 205
Add: posthog session recordings #2751
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,40 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import posthog from 'posthog-js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { browser } from '$app/environment'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { VARS, ENV } from '$lib/system'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { Models } from '@appwrite.io/console'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { preferences } from '$lib/stores/preferences'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const POSTHOG_PREFS_KEY = 'posthog_session_recorded'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (browser && VARS.POSTHOG_API_KEY && !ENV.DEV && !ENV.TEST) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| posthog.init(VARS.POSTHOG_API_KEY, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_host: VARS.POSTHOG_HOST, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| person_profiles: 'identified_only', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| capture_pageview: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| capture_pageleave: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session_recording: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| recordCrossOriginIframes: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /*maskTextSelector: '.ph-no-capture'*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autocapture: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disable_session_recording: !ENV.PROD | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function initializeSessionRecording(user: Models.User<Models.Preferences>): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!posthog) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasRecordedFirstSession = preferences.getKey(POSTHOG_PREFS_KEY, false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!hasRecordedFirstSession) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| posthog.identify(user.$id, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| account_created: user.$createdAt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| posthog.startSessionRecording(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await preferences.setKey(POSTHOG_PREFS_KEY, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| posthog.stopSessionRecording(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+24
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Add error handling and consider privacy/consent requirements. The Additionally, session recording captures user behavior and personal data (user ID, account creation date). Ensure compliance with privacy regulations (GDPR, CCPA) by implementing:
🔎 Example error handling export async function initializeSessionRecording(user: Models.User<Models.Preferences>): Promise<void> {
if (!posthog) return;
const hasRecordedFirstSession = preferences.getKey(POSTHOG_PREFS_KEY, false);
if (!hasRecordedFirstSession) {
- posthog.identify(user.$id, {
- account_created: user.$createdAt
- });
- posthog.startSessionRecording();
- await preferences.setKey(POSTHOG_PREFS_KEY, true);
+ try {
+ posthog.identify(user.$id, {
+ account_created: user.$createdAt
+ });
+ posthog.startSessionRecording();
+ await preferences.setKey(POSTHOG_PREFS_KEY, true);
+ } catch (error) {
+ console.error('Failed to initialize PostHog session recording:', error);
+ }
} else {
posthog.stopSessionRecording();
}
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { posthog }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+40
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix Prettier formatting violations before merging. The pipeline indicates a Prettier formatting check failure. Run 🧰 Tools🪛 GitHub Actions: Tests[error] 1-1: Prettier formatting check failed for src/lib/actions/posthog.ts. Run 'prettier --write' to fix code style issues. 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,8 @@ | |
| import MobileSupportModal from './wizard/support/mobileSupportModal.svelte'; | ||
| import { showSupportModal } from './wizard/support/store'; | ||
| import { activeHeaderAlert, consoleVariables } from './store'; | ||
| import { user } from '$lib/stores/user'; | ||
| import { initializeSessionRecording } from '$lib/actions/posthog'; | ||
|
Comment on lines
+43
to
+44
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find src -name "posthog.ts" -o -name "posthog.js" -o -name "posthog.tsx" -o -name "posthog.jsx"Repository: appwrite/console Length of output: 86 🏁 Script executed: cat -n src/lib/actions/posthog.tsRepository: appwrite/console Length of output: 1618 🏁 Script executed: sed -n '270,285p' src/routes/\(console\)/+layout.svelteRepository: appwrite/console Length of output: 629 Add error handling and explicit user consent check to PostHog initialization. The
The POSTHOG_API_KEY check (line 9) and environment guards are correctly implemented. 🤖 Prompt for AI Agents |
||
| import { base } from '$app/paths'; | ||
| import { headerAlert } from '$lib/stores/headerAlert'; | ||
|
|
@@ -270,6 +272,10 @@ | |
| $stripe = await loadStripe(VARS.PUBLIC_STRIPE_KEY); | ||
| await checkForMissingPaymentMethod(); | ||
| } | ||
| if ($user && isCloud) { | ||
| await initializeSessionRecording($user); | ||
| } | ||
| }); | ||
| function checkForFeedback(interval: number) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: appwrite/console
Length of output: 1618
🏁 Script executed:
Repository: appwrite/console
Length of output: 1319
🏁 Script executed:
Repository: appwrite/console
Length of output: 229
🌐 Web query:
PostHog session recording configuration production preview environments best practices💡 Result:
Here are concise best practices for configuring PostHog session recordings across production / preview (staging/dev) environments:
Use separate PostHog projects per environment (prod vs staging/dev/preview). This prevents test noise and billing surprises. Use env vars to load the correct API key per environment. [3]
Don’t record everything by default. Enable recordings only where useful via URL triggers, event triggers or feature flags (e.g., signup/checkout flows). URL triggers replace the older authorized-domains setting. Use sampling and minimum-duration to reduce volume. (start/stop APIs let you programmatically control recordings). [2][4]
Disable or restrict recordings in preview builds:
Protect PII and sensitive UI:
Use sampling, minimum-duration (strictMinimumDuration) and billing limits:
Consent, compliance and persistence:
Dev/test ergonomics and reliability:
Operational tips:
Sources:
If you want, I can produce a short example posthog.init snippet showing a recommended prod vs preview config (masking + disabled recordings in preview).
Clarify
disable_session_recordingconfiguration and handle PREVIEW environments properly.Line 20 sets
disable_session_recording: !ENV.PROD, but the outer condition on line 9 already ensures!ENV.DEV. SinceENV.PROD = !dev, this configuration is redundant—when the outer condition passes,ENV.PRODis true, makingdisable_session_recordingalways false.Additionally, the outer condition initializes PostHog for both production and preview environments without distinction. Per PostHog best practices, session recording should be disabled by default in preview deployments and enabled only in production. Consider adding
ENV.PREVIEWto the initialization condition check or adjusting the config to properly handle environment-specific behavior.Line 17 contains commented code for
maskTextSelector. Remove it or uncomment with proper configuration for sensitive data masking, which PostHog recommends as default behavior across all environments.🤖 Prompt for AI Agents