vybekiit 0.7.3 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/dist/bin.js +16607 -7527
  2. package/dist/global-skills/aws-cdk/SKILL.md +2 -1
  3. package/dist/global-skills/aws-cloudformation/SKILL.md +2 -1
  4. package/dist/global-skills/aws-serverless/SKILL.md +45 -44
  5. package/dist/global-skills/aws-serverless/assets/powertools-handler.py +2 -1
  6. package/dist/global-skills/aws-serverless/references/api-gateway.md +50 -470
  7. package/dist/global-skills/aws-serverless/references/architecture.md +47 -186
  8. package/dist/global-skills/aws-serverless/references/concurrency.md +44 -158
  9. package/dist/global-skills/aws-serverless/references/deployment.md +1 -1
  10. package/dist/global-skills/aws-serverless/references/event-sources.md +72 -391
  11. package/dist/global-skills/aws-serverless/references/lambda.md +69 -428
  12. package/dist/global-skills/aws-serverless/references/orchestration.md +65 -384
  13. package/dist/global-skills/aws-serverless/references/production.md +78 -415
  14. package/dist/global-skills/aws-serverless/references/troubleshooting.md +92 -619
  15. package/dist/global-skills/claimable-postgres/SKILL.md +60 -49
  16. package/dist/global-skills/design-my-data/SKILL.md +2 -0
  17. package/dist/global-skills/eas-app-stores/SKILL.md +8 -0
  18. package/dist/global-skills/eas-app-stores/references/play-store.md +2 -0
  19. package/dist/global-skills/eas-hosting/SKILL.md +8 -0
  20. package/dist/global-skills/eas-observe/SKILL.md +30 -8
  21. package/dist/global-skills/eas-observe/agents/openai.yaml +1 -1
  22. package/dist/global-skills/eas-observe/references/metrics.md +54 -3
  23. package/dist/global-skills/eas-observe/references/queries.md +78 -17
  24. package/dist/global-skills/eas-observe/references/setup.md +164 -5
  25. package/dist/global-skills/eas-observe/references/third-party.md +136 -0
  26. package/dist/global-skills/eas-simulator/SKILL.md +63 -11
  27. package/dist/global-skills/eas-simulator/references/controllers.md +21 -2
  28. package/dist/global-skills/eas-simulator/references/run-your-app.md +16 -11
  29. package/dist/global-skills/eas-simulator/references/troubleshooting.md +8 -5
  30. package/dist/global-skills/eas-update-insights/SKILL.md +8 -0
  31. package/dist/global-skills/eas-workflows/SKILL.md +15 -10
  32. package/dist/global-skills/eas-workflows/scripts/package.json +2 -7
  33. package/dist/global-skills/email-best-practices/.github/workflows/sync-skills.yml +30 -0
  34. package/dist/global-skills/email-best-practices/README.md +63 -0
  35. package/dist/global-skills/email-best-practices/references/accessibility.md +189 -0
  36. package/dist/global-skills/email-best-practices/references/compliance.md +125 -0
  37. package/dist/global-skills/email-best-practices/references/deliverability.md +121 -0
  38. package/dist/global-skills/email-best-practices/references/email-capture.md +129 -0
  39. package/dist/global-skills/email-best-practices/references/email-types.md +173 -0
  40. package/dist/global-skills/email-best-practices/references/list-management.md +157 -0
  41. package/dist/global-skills/email-best-practices/references/marketing-emails.md +115 -0
  42. package/dist/global-skills/email-best-practices/references/sending-reliability.md +155 -0
  43. package/dist/global-skills/email-best-practices/references/transactional-email-catalog.md +418 -0
  44. package/dist/global-skills/email-best-practices/references/transactional-emails.md +92 -0
  45. package/dist/global-skills/email-best-practices/references/webhooks-events.md +167 -0
  46. package/dist/global-skills/email-best-practices/tests/README.md +35 -0
  47. package/dist/global-skills/email-best-practices/tests/scenarios/01-spam-deliverability.md +46 -0
  48. package/dist/global-skills/email-best-practices/tests/scenarios/02-multi-region-compliance.md +48 -0
  49. package/dist/global-skills/email-best-practices/tests/scenarios/03-retry-idempotency.md +36 -0
  50. package/dist/global-skills/email-best-practices/tests/scenarios/04-webhook-bounce-handling.md +52 -0
  51. package/dist/global-skills/email-best-practices/tests/scenarios/05-new-saas-email-plan.md +51 -0
  52. package/dist/global-skills/expo-animation/LICENSE +21 -0
  53. package/dist/global-skills/expo-animation/RECIPES.md +385 -0
  54. package/dist/global-skills/expo-animation/SKILL.md +267 -0
  55. package/dist/global-skills/expo-animation/agents/openai.yaml +4 -0
  56. package/dist/global-skills/expo-app-clip/SKILL.md +8 -0
  57. package/dist/global-skills/expo-brownfield/SKILL.md +8 -0
  58. package/dist/global-skills/expo-brownfield/references/brownfield-isolated.md +53 -4
  59. package/dist/global-skills/expo-data-fetching/SKILL.md +8 -0
  60. package/dist/global-skills/expo-design-system/SKILL.md +356 -0
  61. package/dist/global-skills/expo-design-system/agents/openai.yaml +4 -0
  62. package/dist/global-skills/expo-design-system/references/audit.md +185 -0
  63. package/dist/global-skills/expo-dev-client/SKILL.md +8 -0
  64. package/dist/global-skills/expo-dom/SKILL.md +8 -0
  65. package/dist/global-skills/expo-examples/SKILL.md +8 -0
  66. package/dist/global-skills/expo-migrate-module/SKILL.md +113 -0
  67. package/dist/global-skills/expo-migrate-module/agents/openai.yaml +4 -0
  68. package/dist/global-skills/expo-migrate-module/references/compatibility.md +73 -0
  69. package/dist/global-skills/expo-migrate-module/references/example.md +212 -0
  70. package/dist/global-skills/expo-migrate-module/references/migration-map.md +306 -0
  71. package/dist/global-skills/expo-module/SKILL.md +11 -1
  72. package/dist/global-skills/expo-native-ui/SKILL.md +8 -0
  73. package/dist/global-skills/expo-project-structure/SKILL.md +114 -0
  74. package/dist/global-skills/expo-project-structure/agents/openai.yaml +4 -0
  75. package/dist/global-skills/expo-router/SKILL.md +8 -0
  76. package/dist/global-skills/expo-skill-feedback/SKILL.md +66 -33
  77. package/dist/global-skills/expo-skill-feedback/agents/openai.yaml +2 -2
  78. package/dist/global-skills/expo-tailwind-setup/SKILL.md +8 -0
  79. package/dist/global-skills/expo-ui/SKILL.md +8 -0
  80. package/dist/global-skills/expo-upgrade/SKILL.md +15 -1
  81. package/dist/global-skills/expo-web-to-native/SKILL.md +8 -0
  82. package/dist/global-skills/extension-to-functions-codebase/SKILL.md +129 -0
  83. package/dist/global-skills/extension-to-functions-codebase/references/configuration-migration.md +161 -0
  84. package/dist/global-skills/extension-to-functions-codebase/references/destructuring-shim.md +122 -0
  85. package/dist/global-skills/extension-to-functions-codebase/references/signature-mapping.md +84 -0
  86. package/dist/global-skills/firebase-ai-logic-basics/SKILL.md +61 -19
  87. package/dist/global-skills/firebase-ai-logic-basics/references/flutter_setup.md +6 -3
  88. package/dist/global-skills/firebase-app-hosting-basics/SKILL.md +5 -1
  89. package/dist/global-skills/firebase-auth-basics/SKILL.md +4 -2
  90. package/dist/global-skills/firebase-basics/SKILL.md +5 -5
  91. package/dist/global-skills/firebase-crashlytics/SKILL.md +2 -0
  92. package/dist/global-skills/firebase-data-connect/SKILL.md +2 -0
  93. package/dist/global-skills/firebase-firestore/SKILL.md +3 -6
  94. package/dist/global-skills/firebase-hosting-basics/SKILL.md +4 -1
  95. package/dist/global-skills/firebase-remote-config-basics/SKILL.md +5 -1
  96. package/dist/global-skills/firebase-security-rules-auditor/SKILL.md +4 -1
  97. package/dist/global-skills/harden/SKILL.md +2 -1
  98. package/dist/global-skills/instrument-feature-flags/SKILL.md +1 -0
  99. package/dist/global-skills/instrument-feature-flags/references/COMMANDMENTS.md +5 -0
  100. package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +6 -4
  101. package/dist/global-skills/instrument-feature-flags/references/android.md +6 -4
  102. package/dist/global-skills/instrument-feature-flags/references/api.md +6 -4
  103. package/dist/global-skills/instrument-feature-flags/references/best-practices.md +6 -4
  104. package/dist/global-skills/instrument-feature-flags/references/django.md +38 -5
  105. package/dist/global-skills/instrument-feature-flags/references/dotnet.md +10 -4
  106. package/dist/global-skills/instrument-feature-flags/references/elixir.md +6 -4
  107. package/dist/global-skills/instrument-feature-flags/references/flask.md +17 -5
  108. package/dist/global-skills/instrument-feature-flags/references/flutter.md +7 -5
  109. package/dist/global-skills/instrument-feature-flags/references/go.md +6 -4
  110. package/dist/global-skills/instrument-feature-flags/references/ios.md +6 -4
  111. package/dist/global-skills/instrument-feature-flags/references/java.md +6 -4
  112. package/dist/global-skills/instrument-feature-flags/references/laravel.md +6 -4
  113. package/dist/global-skills/instrument-feature-flags/references/next-js.md +74 -8
  114. package/dist/global-skills/instrument-feature-flags/references/nodejs.md +6 -4
  115. package/dist/global-skills/instrument-feature-flags/references/php.md +6 -4
  116. package/dist/global-skills/instrument-feature-flags/references/python.md +6 -4
  117. package/dist/global-skills/instrument-feature-flags/references/react-native.md +6 -4
  118. package/dist/global-skills/instrument-feature-flags/references/react.md +6 -4
  119. package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +6 -4
  120. package/dist/global-skills/instrument-feature-flags/references/ruby.md +6 -4
  121. package/dist/global-skills/instrument-feature-flags/references/rust.md +6 -4
  122. package/dist/global-skills/instrument-feature-flags/references/usage.md +41 -4
  123. package/dist/global-skills/instrument-feature-flags/references/web.md +7 -5
  124. package/dist/global-skills/instrument-product-analytics/SKILL.md +2 -1
  125. package/dist/global-skills/instrument-product-analytics/references/COMMANDMENTS.md +5 -0
  126. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-hybrid.md +12 -14
  127. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-ssr.md +25 -21
  128. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-django.md +75 -55
  129. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-fastapi.md +3 -6
  130. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-flask.md +26 -16
  131. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-nuxt-3-6.md +8 -5
  132. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-nuxt-4.md +4 -4
  133. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-react-router-7-framework.md +3 -3
  134. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby-on-rails.md +8 -4
  135. package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-tanstack-start.md +20 -8
  136. package/dist/global-skills/instrument-product-analytics/references/android.md +46 -4
  137. package/dist/global-skills/instrument-product-analytics/references/angular.md +41 -5
  138. package/dist/global-skills/instrument-product-analytics/references/astro.md +41 -5
  139. package/dist/global-skills/instrument-product-analytics/references/configuration.md +7 -4
  140. package/dist/global-skills/instrument-product-analytics/references/django.md +38 -5
  141. package/dist/global-skills/instrument-product-analytics/references/dotnet.md +10 -4
  142. package/dist/global-skills/instrument-product-analytics/references/elixir.md +6 -4
  143. package/dist/global-skills/instrument-product-analytics/references/flask.md +17 -5
  144. package/dist/global-skills/instrument-product-analytics/references/flutter.md +49 -4
  145. package/dist/global-skills/instrument-product-analytics/references/go.md +6 -4
  146. package/dist/global-skills/instrument-product-analytics/references/identify-users.md +38 -7
  147. package/dist/global-skills/instrument-product-analytics/references/ios.md +14 -4
  148. package/dist/global-skills/instrument-product-analytics/references/laravel.md +6 -4
  149. package/dist/global-skills/instrument-product-analytics/references/next-js.md +74 -8
  150. package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +39 -7
  151. package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +40 -4
  152. package/dist/global-skills/instrument-product-analytics/references/php.md +6 -4
  153. package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +21 -17
  154. package/dist/global-skills/instrument-product-analytics/references/python.md +15 -5
  155. package/dist/global-skills/instrument-product-analytics/references/react-native.md +41 -7
  156. package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +18 -4
  157. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +18 -4
  158. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +18 -4
  159. package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +18 -4
  160. package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +6 -4
  161. package/dist/global-skills/instrument-product-analytics/references/ruby.md +6 -4
  162. package/dist/global-skills/instrument-product-analytics/references/svelte.md +42 -6
  163. package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +31 -7
  164. package/dist/global-skills/instrument-product-analytics/references/usage.md +41 -4
  165. package/dist/global-skills/instrument-product-analytics/references/vue-js.md +42 -6
  166. package/dist/global-skills/manifest.json +6 -1
  167. package/dist/global-skills/neon/SKILL.md +235 -121
  168. package/dist/global-skills/neon-ai-gateway/SKILL.md +95 -16
  169. package/dist/global-skills/neon-functions/SKILL.md +242 -152
  170. package/dist/global-skills/neon-functions/references/ai-sdk.md +9 -3
  171. package/dist/global-skills/neon-functions/references/mastra-studio.md +1 -1
  172. package/dist/global-skills/neon-functions/references/mcp.md +13 -4
  173. package/dist/global-skills/neon-functions/references/sentry.md +165 -52
  174. package/dist/global-skills/neon-functions/references/sse.md +23 -6
  175. package/dist/global-skills/neon-object-storage/SKILL.md +40 -16
  176. package/dist/global-skills/neon-postgres/SKILL.md +63 -262
  177. package/dist/global-skills/neon-postgres-branches/SKILL.md +61 -50
  178. package/dist/global-skills/neon-postgres-egress-optimizer/SKILL.md +22 -3
  179. package/dist/global-skills/resend/SKILL.md +6 -6
  180. package/dist/global-skills/resend/references/automations.md +2 -2
  181. package/dist/global-skills/resend/references/broadcasts.md +11 -3
  182. package/dist/global-skills/resend/references/domains.md +25 -3
  183. package/dist/global-skills/resend/references/installation.md +7 -7
  184. package/dist/global-skills/setup-payments/SKILL.md +4 -5
  185. package/dist/global-skills/stripe-best-practices/SKILL.md +32 -7
  186. package/dist/global-skills/stripe-best-practices/references/billing.md +11 -1
  187. package/dist/global-skills/stripe-best-practices/references/payments.md +23 -2
  188. package/dist/global-skills/stripe-best-practices/references/security.md +21 -11
  189. package/dist/global-skills/stripe-best-practices/references/tax.md +116 -11
  190. package/dist/global-skills/supabase/CHANGELOG.md +25 -0
  191. package/dist/global-skills/supabase/SKILL.md +5 -1
  192. package/dist/global-skills/supabase-postgres-best-practices/CHANGELOG.md +30 -0
  193. package/dist/global-skills/supabase-postgres-best-practices/SKILL.md +1 -1
  194. package/dist/global-skills/use-kit-mcp/SKILL.md +5 -5
  195. package/dist/global-skills/use-railway/SKILL.md +4 -4
  196. package/dist/global-skills/use-railway/references/iac.md +206 -57
  197. package/dist/global-skills/use-railway/scripts/railway-api.sh +7 -2
  198. package/dist/global-skills/xcode-project-setup/SKILL.md +2 -0
  199. package/package.json +12 -9
  200. package/LICENSE.md +0 -47
  201. package/dist/global-skills/eas-workflows/scripts/validate.js +0 -84
  202. package/dist/global-skills/expo-skill-feedback/scripts/skill-feedback.cjs +0 -118
  203. package/dist/global-skills/neon-functions/references/hono-websockets.md +0 -145
