-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathcommandments.yaml
More file actions
275 lines (242 loc) · 26.1 KB
/
Copy pathcommandments.yaml
File metadata and controls
275 lines (242 loc) · 26.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# Commandments Configuration
# Tag-based rules that get folded into skill descriptions
# Skills collect all commandments matching their tags
commandments:
javascript:
- When a reverse proxy is configured, both /static/* AND /array/* must route to the assets origin (us-assets.i.posthog.com or eu-assets.i.posthog.com).
react:
# PostHog-specific
- For feature flags, use useFeatureFlagEnabled() or useFeatureFlagPayload() hooks - they handle loading states and external sync automatically
- Add analytics capture in event handlers where user actions occur, NOT in useEffect reacting to state changes
# General React patterns (react.dev/learn/you-might-not-need-an-effect)
- Do NOT use useEffect for data transformation - calculate derived values during render instead
- Do NOT use useEffect to respond to user events - put that logic in the event handler itself
- Do NOT use useEffect to chain state updates - calculate all related updates together in the event handler
- Do NOT use useEffect to notify parent components - call the parent callback alongside setState in the event handler
- To reset component state when a prop changes, pass the prop as the component's key instead of using useEffect
- useEffect is ONLY for synchronizing with external systems (non-React widgets, browser APIs, network subscriptions)
nextjs:
# Initialization
- For Next.js 15.3+, initialize PostHog in instrumentation-client.ts for the simplest setup
nextjs-feature-flags:
# Client-side feature flags
- The PostHog React hooks (useFeatureFlagEnabled, useFeatureFlagPayload) work WITHOUT PostHogProvider if posthog-js is already initialized (e.g., via instrumentation-client.ts)
- In client components, import and use hooks directly - the React context defaults to the posthog-js singleton
- Do NOT wrap components in PostHogProvider just for feature flags - it's unnecessary if posthog-js is initialized globally
# Server-side feature flags
- Server Components and Route Handlers cannot use React hooks - use posthog-node SDK instead
- Create a server-side PostHog client with posthog-node, call getAllFlags() or getFeatureFlag(), then await posthog.shutdown()
- Pass flag values from server to client components as props to avoid hydration mismatches
# Avoiding flicker
- For flags that affect initial render, evaluate server-side and pass as props to prevent UI flicker
- Client-side hooks may return undefined initially while flags load - handle this loading state
javascript_web:
- When a reverse proxy is configured, both /static/* AND /array/* must route to the assets origin (us-assets.i.posthog.com or eu-assets.i.posthog.com).
- Remember that source code is available in the node_modules directory
- Check package.json for type checking or build scripts to validate changes
- posthog-js is the JavaScript SDK package name
- posthog.init() MUST be called before any other PostHog methods (capture, identify, etc.)
- posthog-js is browser-only — do NOT import it in Node.js or server-side contexts (use posthog-node instead)
- Autocapture is ON by default with posthog-js (tracks clicks, form submissions, pageviews). Do NOT disable autocapture unless the user explicitly requests it.
- NEVER send PII in posthog.capture() event properties — no emails, full names, phone numbers, physical addresses, IP addresses, or user-generated content
- PII belongs in posthog.identify() person properties (email, name, role), NOT in capture() event properties
- Call posthog.identify(userId, { email, name, role }) on login AND on page refresh if the user is already logged in
- Call posthog.reset() on logout to unlink future events from the current user
- For SPAs without a framework router, capture pageviews with posthog.capture($pageview) or use the capture_pageview history_change option in init for History API routing
javascript_node:
- posthog-node is the Node.js server-side SDK package name – do NOT use posthog-js on the server
- 'Include enableExceptionAutocapture: true in the PostHog constructor options'
- Add posthog.capture() calls in route handlers for meaningful user actions – every route that creates, updates, or deletes data should track an event with contextual properties
- Add posthog.captureException(err, distinctId) in the application's error handler (e.g., Express error middleware, Fastify setErrorHandler, Koa app.on('error'))
- In long-running servers, the SDK batches events automatically – do NOT set flushAt or flushInterval unless you have a specific reason to
- For short-lived processes (scripts, CLIs, serverless), set flushAt to 1 and flushInterval to 0 to send events immediately
- Reverse proxy is NOT needed for server-side Node.js – only client-side JavaScript needs a proxy to avoid ad blockers
- Remember that source code is available in the node_modules directory
- Check package.json for type checking or build scripts to validate changes
python:
- Remember that source code is available in the venv/site-packages directory
- posthog is the Python SDK package name
- Install dependencies with `pip install posthog` or `pip install -r requirements.txt` and do NOT use unquoted version specifiers like `>=` directly in shell commands
- 'In CLIs and scripts: MUST call posthog.shutdown() before exit or all events are lost'
- Always use the Posthog() class constructor (instance-based API) instead of module-level posthog.api_key config
- Always include enable_exception_autocapture=True in the Posthog() constructor to automatically track exceptions
- NEVER send PII in capture() event properties — no emails, full names, phone numbers, physical addresses, IP addresses, or user-generated content
- PII belongs in identify() person properties, NOT in capture() event properties. Safe event properties are metadata like message_length, form_type, boolean flags.
- Register posthog_client.shutdown with atexit.register() to ensure all events are flushed on exit
- The Python SDK has NO identify() method — use posthog_client.set(distinct_id=user_id, properties={...}) to set person properties, or use identify_context(user_id) within a context
go:
- posthog-go is the Go SDK package; install it with `go get github.com/posthog/posthog-go` and import `github.com/posthog/posthog-go`
- Create one PostHog client per process with `posthog.NewWithConfig(...)`; do not create a new client per request or job
- Always close the client during graceful shutdown with `client.Close()` so queued events flush before the process exits
- Configure the project token, endpoint, and optional personal API key from environment variables; never hardcode PostHog secrets
- Server-side captures must set `DistinctId` to a stable user ID that matches frontend identify calls; avoid anonymous or literal IDs for business events
- Use `posthog.NewProperties().Set(...)` for event properties and keep PII in person properties via `$set`, not in event properties
- For new feature flag code, prefer `client.EvaluateFlags(...)` once per user/request, then use the returned snapshot's `IsEnabled` or `GetFlag` methods
- When capturing events related to feature-gated code, attach the evaluated flag snapshot with `Flags`, optionally filtered with `OnlyAccessed()` or `Only(...)`
- Avoid deprecated feature flag helpers such as `IsFeatureEnabled`, `GetFeatureFlag`, `GetFeatureFlagPayload`, and `Capture.SendFeatureFlags` in new code
- For error tracking, use `posthog.NewDefaultException(...)` for direct captures or wrap `log/slog` with `posthog.NewSlogCaptureHandler(...)` for automatic warning-and-above exception capture
dotnet:
- posthog-dotnet package names are `PostHog` for general .NET apps and `PostHog.AspNetCore` for ASP.NET Core apps
- Use environment variables, user secrets, or configuration providers for `ProjectToken`, `HostUrl`, and `PersonalApiKey`; never hardcode PostHog secrets
- For CLIs, scripts, workers, and other short-lived processes, create one `PostHogClient` for the process lifetime and call `FlushAsync()` before exit
- Call `IdentifyAsync` for known users and put PII such as email in person properties, not in event properties
- Use `CaptureException(exception, distinctId, properties, groups, flags)` for handled exceptions; automatic exception capture is not available in the .NET SDK yet
elixir:
- posthog-elixir is installed as the `posthog` Hex package; add `{:posthog, "~> 2.0"}` to `mix.exs` and run `mix deps.get`
- Configure PostHog in application config using `api_host`, `api_key`, and `in_app_otp_apps`; read secrets from environment or runtime config, never hardcode them
- In tests, set `test_mode` to true so events are dropped instead of sent to PostHog
- For Phoenix or Plug apps, add `PostHog.Integrations.Plug` before the router so request context is attached to captured events and errors
- Server-side captures must include a stable `distinct_id` matching frontend identify calls, or set it once per process/request with `PostHog.set_context/1`
- Remember `PostHog.set_context/1` uses Logger metadata and is process-scoped; set context in the request, job, or Task process that captures the event
- For new feature flag code, prefer `PostHog.FeatureFlags.evaluate_flags/1` once per user/request, then read values from `PostHog.FeatureFlags.Evaluations`
- To attribute captures to feature flags, call `PostHog.FeatureFlags.set_in_context/1` with the evaluated snapshot, optionally filtered with `only_accessed/1` or `only/2`
- Avoid deprecated feature flag helpers such as `check/2`, `check!/2`, `get_feature_flag_result/2`, and `get_feature_flag_result!/2` in new code
- Error tracking is enabled by default through Logger; set `in_app_otp_apps`, `capture_level`, and `metadata` to improve error grouping and context
- For source context in releases, enable source code context and run `mix posthog.package_source_code` before `mix release`
aspnetcore:
- In ASP.NET Core apps, prefer `builder.AddPostHog()` from `PostHog.AspNetCore` and inject `IPostHogClient` from dependency injection instead of manually constructing clients in controllers
- Configure ASP.NET Core apps with the `PostHog` configuration section or environment variable fallbacks such as `POSTHOG_PROJECT_TOKEN` and `POSTHOG_HOST`
- Add product analytics captures at route, controller, or handler boundaries where meaningful user actions occur; do not track every low-level method call
- Capture request exceptions in middleware with `CaptureException` and then rethrow so existing ASP.NET Core error handling still runs
- For Microsoft.FeatureManagement, call `UseFeatureManagement<TContextProvider>()` and implement `IPostHogFeatureFlagContextProvider` to provide the current distinct ID, person properties, and groups
django:
- Add 'posthog.integrations.django.PosthogContextMiddleware' to MIDDLEWARE it auto-extracts tracing headers and captures exceptions
- Initialize PostHog in AppConfig.ready() with api_key and host from environment variables
- Use the context API pattern with new_context(), identify_context(user_id), then capture()
- For login/logout views, create a new context since user state changes during the request
- Do NOT create custom middleware, distinct_id helpers, or conditional checks - the SDK handles these
flask:
- Initialize PostHog globally in create_app() using posthog.api_key and posthog.host (NOT per-request)
- Manually capture exceptions with `posthog.capture_exception(e)` for error tracking since Flask has built-in error handlers
- Blueprint registration happens AFTER PostHog initialization in create_app()
fastapi:
- Initialize PostHog in the lifespan context manager on startup using posthog.api_key and posthog.host
- Call posthog.flush() in the lifespan shutdown to ensure all events are sent before the app exits
- Use Pydantic Settings with @lru_cache decorator on get_settings() for caching and easy test overrides
- Use FastAPI dependency injection (Depends) for accessing current_user and settings in route handlers
- Use the same context API pattern as Flask/Django (with new_context(), identify_context(user_id), then capture())
php:
- Remember that source code is available in the vendor directory after composer install
- posthog/posthog-php is the PHP SDK package name
- Check composer.json for existing dependencies and autoload configuration before adding new files
- The PHP SDK uses static methods (PostHog::capture, PostHog::identify) - initialize once with PostHog::init()
- PHP SDK methods take associative arrays with 'distinctId', 'event', 'properties' keys - not positional arguments
tanstack-router:
- Use TanStack Router's built-in navigation events for pageview tracking instead of useEffect
- Use PostHogProvider in the root component defined in either the file-based convention (__root.tsx) or code-based convention (wherever createRootRoute() is called) so all child routes have access to the PostHog client
tanstack-start:
- Use PostHogProvider in the root route (__root.tsx) for client-side tracking
- Use posthog-node for server-side event capture in API routes (src/routes/api/) - do NOT use posthog-js on the server
- Create a singleton PostHog server client to avoid re-initialization on every request
laravel:
- Create a dedicated PostHogService class in app/Services/ - do NOT scatter PostHog::capture calls throughout controllers
- Register PostHog configuration in config/posthog.php using env() for all settings (api_key, host, disabled)
- Do NOT use Laravel's event system or observers for analytics - call capture explicitly where actions occur
ruby:
- "posthog-ruby is the Ruby SDK gem name (add `gem 'posthog-ruby'` to Gemfile) but require it with `require 'posthog'` (NOT `require 'posthog-ruby'`)"
- "Use PostHog::Client.new(api_key: key, host: host) for instance-based initialization in scripts and CLIs"
- "In CLIs and scripts: MUST call client.shutdown before exit or all events are lost"
- Use begin/rescue/ensure with shutdown in the ensure block for proper cleanup
- "capture and identify take a single hash argument: client.capture(distinct_id: 'user_123', event: 'my_event', properties: { key: 'value' })"
- "capture_exception takes POSITIONAL args (not keyword): client.capture_exception(exception, distinct_id, additional_properties) — do NOT use `distinct_id:` keyword syntax"
ruby-on-rails:
- Use posthog-rails gem alongside posthog-ruby for automatic exception capture and ActiveJob instrumentation
- Run `rails generate posthog:install` to create the initializer, or manually create config/initializers/posthog.rb
- "Configure auto_capture_exceptions: true to automatically track unhandled exceptions in controllers"
- "Configure report_rescued_exceptions: true to also capture exceptions that Rails rescues (e.g. with rescue_from)"
- "Configure auto_instrument_active_job: true to track background job failures with job class, queue, and arguments"
- "Use PostHog.capture() and PostHog.identify() class-level methods (NOT instance methods) — the posthog-rails gem manages the client lifecycle via PostHog.init"
- Do NOT manually create PostHog::Client instances in Rails — use PostHog.init in the initializer and PostHog.capture/identify everywhere else
- "capture_exception takes POSITIONAL args: PostHog.capture_exception(exception, distinct_id, additional_properties) — do NOT use keyword args"
- "Define posthog_distinct_id on the User model for automatic user association in error reports — posthog-rails auto-detects by trying: posthog_distinct_id, distinct_id, id, pk, uuid (in order)"
- "For ActiveJob user association, use the class-level DSL `posthog_distinct_id ->(user) { user.email }` or pass user_id: in a hash argument"
- Store the project token in Rails credentials or environment variables, never hardcode
- "For frontend tracking alongside posthog-rails, add the posthog-js snippet to the layout template — posthog-js handles pageviews, session replay, and client-side errors while posthog-ruby handles backend events, server errors, feature flags, and background jobs"
hogql:
# Property access
- Use properties.$name syntax for event properties, person.properties.$name for person properties
- Use bracket notation for special characters like properties['$feature/cool-flag']
- For cohorts, filter with person_id IN COHORT 'cohort-name'
- For actions, use matchesAction('action-name') in WHERE clauses
# Variables and filters
- Include {filters} placeholder in WHERE clauses to enable UI-based filtering in dashboards
- Use {variables.name} for reusable SQL variables across dashboards
- Access dashboard date range with {filters.dateRange.from} and {filters.dateRange.to}
# Performance optimization
- ALWAYS include a time range filter - shorter is faster (e.g., timestamp >= now() - INTERVAL 7 DAY)
- Prefer uniq() over count(distinct) for counting unique values - it's more efficient
- Don't scan the same table multiple times - use materialized views for reusable subsets
- Use timestamp-based pagination instead of OFFSET for large datasets
- Name queries descriptively for easier debugging in query_log
# Functions
- Use dateTrunc() for time-based grouping (e.g., dateTrunc('day', timestamp))
- For funnel queries, use windowFunnel() or sequenceMatch() functions
- Test queries in the PostHog SQL editor before using them in insights or the API
sveltekit:
- Set paths.relative to false in svelte.config.js — this is required for PostHog session replay to work correctly with SSR and is easy to miss
- Use the Svelte MCP server tools to check Svelte documentation (list-sections, get-documentation) and validate components (svelte-autofixer) — always run svelte-autofixer on new or modified .svelte files before finishing
swift:
- 'Set the PostHog project token and host directly in code when creating the `PostHogConfig` (e.g. `PostHogConfig(apiKey: "<project-token>", host: "https://us.i.posthog.com")`). The project token is a public client-side key designed to ship in the app binary, so hardcoding it is safe and is the recommended approach for iOS'
- 'Do NOT depend on Xcode scheme environment variables (`ProcessInfo.processInfo.environment`) as the only source of the token: they are injected only when launching from Xcode (debug/simulator), NOT in Archive/Release builds (TestFlight, App Store). Reading them is fine as an optional override, but never force-unwrap or `fatalError` on their absence — that crashes production builds on launch. Ensure a value always ships in the binary'
- When adding SPM dependencies to project.pbxproj, create three distinct objects with unique UUIDs — a `PBXBuildFile` (with `productRef`), an `XCSwiftPackageProductDependency` (with `package` and `productName`), and an `XCRemoteSwiftPackageReference` (with `repositoryURL` and `requirement`). The build file goes in the Frameworks phase `files`, the product dependency goes in the target's `packageProductDependencies`, and the package reference goes in the project's `packageReferences`.
- Check the latest release version of posthog-ios at `https://github.com/PostHog/posthog-ios/releases` before setting the `minimumVersion` in the SPM package reference — do not hardcode a stale version
- If the project uses App Sandbox (macOS), add `ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES` to the target's build settings so PostHog can reach its servers — do NOT disable the sandbox entirely
ios:
- Install the PostHog iOS SDK as `PostHog` via Swift Package Manager or CocoaPods, using `https://github.com/PostHog/posthog-ios.git` for SPM
- Initialize `PostHogSDK.shared.setup(config)` exactly once and as early as possible, either in `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)` or in the SwiftUI `App` initializer
- For SwiftUI apps, prefer meaningful `.postHogScreenView(...)` modifiers for screen tracking because automatic SwiftUI screen names can be internal view identifiers
- Call `PostHogSDK.shared.identify(...)` after login and `PostHogSDK.shared.reset()` on logout; keep PII in user properties, not event properties
- Enable iOS error autocapture with `config.errorTrackingConfig.autoCapture = true` and upload dSYM files so crash reports are symbolicated
- Enable session replay with `config.sessionReplay = true` only after confirming project replay settings and privacy masking requirements; session replay is iOS-only, not macOS
- Use `config.setBeforeSend { event in ... }` to redact, drop, or sample custom events, while preserving PostHog internal events where possible
- For iOS logs, use posthog-ios 3.58.0 or later, set `config.logs` fields before `setup`, and capture logs manually with `PostHogSDK.shared.logger` or `captureLog`
- For widgets, app clips, share extensions, and other app extensions, configure `config.appGroupIdentifier` so the main app and extensions share analytics identity
react-native:
- posthog-react-native is the React Native SDK package name
- Use react-native-config to load POSTHOG_PROJECT_TOKEN and POSTHOG_HOST from .env (variables are embedded at build time, not runtime)
- react-native-svg is a required peer dependency of posthog-react-native (used by the surveys feature) and must be installed alongside it
- Place PostHogProvider INSIDE NavigationContainer for React Navigation v7 compatibility
expo:
- posthog-react-native is the React Native SDK package name (same as bare RN)
- Use expo-constants with app.config.js extras for POSTHOG_PROJECT_TOKEN and POSTHOG_HOST (NOT react-native-config)
- Access config via `Constants.expoConfig?.extra?.posthogProjectToken` in your posthog.ts config file
- For expo-router, wrap PostHogProvider in app/_layout.tsx and manually track screens with `posthog.screen(pathname, params)` in a useEffect
flutter:
- posthog_flutter is the Flutter SDK package name; install it with `flutter pub add posthog_flutter` or add it to `pubspec.yaml`
- For manual setup, call `WidgetsFlutterBinding.ensureInitialized()`, create a `PostHogConfig`, then await `Posthog().setup(config)` before `runApp()`
- For Android, ensure `minSdkVersion` is at least `23`. If the current value is lower than `23` or missing, update/add it as `minSdkVersion 23`; if it is already `23` or higher, leave it unchanged. Configure `com.posthog.posthog.PROJECT_TOKEN` and `com.posthog.posthog.POSTHOG_HOST` in `android/app/src/main/AndroidManifest.xml` unless using manual setup with `AUTO_INIT=false`
- For iOS, ensure the minimum deployment target is at least iOS `13.0`. If the current `platform :ios` value is lower than `13.0` or missing, update/add it as `platform :ios, '13.0'`; if it is already `13.0` or higher, leave it unchanged. Configure `com.posthog.posthog.PROJECT_TOKEN` and `com.posthog.posthog.POSTHOG_HOST` in `ios/Runner/Info.plist` unless using manual setup
- For Session Replay or Surveys, disable auto-init with `com.posthog.posthog.AUTO_INIT=false` and initialize manually so the required options can be enabled
- For Flutter Web, add the posthog-js web snippet to `web/index.html`; Flutter Web session replay also requires Canvas capture in project settings
- Capture screen views with `PosthogObserver()` and named routes; unnamed routes will not produce useful `$screen` names
- Call `Posthog().identify(...)` after login and `Posthog().reset()` on logout; keep PII in user properties, not event properties
- Use `beforeSend` to redact or drop Dart-captured events, but remember it does not intercept native session replay, lifecycle, or system properties
astro:
- Always use the is:inline directive on PostHog script tags to prevent Astro from processing them and causing TypeScript errors
- Use PUBLIC_ prefix for client-side environment variables in Astro (e.g., PUBLIC_POSTHOG_PROJECT_TOKEN)
- Create a posthog.astro component in src/components/ for reusable initialization across pages
- Import the PostHog component in a Layout and wrap all pages with that layout
astro-view-transitions:
- Wrap PostHog initialization with a window.__posthog_initialized guard to prevent stack overflow during soft navigation
- Set capture_pageview option to 'history_change' for automatic pageview tracking during soft navigation
- Use the astro page-load event instead of just DOMContentLoaded to re-run scripts after soft navigation
astro-ssr:
- Use posthog-node in API routes under src/pages/api/ for server-side event tracking
- Store the posthog-node client instance in a singleton pattern (src/lib/posthog-server.ts) to avoid creating multiple clients
- Pass the client session ID to server via X-PostHog-Session-Id header for unified session tracking
astro-hybrid:
- Use posthog-node in API routes under src/pages/api/ for server-side event tracking
- Store the posthog-node client instance in a singleton pattern (src/lib/posthog-server.ts) to avoid creating multiple clients
- In Astro 5, use output static (the default) with an adapter - pages are prerendered by default
- Use export const prerender = false to opt specific pages into SSR when they need server-side rendering
- Only pages that need server-side PostHog tracking (like API-backed forms) should opt out of prerendering
angular:
- Use inject() instead of constructor injection. PostHog service should be injected via inject() in components/services that need it.
- Create a dedicated PosthogService as a singleton root service that wraps the PostHog SDK.
- Always use standalone components over NgModules.
- Configure PostHog credentials in src/environments/environment.ts files, as Angular reads environment variables from these configuration files
android:
- Adapt dependency configuration to the appropriate build.gradle(.kts) file according to the project gradle version
- Call `PostHogAndroid.setup()` only once in the Application class's `onCreate()` method, so it's initialized as early as possible and only once.
- Initialize PostHog in the Application class's `onCreate()` method
- Ensure every activity has a `android:label` to accurately track screen views.