@@ -194,7 +194,7 @@ If you're using PostHog's JavaScript SDK on the frontend, enable tracing headers
194
194
  ```javascript
195
195
  posthog.init('<ph_project_token>', {
196
196
  api_host: 'https://us.i.posthog.com',
197
- __add_tracing_headers: ['your-backend-domain.com'],
197
+ tracing_headers: ['your-backend-domain.com'],
198
198
  })
199
199
  ```
200
200
 
@@ -271,6 +271,49 @@ class CoreConfig(AppConfig):
271
271
  if settings.DEBUG:
272
272
  posthog.debug = True
273
273
 
274
+ # Register the auth signal that identifies the login request's context.
275
+ from . import signals # noqa: F401
276
+
277
+ ```
278
+
279
+ ---
280
+
281
+ ## core/signals.py
282
+
283
+ ```py
284
+ """PostHog identity for the login request.
285
+
286
+ The middleware reads request.user once, before any view runs. On a login request
287
+ the visitor is still anonymous at that point, so the request's context has no
288
+ distinct ID, and calling login() inside the view does not change that. This
289
+ signal runs inside the login request and identifies the ambient context, so
290
+ every capture later in that same request is attributed to the user who just
291
+ logged in. Requests made after login don't need this: the middleware sees the
292
+ authenticated user from the start.
293
+ """
294
+
295
+ import posthog
296
+ from posthog import identify_context
297
+ from django.contrib.auth.signals import user_logged_in
298
+ from django.dispatch import receiver
299
+
300
+
301
+ @receiver(user_logged_in)
302
+ def identify_posthog_user(sender, request, user, **kwargs):
303
+ identify_context(str(user.pk))
304
+
305
+ # PII belongs in person properties, never in event properties.
306
+ posthog.set(
307
+ distinct_id=str(user.pk),
308
+ properties={
309
+ 'email': user.email,
310
+ 'username': user.username,
311
+ 'name': user.get_full_name() or user.username,
312
+ 'is_staff': user.is_staff,
313
+ 'date_joined': user.date_joined.isoformat(),
314
+ },
315
+ )
316
+
274
317
  ```
275
318
 
276
319
  ---
@@ -739,7 +782,7 @@ urlpatterns = [
739
782
  """Django views demonstrating PostHog integration patterns"""
740
783
 
741
784
  import posthog
742
- from posthog import new_context, identify_context, tag, capture
785
+ from posthog import capture
743
786
  from django.shortcuts import render, redirect
744
787
  from django.contrib.auth import authenticate, login, logout
745
788
  from django.contrib.auth.decorators import login_required
@@ -762,20 +805,11 @@ def home_view(request):
762
805
  if user is not None:
763
806
  login(request, user)
764
807
 
765
- # PostHog: Identify user and capture login event
766
- with new_context():
767
- identify_context(str(user.id))
768
-
769
- # Set person properties (PII goes in tag, not capture)
770
- tag('email', user.email)
771
- tag('username', user.username)
772
- tag('name', user.get_full_name() or user.username)
773
- tag('is_staff', user.is_staff)
774
- tag('date_joined', user.date_joined.isoformat())
775
-
776
- capture('user_logged_in', properties={
777
- 'login_method': 'email',
778
- })
808
+ # PostHog: the user_logged_in signal (core/signals.py) has identified
809
+ # this request's context, so a plain capture is attributed.
810
+ capture('user_logged_in', properties={
811
+ 'login_method': 'email',
812
+ })
779
813
 
780
814
  return redirect('dashboard')
781
815
  else:
@@ -787,12 +821,9 @@ def home_view(request):
787
821
  def logout_view(request):
788
822
  """Logout the current user"""
789
823
  if request.user.is_authenticated:
790
- user_id = str(request.user.id)
791
-
792
- # PostHog: Track logout before session ends
793
- with new_context():
794
- identify_context(user_id)
795
- capture('user_logged_out')
824
+ # PostHog: the middleware identified this request's context from the
825
+ # still-authenticated user, so capture before calling logout().
826
+ capture('user_logged_out')
796
827
 
797
828
  logout(request)
798
829
 
@@ -804,12 +835,11 @@ def dashboard_view(request):
804
835
  """Dashboard page with feature flag example"""
805
836
  user_id = str(request.user.id)
806
837
 
807
- # PostHog: Track dashboard view
808
- with new_context():
809
- identify_context(user_id)
810
- capture('dashboard_viewed', properties={
811
- 'is_staff': request.user.is_staff,
812
- })
838
+ # PostHog: the middleware already identified this request's context from the
839
+ # logged-in user, so a plain capture is attributed to them.
840
+ capture('dashboard_viewed', properties={
841
+ 'is_staff': request.user.is_staff,
842
+ })
813
843
 
814
844
  # PostHog: Check feature flag
815
845
  show_new_feature = posthog.feature_enabled(
@@ -854,14 +884,10 @@ def consider_burrito_view(request):
854
884
  count = request.session.get('burrito_count', 0) + 1
855
885
  request.session['burrito_count'] = count
856
886
 
857
- user_id = str(request.user.id)
858
-
859
887
  # PostHog: Track custom event
860
- with new_context():
861
- identify_context(user_id)
862
- capture('burrito_considered', properties={
863
- 'total_considerations': count,
864
- })
888
+ capture('burrito_considered', properties={
889
+ 'total_considerations': count,
890
+ })
865
891
 
866
892
  return JsonResponse({
867
893
  'success': True,
@@ -875,9 +901,7 @@ def profile_view(request):
875
901
  user_id = str(request.user.id)
876
902
 
877
903
  # PostHog: Track profile view
878
- with new_context():
879
- identify_context(user_id)
880
- capture('profile_viewed')
904
+ capture('profile_viewed')
881
905
 
882
906
  context = {
883
907
  'user': request.user,
@@ -906,12 +930,10 @@ def trigger_error_view(request):
906
930
  posthog.capture_exception(e)
907
931
 
908
932
  # PostHog: Track error trigger event
909
- with new_context():
910
- identify_context(str(request.user.id))
911
- capture('error_triggered', properties={
912
- 'error_type': error_type,
913
- 'error_message': str(e),
914
- })
933
+ capture('error_triggered', properties={
934
+ 'error_type': error_type,
935
+ 'error_message': str(e),
936
+ })
915
937
 
916
938
  return JsonResponse({
917
939
  'success': False,
@@ -939,17 +961,15 @@ def group_analytics_view(request):
939
961
  )
940
962
 
941
963
  # PostHog: Capture event with group
942
- with new_context():
943
- identify_context(user_id)
944
- capture(
945
- 'feature_used',
946
- properties={
947
- 'feature_name': 'group_analytics',
948
- },
949
- groups={
950
- 'company': 'acme-corp',
951
- }
952
- )
964
+ capture(
965
+ 'feature_used',
966
+ properties={
967
+ 'feature_name': 'group_analytics',
968
+ },
969
+ groups={
970
+ 'company': 'acme-corp',
971
+ }
972
+ )
953
973
 
954
974
  return JsonResponse({
955
975
  'success': True,
@@ -446,8 +446,7 @@ class PostHogMiddleware:
446
446
 
447
447
  with new_context():
448
448
  if user:
449
- identify_context(user.email)
450
- tag("email", user.email)
449
+ identify_context(str(user.id))
451
450
  tag("is_staff", user.is_staff)
452
451
 
453
452
  await self.app(scope, receive, send)
@@ -794,12 +793,11 @@ async def login(
794
793
  if user:
795
794
  is_new_user = user.record_login(db)
796
795
  with new_context():
797
- identify_context(user.email)
796
+ identify_context(str(user.id))
798
797
  capture(
799
798
  "user_logged_in",
800
799
  properties={
801
800
  "$set": {"email": user.email, "is_staff": user.is_staff},
802
- "username": user.email,
803
801
  "is_new_user": is_new_user,
804
802
  },
805
803
  )
@@ -860,12 +858,11 @@ async def signup(
860
858
  user = User.create_user(db, email=email, password=password, is_staff=False)
861
859
 
862
860
  with new_context():
863
- identify_context(user.email)
861
+ identify_context(str(user.id))
864
862
  capture(
865
863
  "user_signed_up",
866
864
  properties={
867
865
  "$set": {"email": user.email, "is_staff": user.is_staff},
868
- "username": user.email,
869
866
  "signup_method": "form",
870
867
  },
871
868
  )
@@ -265,7 +265,7 @@ def consider_burrito():
265
265
 
266
266
  # PostHog: Capture custom event
267
267
  with new_context():
268
- identify_context(current_user.email)
268
+ identify_context(str(current_user.id))
269
269
  capture("burrito_considered", properties={"total_considerations": burrito_count})
270
270
 
271
271
  return jsonify({"success": True, "count": burrito_count})
@@ -291,7 +291,7 @@ def test_error():
291
291
  if should_capture:
292
292
  # Manually capture this specific exception in PostHog
293
293
  with new_context():
294
- identify_context(current_user.email)
294
+ identify_context(str(current_user.id))
295
295
  event_id = posthog.capture_exception(e)
296
296
 
297
297
  return jsonify({
@@ -398,7 +398,7 @@ from app.main import routes # noqa: E402, F401
398
398
  import posthog
399
399
  from flask import flash, redirect, render_template, request, session, url_for
400
400
  from flask_login import current_user, login_required, login_user, logout_user
401
- from posthog import capture, identify_context, new_context, tag
401
+ from posthog import capture, identify_context, new_context
402
402
 
403
403
  from app.main import main_bp
404
404
  from app.models import User
@@ -420,12 +420,17 @@ def home():
420
420
 
421
421
  # PostHog: Identify user and capture login event
422
422
  with new_context():
423
- identify_context(user.email)
424
-
425
- # Set person properties (PII goes in tag, not capture)
426
- tag("email", user.email)
427
- tag("is_staff", user.is_staff)
428
- tag("date_joined", user.date_joined.isoformat())
423
+ identify_context(str(user.id))
424
+
425
+ # PII belongs in person properties, never in event properties
426
+ posthog.set(
427
+ distinct_id=str(user.id),
428
+ properties={
429
+ "email": user.email,
430
+ "is_staff": user.is_staff,
431
+ "date_joined": user.date_joined.isoformat(),
432
+ },
433
+ )
429
434
 
430
435
  capture("user_logged_in", properties={"login_method": "password"})
431
436
 
@@ -464,11 +469,16 @@ def signup():
464
469
 
465
470
  # PostHog: Identify new user and capture signup event
466
471
  with new_context():
467
- identify_context(user.email)
472
+ identify_context(str(user.id))
468
473
 
469
- tag("email", user.email)
470
- tag("is_staff", user.is_staff)
471
- tag("date_joined", user.date_joined.isoformat())
474
+ posthog.set(
475
+ distinct_id=str(user.id),
476
+ properties={
477
+ "email": user.email,
478
+ "is_staff": user.is_staff,
479
+ "date_joined": user.date_joined.isoformat(),
480
+ },
481
+ )
472
482
 
473
483
  capture("user_signed_up", properties={"signup_method": "form"})
474
484
 
@@ -486,7 +496,7 @@ def logout():
486
496
  """Logout and capture event."""
487
497
  # PostHog: Capture logout event before session ends
488
498
  with new_context():
489
- identify_context(current_user.email)
499
+ identify_context(str(current_user.id))
490
500
  capture("user_logged_out")
491
501
 
492
502
  logout_user()
@@ -499,7 +509,7 @@ def dashboard():
499
509
  """Dashboard with feature flag demonstration."""
500
510
  # PostHog: Capture dashboard view
501
511
  with new_context():
502
- identify_context(current_user.email)
512
+ identify_context(str(current_user.id))
503
513
  capture("dashboard_viewed", properties={"is_staff": current_user.is_staff})
504
514
 
505
515
  # Check feature flag
@@ -538,7 +548,7 @@ def profile():
538
548
  """User profile page."""
539
549
  # PostHog: Capture profile view
540
550
  with new_context():
541
- identify_context(current_user.email)
551
+ identify_context(str(current_user.id))
542
552
  capture("profile_viewed")
543
553
 
544
554
  return render_template("profile.html")
@@ -115,7 +115,7 @@ export default defineNuxtPlugin((nuxtApp) => {
115
115
  })
116
116
  ```
117
117
 
118
- The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers when `__add_tracing_headers` is configured in the PostHog initialization.
118
+ The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers when `tracing_headers` is configured in the PostHog initialization.
119
119
 
120
120
  **Important**: do not identify users on the server-side.
121
121
 
@@ -138,7 +138,7 @@ const handleSubmit = async () => {
138
138
  }
139
139
  ```
140
140
 
141
- The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `__add_tracing_headers` option in the PostHog initialization.
141
+ The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `tracing_headers` option in the PostHog initialization.
142
142
 
143
143
  **Important**: do not identify users on the server-side.
144
144
 
@@ -153,7 +153,7 @@ import { getHeader } from 'h3'
153
153
  export default defineEventHandler(async (event) => {
154
154
  const runtimeConfig = useRuntimeConfig()
155
155
 
156
- // Relies on __add_tracing_headers being set in the client-side SDK
156
+ // Relies on tracing_headers being set in the client-side SDK
157
157
  const sessionId = getHeader(event, 'x-posthog-session-id')
158
158
  const distinctId = getHeader(event, 'x-posthog-distinct-id')
159
159
 
@@ -711,6 +711,9 @@ export default defineNuxtPlugin((nuxtApp) => {
711
711
  const posthogClient = posthog.init(runtimeConfig.public.posthog.publicKey, {
712
712
  api_host: runtimeConfig.public.posthog.host,
713
713
  defaults: runtimeConfig.public.posthog.posthogDefaults as any,
714
+ // Automatically add X-POSTHOG-SESSION-ID and X-POSTHOG-DISTINCT-ID headers
715
+ // to same-origin requests so server-side events join the same session.
716
+ tracing_headers: [window.location.hostname],
714
717
  loaded: (posthog: PostHogInterface) => {
715
718
  if (import.meta.env.MODE === 'development') posthog.debug()
716
719
  },
@@ -772,7 +775,7 @@ export default defineEventHandler(async (event) => {
772
775
 
773
776
  const runtimeConfig = useRuntimeConfig()
774
777
 
775
- // Relies on __add_tracing_headers being set in the client-side SDK
778
+ // Relies on tracing_headers being set in the client-side SDK
776
779
  const sessionId = getHeader(event, 'x-posthog-session-id')
777
780
  const distinctId = getHeader(event, 'x-posthog-distinct-id')
778
781
 
@@ -844,7 +847,7 @@ export default defineEventHandler(async (event) => {
844
847
 
845
848
  const runtimeConfig = useRuntimeConfig()
846
849
 
847
- // Relies on __add_tracing_headers being set in the client-side SDK
850
+ // Relies on tracing_headers being set in the client-side SDK
848
851
  const sessionId = getHeader(event, 'x-posthog-session-id')
849
852
  const distinctId = getHeader(event, 'x-posthog-distinct-id')
850
853
 
@@ -117,7 +117,7 @@ export default defineNuxtConfig({
117
117
  host: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com',
118
118
  clientConfig: {
119
119
  capture_exceptions: true, // Enables automatic exception capture on the client side (Vue)
120
- __add_tracing_headers: ['localhost', 'yourdomain.com'], // Add your domain here
120
+ tracing_headers: ['localhost', 'yourdomain.com'], // Add your domain here
121
121
  },
122
122
  serverConfig: {
123
123
  enableExceptionAutocapture: true, // Enables automatic exception capture on the server side (Nitro)
@@ -138,7 +138,7 @@ export default defineNuxtConfig({
138
138
  - Client-side error tracking is enabled via `capture_exceptions: true`
139
139
  - Server-side error tracking is enabled via `enableExceptionAutocapture: true`
140
140
  - Source map uploads are configured for better error tracking
141
- - The `__add_tracing_headers` option automatically adds `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers to requests
141
+ - The `tracing_headers` option automatically adds `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers to requests
142
142
 
143
143
  **Important**: do not identify users on the server-side.
144
144
 
@@ -161,7 +161,7 @@ const handleSubmit = async () => {
161
161
  }
162
162
  ```
163
163
 
164
- The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `__add_tracing_headers` option in the PostHog configuration.
164
+ The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `tracing_headers` option in the PostHog configuration.
165
165
 
166
166
  **Important**: do not identify users on the server-side.
167
167
 
@@ -879,7 +879,7 @@ export default defineNuxtConfig({
879
879
  host: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', // Optional: defaults to https://us.i.posthog.com. Use https://eu.i.posthog.com for EU region
880
880
  clientConfig: {
881
881
  capture_exceptions: true, // Enables automatic exception capture on the client side (Vue)
882
- __add_tracing_headers: [ 'localhost', 'yourdomain.com' ], // Add your domain here
882
+ tracing_headers: [ 'localhost', 'yourdomain.com' ], // Add your domain here
883
883
  },
884
884
  serverConfig: {
885
885
  enableExceptionAutocapture: true, // Enables automatic exception capture on the server side (Nitro)
@@ -84,7 +84,7 @@ import { PostHogProvider } from '@posthog/react'
84
84
  posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN, {
85
85
  api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
86
86
  defaults: '2026-01-30',
87
- __add_tracing_headers: [ window.location.host, 'localhost' ],
87
+ tracing_headers: [ window.location.hostname ],
88
88
  });
89
89
 
90
90
  <PostHogProvider client={posthog}>
@@ -105,7 +105,7 @@ posthog?.capture('user_logged_in', {
105
105
  });
106
106
  ```
107
107
 
108
- The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `__add_tracing_headers` option in the PostHog initialization.
108
+ The session and distinct ID are automatically passed to the backend via the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers because we set the `tracing_headers` option in the PostHog initialization.
109
109
 
110
110
  **Important**: do not identify users on the server-side.
111
111
 
@@ -372,7 +372,7 @@ import { PostHogProvider } from '@posthog/react'
372
372
  posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN, {
373
373
  api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST,
374
374
  defaults: '2026-01-30',
375
- __add_tracing_headers: [ window.location.host, 'localhost' ],
375
+ tracing_headers: [ window.location.hostname ],
376
376
  });
377
377
 
378
378
 
@@ -117,9 +117,11 @@ end
117
117
  class User < ApplicationRecord
118
118
  has_secure_password
119
119
 
120
- # Called by posthog-rails for automatic user association in error reports
120
+ # Called by posthog-rails for automatic user association in error reports.
121
+ # The primary key, not the email — an email can change, which splits one
122
+ # person's history in two, and it is PII on every event's identity.
121
123
  def posthog_distinct_id
122
- email
124
+ id.to_s
123
125
  end
124
126
 
125
127
  def posthog_properties
@@ -218,7 +220,7 @@ This example includes the posthog-js snippet in the layout template to demonstra
218
220
 
219
221
  1. **posthog-js** (frontend) captures pageviews, clicks, and session replay
220
222
  2. **posthog-ruby + posthog-rails** (backend) captures business logic events, errors, and feature flag evaluations
221
- 3. **Shared distinct_id** — frontend and backend events are linked when the same `distinct_id` is used on both sides. Call `posthog.identify(user.email)` in posthog-js after login, matching the `posthog_distinct_id` used on the backend
223
+ 3. **Shared distinct_id** — frontend and backend events are linked when the same `distinct_id` is used on both sides. Call `posthog.identify(user.id.to_s)` in posthog-js after login, matching the `posthog_distinct_id` used on the backend
222
224
  4. **Session replay** lets you watch user sessions where errors occurred
223
225
 
224
226
  **Note:** Unlike the Django SDK, posthog-rails does not include a context middleware that reads `X-POSTHOG-SESSION-ID` or `X-POSTHOG-DISTINCT-ID` tracing headers. Frontend and backend events are correlated through the shared `distinct_id`.
@@ -584,8 +586,10 @@ class User < ApplicationRecord
584
586
  # Called by posthog-rails for automatic user association in error reports.
585
587
  # When auto_capture_exceptions and capture_user_context are enabled,
586
588
  # posthog-rails calls this method on current_user to get the distinct_id.
589
+ # The primary key, not the email: an email can change, which would split one
590
+ # person's history in two, and it is PII on every event's identity.
587
591
  def posthog_distinct_id
588
- email
592
+ id.to_s
589
593
  end
590
594
 
591
595
  # Helper used by controllers when calling PostHog.identify to set person properties.
@@ -122,16 +122,21 @@ This client is used in API routes to track server-side events.
122
122
 
123
123
  ### Server-side capture (routes/api/*)
124
124
 
125
- Server-side events include the client's `$session_id` so they appear in the same session in PostHog. The frontend sends it via a header:
125
+ Server-side events include the client's `$session_id` so they appear in the same session in PostHog. The `tracing_headers` option on the `PostHogProvider` adds the `X-POSTHOG-SESSION-ID` and `X-POSTHOG-DISTINCT-ID` headers to same-origin requests automatically, so the frontend fetch needs no PostHog headers of its own:
126
126
 
127
127
  ```typescript
128
- // Frontend: include session ID in API requests
128
+ // Client: tracing_headers is configured once on the PostHogProvider
129
+ options={{
130
+ api_host: '/ingest',
131
+ // ...
132
+ // Guarded for SSR, where `window` is undefined.
133
+ tracing_headers: typeof window !== 'undefined' ? [window.location.hostname] : [],
134
+ }}
135
+
136
+ // Frontend fetch — no manual header needed
129
137
  await fetch('/api/burrito/consider', {
130
138
  method: 'POST',
131
- headers: {
132
- 'Content-Type': 'application/json',
133
- 'X-PostHog-Session-Id': posthog.get_session_id() ?? '',
134
- },
139
+ headers: { 'Content-Type': 'application/json' },
135
140
  body: JSON.stringify({ ... }),
136
141
  })
137
142
  ```
@@ -352,11 +357,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
352
357
  password: string,
353
358
  ): Promise<boolean> => {
354
359
  try {
360
+ // The session and distinct ID are added automatically by the
361
+ // tracing_headers option configured on the PostHogProvider.
355
362
  const response = await fetch('/api/auth/login', {
356
363
  method: 'POST',
357
364
  headers: {
358
365
  'Content-Type': 'application/json',
359
- 'X-PostHog-Session-Id': posthog.get_session_id() ?? '',
360
366
  },
361
367
  body: JSON.stringify({ username, password }),
362
368
  })
@@ -509,6 +515,11 @@ function RootDocument({ children }: { children: React.ReactNode }) {
509
515
  defaults: '2025-05-24',
510
516
  capture_exceptions: true,
511
517
  debug: import.meta.env.DEV,
518
+ // Automatically add X-POSTHOG-SESSION-ID and X-POSTHOG-DISTINCT-ID
519
+ // headers to same-origin requests so server-side events join the
520
+ // same session. Guarded for SSR, where `window` is undefined.
521
+ tracing_headers:
522
+ typeof window !== 'undefined' ? [window.location.hostname] : [],
512
523
  }}
513
524
  >
514
525
  <AuthProvider>
@@ -704,11 +715,12 @@ function BurritoPage() {
704
715
  setHasConsidered(true)
705
716
  setTimeout(() => setHasConsidered(false), 2000)
706
717
 
718
+ // The session and distinct ID are added automatically by the
719
+ // tracing_headers option configured on the PostHogProvider.
707
720
  await fetch('/api/burrito/consider', {
708
721
  method: 'POST',
709
722
  headers: {
710
723
  'Content-Type': 'application/json',
711
- 'X-PostHog-Session-Id': posthog.get_session_id() ?? '',
712
724
  },
713
725
  body: JSON.stringify({
714
726
  username: user.username,
@@ -1,3 +1,9 @@
1
+ > AI agents: this is one page from PostHog's docs. Full index of Markdown docs for LLMs: https://posthog.com/llms.txt
2
+
3
+ # Android - Docs
4
+
5
+ Copy page
6
+
1
7
  # Android - Docs
2
8
 
3
9
  It uses an internal queue to make calls fast and non-blocking. It also batches requests and flushes asynchronously, making it perfect to use in any part of your mobile app.
@@ -566,6 +572,41 @@ PostHog.captureFeatureView("flag-key", flagVariant = "variant-key")
566
572
  PostHog.captureFeatureInteraction("flag-key", flagVariant = "variant-key")
567
573
  ```
568
574
 
575
+ ### Bootstrapping flags
576
+
577
+ Since there is a delay between initializing PostHog and fetching feature flags, feature flags are not always available immediately. This makes them unusable if you want to do something like redirecting a user to a different page based on a feature flag.
578
+
579
+ To have your feature flags available immediately, you can initialize PostHog with precomputed values until it has had a chance to fetch them. This is called bootstrapping. After the SDK fetches feature flags from PostHog, it will use those flag values instead of bootstrapped ones.
580
+
581
+ Set `config.bootstrap` before calling `setup()` to seed identity and flag values before the first `/flags` response (requires Android SDK `3.55.0`+):
582
+
583
+ Kotlin
584
+
585
+ PostHog AI
586
+
587
+ ```kotlin
588
+ import com.posthog.PostHogBootstrapConfig
589
+ val config = PostHogAndroidConfig(apiKey = POSTHOG_API_KEY, host = POSTHOG_HOST)
590
+ config.bootstrap = PostHogBootstrapConfig(
591
+ distinctId = "distinct_id_of_your_user",
592
+ isIdentifiedId = true,
593
+ featureFlags = mapOf(
594
+ "flag-1" to true,
595
+ "variant-flag" to "control"
596
+ )
597
+ )
598
+ PostHogAndroid.setup(this, config)
599
+ ```
600
+
601
+ - **Bootstrapped identity applies during setup.** On a fresh install, setting it before `setup()` means events captured synchronously during initialization (like `Application Installed`) carry your distinct ID instead of the SDK-generated UUID.
602
+ - An **anonymous** bootstrap (`isIdentifiedId: false`, the default) seeds the anonymous ID only when none is persisted yet. Once an anonymous ID exists on disk, or the person has been identified, the SDK ignores it.
603
+ - An **identified** bootstrap (`isIdentifiedId: true`) is for a signed-in identity available to your app (for example, from a backend session token). On a fresh install, it seeds the distinct ID, marks the person identified, and generates a separate device ID. On a returning install, a matching anonymous ID is marked identified without emitting `$identify`; a different anonymous ID is merged via `identify()` when person profiles are enabled. This emits `$identify` unless capturing is opted out. A different, already-identified person is left untouched.
604
+ - **Bootstrapped flags are served until the first `/flags` response, then replaced.** A complete `/flags` response takes over entirely, so bootstrapped-only keys don't persist past it. Only *enabled* flags are seeded: a `true` boolean or a non-empty variant string. A `false` or empty value is dropped, matching posthog-js. Seed payloads with the separate `featureFlagPayloads` option. Flag values and payloads must be JSON-serializable, or they're dropped. Bootstrapped flags are cleared on `reset()`.
605
+
606
+ The feature-flags-loaded signal fires as soon as bootstrapped flags are applied, so startup logic can read them immediately. These SDKs don't support the `sessionID` bootstrap option. When person profiles are set to `never`, the SDK preserves a different anonymous identity instead of merging it into an identified bootstrap.
607
+
608
+ See the [SDK bootstrapping guide](/docs/libraries/bootstrapping.md) for the cross-SDK overview.
609
+
569
610
  ## Experiments (A/B tests)
570
611
 
571
612
  Since [experiments](/docs/experiments/start-here.md) use feature flags, the code for running an experiment is very similar to the feature flags code:
@@ -750,6 +791,7 @@ val config = PostHogAndroidConfig(
750
791
  | errorTrackingConfig | PostHogErrorTrackingConfig() | Configures error tracking. autoCapture defaults to false; set it to true to autocapture uncaught exceptions when project settings also enable error tracking. |
751
792
  | surveys | false | Internal/experimental native Android survey support. Native Android survey UI is not fully supported or documented yet. |
752
793
  | surveysConfig | PostHogSurveysConfig() | Internal/experimental survey display delegate configuration, primarily for hybrid SDKs. |
794
+ | bootstrap | null | Seeds identity (distinctId, isIdentifiedId) and feature-flag state (featureFlags, featureFlagPayloads) before the first /flags response. Bootstrapped identity applies to the first session; only enabled flags are served, until the first /flags response replaces them. See [SDK bootstrapping](/docs/libraries/bootstrapping.md#behavior-on-mobile-sdks). |
753
795
 
754
796
  ### Event filtering with `beforeSend`
755
797
 
@@ -792,6 +834,10 @@ config.addBeforeSend { event ->
792
834
  }
793
835
  ```
794
836
 
837
+ ## Push notifications
838
+
839
+ The Android SDK can register a device for [Workflows](/docs/workflows.md) push notifications and capture when a user opens one. For setup, including automatic and manual registration, capturing opens, opting out, and identity verification, see [Push notifications](/docs/workflows/push-notifications.md).
840
+
795
841
  ## FAQ
796
842
 
797
843
  ## What Android API level is required?
@@ -802,10 +848,6 @@ The Android SDK supports Android API 23 and newer.
802
848
 
803
849
  Usually, no. The SDK declares `android.permission.INTERNET` and `android.permission.ACCESS_NETWORK_STATE`, and Android's manifest merger adds them to your app. The SDK does not declare or require an Android `Service`.
804
850
 
805
- ### Community questions
806
-
807
- Ask a question
808
-
809
851
  ### Was this page useful?
810
852
 
811
853
  HelpfulCould be better