vybekiit 0.7.33 → 0.7.35
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.
- package/dist/bin.js +818 -92
- package/dist/global-skills/eas-app-stores/SKILL.md +2 -2
- package/dist/global-skills/eas-hosting/SKILL.md +2 -2
- package/dist/global-skills/eas-observe/SKILL.md +7 -15
- package/dist/global-skills/eas-observe/references/queries.md +51 -10
- package/dist/global-skills/eas-observe/references/setup.md +60 -7
- package/dist/global-skills/eas-simulator/SKILL.md +2 -2
- package/dist/global-skills/eas-simulator/references/run-your-app.md +2 -0
- package/dist/global-skills/eas-update/SKILL.md +2 -2
- package/dist/global-skills/eas-update-insights/SKILL.md +2 -2
- package/dist/global-skills/eas-workflows/SKILL.md +2 -2
- package/dist/global-skills/expo-animation/SKILL.md +2 -2
- package/dist/global-skills/expo-app-clip/SKILL.md +2 -2
- package/dist/global-skills/expo-brownfield/SKILL.md +2 -2
- package/dist/global-skills/expo-data-fetching/SKILL.md +2 -2
- package/dist/global-skills/expo-design-system/SKILL.md +2 -2
- package/dist/global-skills/expo-dev-client/SKILL.md +4 -2
- package/dist/global-skills/expo-dom/SKILL.md +2 -2
- package/dist/global-skills/expo-examples/SKILL.md +2 -2
- package/dist/global-skills/expo-migrate-module/SKILL.md +2 -2
- package/dist/global-skills/expo-module/SKILL.md +2 -2
- package/dist/global-skills/expo-native-ui/SKILL.md +2 -2
- package/dist/global-skills/expo-overview/SKILL.md +9 -4
- package/dist/global-skills/expo-overview/references/launch-without-dev-menu.md +24 -0
- package/dist/global-skills/expo-project-structure/SKILL.md +2 -2
- package/dist/global-skills/expo-router/SKILL.md +2 -2
- package/dist/global-skills/expo-ui/SKILL.md +2 -2
- package/dist/global-skills/expo-upgrade/SKILL.md +2 -2
- package/dist/global-skills/expo-web-to-native/SKILL.md +2 -2
- package/dist/global-skills/expo-web-to-native/references/verify-on-device.md +1 -1
- package/dist/global-skills/firebase-app-hosting-basics/SKILL.md +16 -3
- package/dist/global-skills/firebase-app-hosting-basics/references/cli_commands.md +10 -12
- package/dist/global-skills/firebase-app-hosting-basics/references/configuration.md +2 -1
- package/dist/global-skills/firebase-basics/SKILL.md +6 -4
- package/dist/global-skills/firebase-basics/references/web_setup.md +3 -3
- package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +81 -333
- package/dist/global-skills/instrument-feature-flags/references/android.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/api.md +17 -13
- package/dist/global-skills/instrument-feature-flags/references/best-practices.md +35 -35
- package/dist/global-skills/instrument-feature-flags/references/django.md +120 -72
- package/dist/global-skills/instrument-feature-flags/references/dotnet.md +48 -102
- package/dist/global-skills/instrument-feature-flags/references/elixir.md +4 -10
- package/dist/global-skills/instrument-feature-flags/references/flask.md +55 -39
- package/dist/global-skills/instrument-feature-flags/references/flutter.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/go.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/ios.md +19 -13
- package/dist/global-skills/instrument-feature-flags/references/java.md +4 -12
- package/dist/global-skills/instrument-feature-flags/references/laravel.md +18 -16
- package/dist/global-skills/instrument-feature-flags/references/next-js.md +44 -54
- package/dist/global-skills/instrument-feature-flags/references/nodejs.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/php.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/python.md +22 -14
- package/dist/global-skills/instrument-feature-flags/references/react-native.md +18 -13
- package/dist/global-skills/instrument-feature-flags/references/react.md +21 -14
- package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +31 -68
- package/dist/global-skills/instrument-feature-flags/references/ruby.md +21 -13
- package/dist/global-skills/instrument-feature-flags/references/rust.md +10 -34
- package/dist/global-skills/instrument-feature-flags/references/usage.md +94 -114
- package/dist/global-skills/instrument-feature-flags/references/web.md +21 -13
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-android.md +7 -7
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-expo.md +2 -2
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-fastapi.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-flask.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-laravel.md +2 -2
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-php.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-python.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby.md +1 -1
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-swift.md +4 -4
- package/dist/global-skills/instrument-product-analytics/references/android.md +64 -109
- package/dist/global-skills/instrument-product-analytics/references/angular.md +32 -28
- package/dist/global-skills/instrument-product-analytics/references/astro.md +29 -34
- package/dist/global-skills/instrument-product-analytics/references/configuration.md +27 -42
- package/dist/global-skills/instrument-product-analytics/references/django.md +120 -72
- package/dist/global-skills/instrument-product-analytics/references/dotnet.md +48 -102
- package/dist/global-skills/instrument-product-analytics/references/elixir.md +25 -50
- package/dist/global-skills/instrument-product-analytics/references/flask.md +55 -39
- package/dist/global-skills/instrument-product-analytics/references/flutter.md +94 -96
- package/dist/global-skills/instrument-product-analytics/references/go.md +39 -77
- package/dist/global-skills/instrument-product-analytics/references/identify-users.md +24 -26
- package/dist/global-skills/instrument-product-analytics/references/ios.md +22 -22
- package/dist/global-skills/instrument-product-analytics/references/laravel.md +18 -16
- package/dist/global-skills/instrument-product-analytics/references/next-js.md +44 -54
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +32 -34
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +36 -36
- package/dist/global-skills/instrument-product-analytics/references/php.md +42 -87
- package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +15 -12
- package/dist/global-skills/instrument-product-analytics/references/python.md +106 -154
- package/dist/global-skills/instrument-product-analytics/references/react-native.md +97 -176
- package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +29 -40
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +29 -38
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +29 -40
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +32 -37
- package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +31 -68
- package/dist/global-skills/instrument-product-analytics/references/ruby.md +40 -96
- package/dist/global-skills/instrument-product-analytics/references/svelte.md +34 -34
- package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +19 -19
- package/dist/global-skills/instrument-product-analytics/references/usage.md +94 -114
- package/dist/global-skills/instrument-product-analytics/references/vue-js.md +33 -45
- package/dist/global-skills/manifest.json +2 -1
- package/dist/global-skills/mongodb-search-and-ai/SKILL.md +40 -22
- package/dist/global-skills/mongodb-search-and-ai/references/automated-embedding.md +8 -2
- package/dist/global-skills/mongodb-search-and-ai/references/quick-start.md +725 -0
- package/dist/global-skills/mongodb-search-and-ai/scripts/quickstart_complete.py +386 -0
- package/dist/global-skills/neon/SKILL.md +15 -10
- package/dist/global-skills/neon/references/claimable-neon.md +2 -0
- package/dist/global-skills/neon-functions/SKILL.md +12 -11
- package/dist/global-skills/neon-functions/references/sse.md +2 -2
- package/dist/global-skills/neon-object-storage/SKILL.md +5 -4
- package/dist/global-skills/neon-postgres/SKILL.md +4 -1
- package/dist/global-skills/neon-realtime/SKILL.md +207 -0
- package/dist/global-skills/neon-realtime/references/mutations.md +743 -0
- package/dist/global-skills/neon-realtime/references/queries.md +509 -0
- package/dist/global-skills/neon-realtime/references/reactivity.md +407 -0
- package/dist/global-skills/neon-realtime/references/ssr.md +695 -0
- package/dist/global-skills/neon-realtime/references/subscribing.md +485 -0
- package/dist/global-skills/resend/SKILL.md +4 -2
- package/dist/global-skills/resend/references/inboxes.md +377 -0
- package/dist/global-skills/resend/references/webhooks.md +9 -0
- package/dist/global-skills/stripe-best-practices/SKILL.md +1 -1
- package/dist/global-skills/stripe-best-practices/references/connect.md +1 -1
- package/dist/global-skills/stripe-best-practices/references/security.md +9 -9
- package/dist/global-skills/vybekiitReferences/backend/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/backend/agent/goal-routes.json +303 -18
- package/dist/global-skills/vybekiitReferences/extension/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/extension/agent/goal-routes.json +352 -18
- package/dist/global-skills/vybekiitReferences/mobile/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/mobile/agent/goal-routes.json +413 -22
- package/dist/global-skills/vybekiitReferences/spa/AGENTS.md +1 -1
- package/dist/global-skills/vybekiitReferences/spa/agent/goal-routes.json +391 -21
- package/dist/global-skills/vybekiitReferences/web/AGENTS.md +14 -2
- package/dist/global-skills/vybekiitReferences/web/agent/goal-routes.json +490 -32
- package/package.json +8 -8
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
# Android Feature Flags installation
|
|
4
4
|
|
|
5
|
+
Canonical URL: https://posthog.com/docs/feature-flags/installation/android
|
|
6
|
+
|
|
7
|
+
> **Cloud region:** This page uses US Cloud hosts. For an EU Cloud project, use `https://eu.i.posthog.com` instead of `https://us.i.posthog.com` (ingestion host).
|
|
8
|
+
|
|
9
|
+
## On this page
|
|
10
|
+
|
|
11
|
+
- [Install the dependency](#install-the-dependency)
|
|
12
|
+
- [Configure PostHog](#configure-posthog)
|
|
13
|
+
- [Send events](#send-events)
|
|
14
|
+
- [Evaluate boolean feature flags](#evaluate-boolean-feature-flags)
|
|
15
|
+
- [Evaluate multivariate feature flags](#evaluate-multivariate-feature-flags)
|
|
16
|
+
- [Running experiments](#running-experiments)
|
|
17
|
+
- [Next steps](#next-steps)
|
|
18
|
+
|
|
5
19
|
1. 1
|
|
6
20
|
|
|
7
21
|
## Install the dependency
|
|
@@ -128,16 +142,8 @@
|
|
|
128
142
|
|
|
129
143
|
| Resource | Description |
|
|
130
144
|
| --- | --- |
|
|
131
|
-
| [Creating a feature flag](/docs/feature-flags/creating-feature-flags.md) | How to create a feature flag in PostHog |
|
|
132
|
-
| [Adding feature flag code](/docs/feature-flags/adding-feature-flag-code.md) | How to check flags in your code for all platforms |
|
|
133
|
-
| [Framework-specific guides](/docs/feature-flags/tutorials.md#framework-guides) | Setup guides for React Native, Next.js, Flutter, and other frameworks |
|
|
134
|
-
| [How to do a phased rollout](/tutorials/phased-rollout.md) | Gradually roll out features to minimize risk |
|
|
135
|
-
| [More tutorials](/docs/feature-flags/tutorials.md) | Other real-world examples and use cases |
|
|
136
|
-
|
|
137
|
-
### Still have questions?
|
|
138
|
-
|
|
139
|
-
Ask PostHog AI
|
|
140
|
-
|
|
141
|
-
### Was this page useful?
|
|
142
|
-
|
|
143
|
-
HelpfulCould be better
|
|
145
|
+
| [Creating a feature flag](https://posthog.com/docs/feature-flags/creating-feature-flags.md) | How to create a feature flag in PostHog |
|
|
146
|
+
| [Adding feature flag code](https://posthog.com/docs/feature-flags/adding-feature-flag-code.md) | How to check flags in your code for all platforms |
|
|
147
|
+
| [Framework-specific guides](https://posthog.com/docs/feature-flags/tutorials.md#framework-guides) | Setup guides for React Native, Next.js, Flutter, and other frameworks |
|
|
148
|
+
| [How to do a phased rollout](https://posthog.com/tutorials/phased-rollout.md) | Gradually roll out features to minimize risk |
|
|
149
|
+
| [More tutorials](https://posthog.com/docs/feature-flags/tutorials.md) | Other real-world examples and use cases |
|
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# API Feature Flags installation
|
|
4
4
|
|
|
5
|
+
Canonical URL: https://posthog.com/docs/feature-flags/installation/api
|
|
6
|
+
|
|
7
|
+
> **Cloud region:** This page uses US Cloud hosts. For an EU Cloud project, use `https://eu.i.posthog.com` instead of `https://us.i.posthog.com` (ingestion host).
|
|
8
|
+
|
|
9
|
+
## On this page
|
|
10
|
+
|
|
11
|
+
- [Evaluate the feature flag value using flags](#evaluate-the-feature-flag-value-using-flags)
|
|
12
|
+
- [Include feature flag information when capturing events](#include-feature-flag-information-when-capturing-events)
|
|
13
|
+
- [Send a $feature_flag_called event](#send-a-feature_flag_called-event)
|
|
14
|
+
- [Running experiments](#running-experiments)
|
|
15
|
+
- [Next steps](#next-steps)
|
|
16
|
+
|
|
5
17
|
1. 1
|
|
6
18
|
|
|
7
19
|
## Evaluate the feature flag value using flags
|
|
@@ -178,16 +190,8 @@
|
|
|
178
190
|
|
|
179
191
|
| Resource | Description |
|
|
180
192
|
| --- | --- |
|
|
181
|
-
| [Creating a feature flag](/docs/feature-flags/creating-feature-flags.md) | How to create a feature flag in PostHog |
|
|
182
|
-
| [Adding feature flag code](/docs/feature-flags/adding-feature-flag-code.md) | How to check flags in your code for all platforms |
|
|
183
|
-
| [Framework-specific guides](/docs/feature-flags/tutorials.md#framework-guides) | Setup guides for React Native, Next.js, Flutter, and other frameworks |
|
|
184
|
-
| [How to do a phased rollout](/tutorials/phased-rollout.md) | Gradually roll out features to minimize risk |
|
|
185
|
-
| [More tutorials](/docs/feature-flags/tutorials.md) | Other real-world examples and use cases |
|
|
186
|
-
|
|
187
|
-
### Still have questions?
|
|
188
|
-
|
|
189
|
-
Ask PostHog AI
|
|
190
|
-
|
|
191
|
-
### Was this page useful?
|
|
192
|
-
|
|
193
|
-
HelpfulCould be better
|
|
193
|
+
| [Creating a feature flag](https://posthog.com/docs/feature-flags/creating-feature-flags.md) | How to create a feature flag in PostHog |
|
|
194
|
+
| [Adding feature flag code](https://posthog.com/docs/feature-flags/adding-feature-flag-code.md) | How to check flags in your code for all platforms |
|
|
195
|
+
| [Framework-specific guides](https://posthog.com/docs/feature-flags/tutorials.md#framework-guides) | Setup guides for React Native, Next.js, Flutter, and other frameworks |
|
|
196
|
+
| [How to do a phased rollout](https://posthog.com/tutorials/phased-rollout.md) | Gradually roll out features to minimize risk |
|
|
197
|
+
| [More tutorials](https://posthog.com/docs/feature-flags/tutorials.md) | Other real-world examples and use cases |
|
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
# Best practices for production-ready flags
|
|
4
4
|
|
|
5
|
+
Canonical URL: https://posthog.com/docs/feature-flags/best-practices
|
|
6
|
+
|
|
7
|
+
## On this page
|
|
8
|
+
|
|
9
|
+
- [Checklist](#checklist)
|
|
10
|
+
- [Flags are pure functions](#flags-are-pure-functions)
|
|
11
|
+
- [Unexpected results are almost always input problems](#unexpected-results-are-almost-always-input-problems)
|
|
12
|
+
- [Resolve identity before evaluating flags](#resolve-identity-before-evaluating-flags)
|
|
13
|
+
- [Evaluation architecture](#evaluation-architecture)
|
|
14
|
+
- [Flag hygiene](#flag-hygiene)
|
|
15
|
+
- [Further reading](#further-reading)
|
|
16
|
+
|
|
5
17
|
## Checklist
|
|
6
18
|
|
|
7
19
|
- [Call `identify()` before evaluating flags](#resolve-identity-before-evaluating-flags) – the hash uses the wrong ID otherwise. This is the most common input problem.
|
|
8
20
|
- [Evaluate flags server-side with local evaluation](#server-side-local-evaluation-is-the-recommended-default) – explicit inputs, your data right there, no workarounds.
|
|
9
|
-
- [Bootstrap client-side flags](#have-the-value-before-you-need-it) – client-side evaluation is async. [Bootstrap](/docs/feature-flags/bootstrapping.md) to eliminate the gap.
|
|
21
|
+
- [Bootstrap client-side flags](#have-the-value-before-you-need-it) – client-side evaluation is async. [Bootstrap](https://posthog.com/docs/feature-flags/bootstrapping.md) to eliminate the gap.
|
|
10
22
|
- [Handle `undefined` explicitly](#undefined-is-not-false) – it means "not evaluated yet," not `false`.
|
|
11
23
|
- [Evaluate once, record the result](#evaluate-once-not-continuously) – a flag is a one-time signal. Re-evaluate only on meaningful state changes.
|
|
12
24
|
- [Evaluate where the data lives](#evaluate-where-the-data-lives) – if the data is on your server, evaluate there.
|
|
@@ -58,13 +70,13 @@ So when a flag returns something you didn't expect, **the flag is fine, the prob
|
|
|
58
70
|
|
|
59
71
|
If you keep running into flag issues and they're not [incidents](https://status.posthog.com), the conversation isn't about PostHog's flag behavior – it's about how your application coordinates the data that flags depend on. That's an engineering conversation about identity flows, property syncing, and evaluation architecture. No single config tweak fixes it.
|
|
60
72
|
|
|
61
|
-
We're here to help with that – this guide, [PostHog AI](/docs/feature-flags/manage-flags-ai.md), and [professional services](https://posthog.com/professional-services) all exist for exactly this. But the starting point is always the same: **look at the inputs.**
|
|
73
|
+
We're here to help with that – this guide, [PostHog AI](https://posthog.com/docs/feature-flags/manage-flags-ai.md), and [professional services](https://posthog.com/professional-services) all exist for exactly this. But the starting point is always the same: **look at the inputs.**
|
|
62
74
|
|
|
63
75
|
When something goes wrong, in order of likelihood:
|
|
64
76
|
|
|
65
|
-
1. **Input problems** (most common). Wrong distinct ID, missing properties, changed flag definition. PostHog gives you tools to get the coordination right – [bootstrapping](/docs/feature-flags/bootstrapping.md), [property overrides](/docs/feature-flags/property-overrides.md), [server-side evaluation](/docs/feature-flags/local-evaluation.md).
|
|
77
|
+
1. **Input problems** (most common). Wrong distinct ID, missing properties, changed flag definition. PostHog gives you tools to get the coordination right – [bootstrapping](https://posthog.com/docs/feature-flags/bootstrapping.md), [property overrides](https://posthog.com/docs/feature-flags/property-overrides.md), [server-side evaluation](https://posthog.com/docs/feature-flags/local-evaluation.md).
|
|
66
78
|
2. **Output problems.** The flag returned the right value but your code misread it – `undefined` treated as `false`, no handling for the loading gap, evaluating repeatedly instead of recording the result.
|
|
67
|
-
3. **Actual incidents.** Check [status.posthog.com](https://status.posthog.com). If nothing there, it's #1 or #2. And even here: with [server-side local evaluation](/docs/feature-flags/local-evaluation.md), the SDK evaluates against cached flag definitions locally. PostHog being unreachable doesn't affect flags that are already cached. Add per-flag safe defaults and even a cold start during an outage returns usable values. An incident only breaks your flags if your implementation depends on PostHog being available at request time – which is itself an implementation gap you can close.
|
|
79
|
+
3. **Actual incidents.** Check [status.posthog.com](https://status.posthog.com). If nothing there, it's #1 or #2. And even here: with [server-side local evaluation](https://posthog.com/docs/feature-flags/local-evaluation.md), the SDK evaluates against cached flag definitions locally. PostHog being unreachable doesn't affect flags that are already cached. Add per-flag safe defaults and even a cold start during an outage returns usable values. An incident only breaks your flags if your implementation depends on PostHog being available at request time – which is itself an implementation gap you can close.
|
|
68
80
|
|
|
69
81
|
## Resolve identity before evaluating flags
|
|
70
82
|
|
|
@@ -72,17 +84,17 @@ Identity is the most common input problem. The hash takes two inputs: the flag k
|
|
|
72
84
|
|
|
73
85
|
If you call `identify()` after a flag has already been evaluated, the flag likely used the anonymous ID. The hash produced one result. After `identify()`, the distinct ID changes, the hash changes, and the next evaluation returns a different variant. You see a "flip" – but it's because the input changed.
|
|
74
86
|
|
|
75
|
-
Call [`identify()`](/docs/product-analytics/identify.md) before any flag evaluation in auth flows. If you can't guarantee that timing, [bootstrap](/docs/feature-flags/bootstrapping.md) with the stable ID at init so the distinct ID is correct from the first millisecond. See [keeping flag evaluations stable](/docs/feature-flags/stable-identity-for-flags.md) for the full picture.
|
|
87
|
+
Call [`identify()`](https://posthog.com/docs/product-analytics/identify.md) before any flag evaluation in auth flows. If you can't guarantee that timing, [bootstrap](https://posthog.com/docs/feature-flags/bootstrapping.md) with the stable ID at init so the distinct ID is correct from the first millisecond. See [keeping flag evaluations stable](https://posthog.com/docs/feature-flags/stable-identity-for-flags.md) for the full picture.
|
|
76
88
|
|
|
77
89
|
**SPA-specific timing.** In single-page applications, `identify()` and event captures often fire from different components during the same navigation in unpredictable order. The SDK updates the `distinct_id` synchronously when `identify()` runs, but if `capture()` was called first in the same execution frame, that event uses the anonymous ID. The fix: call `identify()` before the navigation that mounts post-auth components – in Vue, in `beforeEach` before `next()`; in React, before `navigate()`, not in a `useEffect` inside the target route.
|
|
78
90
|
|
|
79
91
|
### Don't rely on flag persistence to fix identity gaps
|
|
80
92
|
|
|
81
|
-
If you've enabled [experience continuity](/docs/feature-flags/creating-feature-flags.md#persisting-feature-flags-across-authentication-steps-optional) (flag persistence across authentication), consider what that's telling you: the distinct ID is changing during your session, and you need PostHog to paper over it.
|
|
93
|
+
If you've enabled [experience continuity](https://posthog.com/docs/feature-flags/creating-feature-flags.md#persisting-feature-flags-across-authentication-steps-optional) (flag persistence across authentication), consider what that's telling you: the distinct ID is changing during your session, and you need PostHog to paper over it.
|
|
82
94
|
|
|
83
|
-
That comes at a cost. Experience continuity couples flag evaluation with database writes – every evaluation reads and writes to the DB to persist the result. This mixes two concerns (evaluation and storage) that should be separate, and it's the source of [known bugs](https://github.com/PostHog/posthog-js/issues/2623) where values can still change after `identify()`. It also means no support for [local evaluation](/docs/feature-flags/local-evaluation.md) and slower flag responses.
|
|
95
|
+
That comes at a cost. Experience continuity couples flag evaluation with database writes – every evaluation reads and writes to the DB to persist the result. This mixes two concerns (evaluation and storage) that should be separate, and it's the source of [known bugs](https://github.com/PostHog/posthog-js/issues/2623) where values can still change after `identify()`. It also means no support for [local evaluation](https://posthog.com/docs/feature-flags/local-evaluation.md) and slower flag responses.
|
|
84
96
|
|
|
85
|
-
The better fix is to make persistence unnecessary. Use [device bucketing](/docs/feature-flags/device-bucketing.md) for single-device consistency, or design your identity flow so the distinct ID [never changes](/docs/feature-flags/stable-identity-for-flags.md). If you need experience continuity today, treat it as a migration path toward proper [identity resolution](/docs/product-analytics/identity-resolution.md), not a permanent solution. The identity gap it papers over is the root cause of the most common flag issues – closing that gap eliminates the need for persistence entirely.
|
|
97
|
+
The better fix is to make persistence unnecessary. Use [device bucketing](https://posthog.com/docs/feature-flags/device-bucketing.md) for single-device consistency, or design your identity flow so the distinct ID [never changes](https://posthog.com/docs/feature-flags/stable-identity-for-flags.md). If you need experience continuity today, treat it as a migration path toward proper [identity resolution](https://posthog.com/docs/product-analytics/identity-resolution.md), not a permanent solution. The identity gap it papers over is the root cause of the most common flag issues – closing that gap eliminates the need for persistence entirely.
|
|
86
98
|
|
|
87
99
|
## Evaluation architecture
|
|
88
100
|
|
|
@@ -103,13 +115,13 @@ If you target a flag on `plan_type: "pro"`, your app originally told PostHog thi
|
|
|
103
115
|
|
|
104
116
|
If you evaluate client-side instead, the SDK needs to fetch that property from PostHog's servers – a round-trip to look up what you originally sent it. Any flag check before that completes evaluates against incomplete data.
|
|
105
117
|
|
|
106
|
-
If you must evaluate client-side, use [`setPersonPropertiesForFlags()`](/docs/feature-flags/property-overrides.md#manual-overrides-with-setpersonpropertiesforflags) to set properties locally before evaluation. This avoids the round-trip when you already have the data in the browser.
|
|
118
|
+
If you must evaluate client-side, use [`setPersonPropertiesForFlags()`](https://posthog.com/docs/feature-flags/property-overrides.md#manual-overrides-with-setpersonpropertiesforflags) to set properties locally before evaluation. This avoids the round-trip when you already have the data in the browser.
|
|
107
119
|
|
|
108
120
|
Property targeting is fine – just understand that the further the evaluation is from the data, the more async complexity you take on.
|
|
109
121
|
|
|
110
122
|
### Server-side local evaluation is the recommended default
|
|
111
123
|
|
|
112
|
-
[Server-side local evaluation](/docs/feature-flags/local-evaluation.md) is where the pure function model is fully legible:
|
|
124
|
+
[Server-side local evaluation](https://posthog.com/docs/feature-flags/local-evaluation.md) is where the pure function model is fully legible:
|
|
113
125
|
|
|
114
126
|
- **All inputs are explicit.** You pass the distinct ID and properties directly. When something's wrong, you log what you passed.
|
|
115
127
|
- **Your data is right there.** User plan, account type, permissions – it's in your database at request time. No syncing, no fetching.
|
|
@@ -121,7 +133,7 @@ Client-side evaluation is right when you need properties only available in the b
|
|
|
121
133
|
|
|
122
134
|
Client-side flag evaluation is async – the SDK needs to fetch values from PostHog. Any flag check before that completes returns `undefined`, not `false`.
|
|
123
135
|
|
|
124
|
-
**[Bootstrap](/docs/feature-flags/bootstrapping.md) is the fix.** Evaluate flags server-side and pass values to the client at init. The value exists before the page renders – no gap, no flicker.
|
|
136
|
+
**[Bootstrap](https://posthog.com/docs/feature-flags/bootstrapping.md) is the fix.** Evaluate flags server-side and pass values to the client at init. The value exists before the page renders – no gap, no flicker.
|
|
125
137
|
|
|
126
138
|
If you can't bootstrap, use `onFeatureFlags()` to wait. This means you will need a loading state (spinner, skeleton) until flags arrive – it prevents showing the wrong variant but doesn't prevent a delay.
|
|
127
139
|
|
|
@@ -129,8 +141,6 @@ If you can't bootstrap, use `onFeatureFlags()` to wait. This means you will need
|
|
|
129
141
|
|
|
130
142
|
`posthog.getFeatureFlag()` returns `undefined` before flags load. That means "not evaluated yet," not "flag is off."
|
|
131
143
|
|
|
132
|
-
JavaScript
|
|
133
|
-
|
|
134
144
|
```javascript
|
|
135
145
|
// Returns undefined before flags load – not false
|
|
136
146
|
if (posthog.getFeatureFlag('my-experiment') === 'test') {
|
|
@@ -138,9 +148,9 @@ if (posthog.getFeatureFlag('my-experiment') === 'test') {
|
|
|
138
148
|
}
|
|
139
149
|
```
|
|
140
150
|
|
|
141
|
-
Handle it with [bootstrap](/docs/feature-flags/bootstrapping.md) (preferred) or `onFeatureFlags()` (adds a loading state). You can check the current identity with `posthog.get_distinct_id()`.
|
|
151
|
+
Handle it with [bootstrap](https://posthog.com/docs/feature-flags/bootstrapping.md) (preferred) or `onFeatureFlags()` (adds a loading state). You can check the current identity with `posthog.get_distinct_id()`.
|
|
142
152
|
|
|
143
|
-
The "not loaded yet" return value varies across SDKs – some return `undefined`/`nil`/`None`, others return `false` or a `defaultValue` you provide. Don't assume that a falsy return means the flag is off. Check your SDK's documentation for the exact return type of `getFeatureFlag()` and `isFeatureEnabled()` when flags haven't loaded, and handle that state explicitly. If your goal is to programmatically check whether a flag exists at all, use the [Feature Flags API](/docs/api/feature-flags.md) to query flag definitions directly.
|
|
153
|
+
The "not loaded yet" return value varies across SDKs – some return `undefined`/`nil`/`None`, others return `false` or a `defaultValue` you provide. Don't assume that a falsy return means the flag is off. Check your SDK's documentation for the exact return type of `getFeatureFlag()` and `isFeatureEnabled()` when flags haven't loaded, and handle that state explicitly. If your goal is to programmatically check whether a flag exists at all, use the [Feature Flags API](https://posthog.com/docs/api/feature-flags.md) to query flag definitions directly.
|
|
144
154
|
|
|
145
155
|
## Flag hygiene
|
|
146
156
|
|
|
@@ -148,7 +158,7 @@ Flags are infrastructure. Like any infrastructure, they accumulate cost when lef
|
|
|
148
158
|
|
|
149
159
|
### Choose a flag type intentionally
|
|
150
160
|
|
|
151
|
-
Every flag in PostHog is configured as client-side, server-side, or both via [evaluation contexts](/docs/feature-flags/evaluation-contexts.md). New flags default to "server and client" – this exists for backwards compatibility (it's how all flags worked before we added evaluation contexts) and to avoid blocking users who haven't thought about their implementation yet. It's a safe starting point, not a recommendation.
|
|
161
|
+
Every flag in PostHog is configured as client-side, server-side, or both via [evaluation contexts](https://posthog.com/docs/feature-flags/evaluation-contexts.md). New flags default to "server and client" – this exists for backwards compatibility (it's how all flags worked before we added evaluation contexts) and to avoid blocking users who haven't thought about their implementation yet. It's a safe starting point, not a recommendation.
|
|
152
162
|
|
|
153
163
|
If all your flags are set to both, that usually means the decision was never revisited after creation – and you're paying for client-side evaluation on flags that only need to exist on your server.
|
|
154
164
|
|
|
@@ -158,7 +168,7 @@ Pick the context based on where the flag is actually consumed. Server-side flags
|
|
|
158
168
|
|
|
159
169
|
A flag set to 100% of all users with no property targeting is a flag that has finished its job. It's always returning the same value – the rollout is complete, the experiment concluded, the feature is live. If your SDK still evaluates that flag, it can keep making billable `/flags` requests, keep appearing in SDK payloads, and add clutter to your codebase.
|
|
160
170
|
|
|
161
|
-
Remove the flag and hardcode the winning path. If you're not ready to remove it from code, at least archive it in PostHog so it stops being evaluated. Stale flags are the most common source of unnecessary flag evaluation. See [cleaning up stale flags](/docs/feature-flags/cleaning-up-stale-flags.md) for the full workflow and [cutting costs](/docs/feature-flags/cutting-costs.md) for more on reducing your bill.
|
|
171
|
+
Remove the flag and hardcode the winning path. If you're not ready to remove it from code, at least archive it in PostHog so it stops being evaluated. Stale flags are the most common source of unnecessary flag evaluation. See [cleaning up stale flags](https://posthog.com/docs/feature-flags/cleaning-up-stale-flags.md) for the full workflow and [cutting costs](https://posthog.com/docs/feature-flags/cutting-costs.md) for more on reducing your bill.
|
|
162
172
|
|
|
163
173
|
**An idea worth considering:** design your flag code paths with an escape hatch you control outside of PostHog. For example, a "gate flag" that your server reads once every 30 seconds (not per user) – when it's `true`, the feature is fully rolled out and your code skips the per-user flag evaluation entirely. This means you stop making per-user `/flags` requests for that rollout as soon as it's complete, even before you remove the flag from code. And you can dial it back by setting the gate flag to `false`. This is also another application of "evaluate once, not continuously" – if you cache flag results, your per-user evaluation cost drops while you wait for the code cleanup.
|
|
164
174
|
|
|
@@ -170,14 +180,12 @@ This is the practical extension of "evaluate once, not continuously." Your serve
|
|
|
170
180
|
|
|
171
181
|
### Use a reverse proxy
|
|
172
182
|
|
|
173
|
-
Ad blockers can disable your Feature Flags, leading to users seeing the wrong version of your app or missing a rollout. Deploy a [reverse proxy](/docs/advanced/proxy.md) so requests go through your own domain. PostHog offers a free [managed reverse proxy](/docs/advanced/proxy/managed-reverse-proxy.md), or you can run your own.
|
|
183
|
+
Ad blockers can disable your Feature Flags, leading to users seeing the wrong version of your app or missing a rollout. Deploy a [reverse proxy](https://posthog.com/docs/advanced/proxy.md) so requests go through your own domain. PostHog offers a free [managed reverse proxy](https://posthog.com/docs/advanced/proxy/managed-reverse-proxy.md), or you can run your own.
|
|
174
184
|
|
|
175
185
|
### Call your flag in as few places as possible
|
|
176
186
|
|
|
177
187
|
The more locations a flag appears in your code, the more likely it is to cause problems – a developer removes it in one place but forgets another. If you use a flag in multiple places, wrap it in a single function:
|
|
178
188
|
|
|
179
|
-
JavaScript
|
|
180
|
-
|
|
181
189
|
```javascript
|
|
182
190
|
function useBetaFeature() {
|
|
183
191
|
return posthog.isFeatureEnabled('beta-feature')
|
|
@@ -195,11 +203,11 @@ Good naming makes flags easier to understand and maintain:
|
|
|
195
203
|
|
|
196
204
|
### Roll out progressively
|
|
197
205
|
|
|
198
|
-
Start at 5-10% of users, monitor metrics, then gradually increase. This is a [phased rollout](/tutorials/phased-rollout.md). At PostHog, we typically roll out to the developer first, then the internal team, then beta users, then everyone.
|
|
206
|
+
Start at 5-10% of users, monitor metrics, then gradually increase. This is a [phased rollout](https://posthog.com/tutorials/phased-rollout.md). At PostHog, we typically roll out to the developer first, then the internal team, then beta users, then everyone.
|
|
199
207
|
|
|
200
208
|
### Use dependencies for complex rollouts
|
|
201
209
|
|
|
202
|
-
[Feature flag dependencies](/docs/feature-flags/dependencies.md) let one flag's activation depend on another flag's state – useful for enabling complex features only after foundational components are active, or running Experiments only on users with specific features enabled. Keep dependency chains simple and avoid circular dependencies.
|
|
210
|
+
[Feature flag dependencies](https://posthog.com/docs/feature-flags/dependencies.md) let one flag's activation depend on another flag's state – useful for enabling complex features only after foundational components are active, or running Experiments only on users with specific features enabled. Keep dependency chains simple and avoid circular dependencies.
|
|
203
211
|
|
|
204
212
|
### Be careful with "Latest" person properties
|
|
205
213
|
|
|
@@ -207,19 +215,11 @@ PostHog automatically creates person properties like "Latest Current URL" and "L
|
|
|
207
215
|
|
|
208
216
|
### Reducing your bill
|
|
209
217
|
|
|
210
|
-
Stale flags are the most common source of unnecessary cost. Beyond cleaning up flags, see our [dedicated guide to cutting costs](/docs/feature-flags/cutting-costs.md) for estimating and reducing your feature flag bill.
|
|
218
|
+
Stale flags are the most common source of unnecessary cost. Beyond cleaning up flags, see our [dedicated guide to cutting costs](https://posthog.com/docs/feature-flags/cutting-costs.md) for estimating and reducing your feature flag bill.
|
|
211
219
|
|
|
212
220
|
## Further reading
|
|
213
221
|
|
|
214
|
-
- [Identity resolution](/docs/product-analytics/identity-resolution.md) – how PostHog resolves who a user is
|
|
215
|
-
- [Keeping flag evaluations stable](/docs/feature-flags/stable-identity-for-flags.md) – preventing the hash input from changing across auth transitions
|
|
216
|
-
- [Local evaluation](/docs/feature-flags/local-evaluation.md) – server-side evaluation for explicit input control
|
|
217
|
-
- [Bootstrapping](/docs/feature-flags/bootstrapping.md) – having flag values before the page renders
|
|
218
|
-
|
|
219
|
-
### Still have questions?
|
|
220
|
-
|
|
221
|
-
Ask PostHog AI
|
|
222
|
-
|
|
223
|
-
### Was this page useful?
|
|
224
|
-
|
|
225
|
-
HelpfulCould be better
|
|
222
|
+
- [Identity resolution](https://posthog.com/docs/product-analytics/identity-resolution.md) – how PostHog resolves who a user is
|
|
223
|
+
- [Keeping flag evaluations stable](https://posthog.com/docs/feature-flags/stable-identity-for-flags.md) – preventing the hash input from changing across auth transitions
|
|
224
|
+
- [Local evaluation](https://posthog.com/docs/feature-flags/local-evaluation.md) – server-side evaluation for explicit input control
|
|
225
|
+
- [Bootstrapping](https://posthog.com/docs/feature-flags/bootstrapping.md) – having flag values before the page renders
|
|
@@ -2,18 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
# Django
|
|
4
4
|
|
|
5
|
+
Canonical URL: https://posthog.com/docs/libraries/django
|
|
6
|
+
|
|
7
|
+
> **Cloud region:** This page uses US Cloud hosts. For an EU Cloud project, use `https://eu.i.posthog.com` instead of `https://us.i.posthog.com` (ingestion host), and use `https://eu.posthog.com` instead of `https://app.posthog.com` (app host for links).
|
|
8
|
+
|
|
9
|
+
## On this page
|
|
10
|
+
|
|
11
|
+
- [Beta: integration via LLM](#beta-integration-via-llm)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Identifying users](#identifying-users)
|
|
14
|
+
- [Django contexts middleware](#django-contexts-middleware)
|
|
15
|
+
- [Next steps](#next-steps)
|
|
16
|
+
- [Supported versions](#supported-versions)
|
|
17
|
+
|
|
5
18
|
PostHog makes it easy to get data about traffic and usage of your Django app. Integrating PostHog enables analytics, custom events capture, feature flags, error tracking, and more.
|
|
6
19
|
|
|
7
|
-
This guide walks you through integrating PostHog into your Django app using the [Python SDK](/docs/libraries/python.md).
|
|
20
|
+
This guide walks you through integrating PostHog into your Django app using the [Python SDK](https://posthog.com/docs/libraries/python.md).
|
|
8
21
|
|
|
9
22
|
## Beta: integration via LLM
|
|
10
23
|
|
|
11
|
-
Install PostHog for Django in seconds with our wizard by running this prompt with [LLM coding agents](/blog/envoy-wizard-llm-agent.md) like Cursor and Bolt, or by running it in your terminal.
|
|
24
|
+
Install PostHog for Django in seconds with our wizard by running this prompt with [LLM coding agents](https://posthog.com/blog/envoy-wizard-llm-agent.md) like Cursor and Bolt, or by running it in your terminal.
|
|
12
25
|
|
|
13
26
|
`npx @posthog/wizard`
|
|
14
27
|
|
|
15
|
-
[Learn more](/wizard.md)
|
|
16
|
-
|
|
17
28
|
Or, to integrate manually, continue with the rest of this guide.
|
|
18
29
|
|
|
19
30
|
> These docs cover version `7.x` of the Python SDK, which requires Python 3.10 or higher. On Python 3.9? See [supported versions](#supported-versions).
|
|
@@ -53,8 +64,6 @@ You can find your project token and instance address in [your project settings](
|
|
|
53
64
|
|
|
54
65
|
To capture events from any file, import `posthog` and call the method you need. For example:
|
|
55
66
|
|
|
56
|
-
Python
|
|
57
|
-
|
|
58
67
|
```python
|
|
59
68
|
import posthog
|
|
60
69
|
from posthog import identify_context
|
|
@@ -69,7 +78,7 @@ def some_request(request):
|
|
|
69
78
|
posthog.capture('event_name')
|
|
70
79
|
```
|
|
71
80
|
|
|
72
|
-
Events captured without a context or explicit `distinct_id` are sent as [anonymous events](/docs/data/anonymous-vs-identified-events.md) with an auto-generated `distinct_id`. See the [Python SDK docs](/docs/libraries/python.md#person-profiles-and-properties) for more details.
|
|
81
|
+
Events captured without a context or explicit `distinct_id` are sent as [anonymous events](https://posthog.com/docs/data/anonymous-vs-identified-events.md) with an auto-generated `distinct_id`. See the [Python SDK docs](https://posthog.com/docs/libraries/python.md#person-profiles-and-properties) for more details.
|
|
73
82
|
|
|
74
83
|
## Identifying users
|
|
75
84
|
|
|
@@ -77,8 +86,6 @@ Events captured without a context or explicit `distinct_id` are sent as [anonymo
|
|
|
77
86
|
>
|
|
78
87
|
> In Python, you can do this through a context. All event captures in the same context will be tagged automatically with the correct `distinct_id`. Typically, you would set a fresh context and identify at the top of each route.
|
|
79
88
|
>
|
|
80
|
-
> Python
|
|
81
|
-
>
|
|
82
89
|
> ```python
|
|
83
90
|
> from posthog import new_context, identify_context, capture
|
|
84
91
|
>
|
|
@@ -94,18 +101,16 @@ Events captured without a context or explicit `distinct_id` are sent as [anonymo
|
|
|
94
101
|
|
|
95
102
|
## Django contexts middleware
|
|
96
103
|
|
|
97
|
-
The Python SDK provides a Django middleware that automatically wraps all requests with a [context](/docs/libraries/python.md#contexts). This middleware extracts session and user information from each request and
|
|
104
|
+
The Python SDK provides a Django middleware that automatically wraps all requests with a [context](https://posthog.com/docs/libraries/python.md#contexts). This middleware extracts session and user information from each request and adds relevant properties to events captured during that request.
|
|
98
105
|
|
|
99
106
|
### Basic setup
|
|
100
107
|
|
|
101
108
|
Add the middleware to your Django settings. If your app uses Django authentication, place it after `django.contrib.auth.middleware.AuthenticationMiddleware` so the middleware can use the authenticated Django user as a distinct ID fallback and capture the user's email.
|
|
102
109
|
|
|
103
|
-
Python
|
|
104
|
-
|
|
105
110
|
```python
|
|
106
111
|
MIDDLEWARE = [
|
|
107
112
|
# ... other middleware
|
|
108
|
-
|
|
113
|
+
"posthog.integrations.django.PosthogContextMiddleware",
|
|
109
114
|
# ... other middleware
|
|
110
115
|
]
|
|
111
116
|
```
|
|
@@ -114,8 +119,8 @@ The middleware uses the globally configured `posthog` client by default, so you
|
|
|
114
119
|
|
|
115
120
|
The middleware automatically extracts and uses:
|
|
116
121
|
|
|
117
|
-
- **Session ID** from the `X-POSTHOG-SESSION-ID` header
|
|
118
|
-
- **Distinct ID** from the
|
|
122
|
+
- **Session ID** from the `X-POSTHOG-SESSION-ID` header when you enable `POSTHOG_MW_TRUST_TRACING_HEADERS`
|
|
123
|
+
- **Distinct ID** from the authenticated Django user's `pk` (Django's primary-key alias, which works with custom user models), or from the `X-POSTHOG-DISTINCT-ID` header when you enable `POSTHOG_MW_TRUST_TRACING_HEADERS`
|
|
119
124
|
- **User email** from the authenticated Django user's `email` as `email`
|
|
120
125
|
- **Current URL** as `$current_url`
|
|
121
126
|
- **Request method** as `$request_method`
|
|
@@ -123,7 +128,14 @@ The middleware automatically extracts and uses:
|
|
|
123
128
|
- **Forwarded IP address** from `X-Forwarded-For` as `$ip`
|
|
124
129
|
- **User agent** from `User-Agent` as `$user_agent`
|
|
125
130
|
|
|
126
|
-
The session and distinct ID headers
|
|
131
|
+
The middleware ignores the session and distinct ID headers by default because clients can control them. To use them as analytics context, enable them in your Django settings:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
# settings.py
|
|
135
|
+
POSTHOG_MW_TRUST_TRACING_HEADERS = True
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Don't use these headers for authentication or authorization. The middleware sanitizes trusted header values before use. It ignores empty values, removes control characters, trims values, and caps them at 1000 characters.
|
|
127
139
|
|
|
128
140
|
All events captured during the request (including exceptions) include these properties and are associated with the extracted session and distinct ID.
|
|
129
141
|
|
|
@@ -133,8 +145,6 @@ The middleware reads `request.user` once, before your view runs. On a login or s
|
|
|
133
145
|
|
|
134
146
|
Identify the context from inside the request once you know who the user is. Django's auth signals are the natural place:
|
|
135
147
|
|
|
136
|
-
Python
|
|
137
|
-
|
|
138
148
|
```python
|
|
139
149
|
from django.contrib.auth.signals import user_logged_in
|
|
140
150
|
from django.dispatch import receiver
|
|
@@ -147,7 +157,7 @@ def identify_posthog_user(sender, request, user, **kwargs):
|
|
|
147
157
|
|
|
148
158
|
Every capture later in that request is then attributed to the user who just logged in. Requests made after login don't need this. The middleware sees the authenticated user from the start.
|
|
149
159
|
|
|
150
|
-
If you're using [PostHog JavaScript Web](/docs/libraries/js.md) on the frontend, configure [`tracing_headers`](/docs/libraries/js/config.md#tracing-headers) for your Django backend hostname so browser requests include the session and distinct ID headers.
|
|
160
|
+
If you're using [PostHog JavaScript Web](https://posthog.com/docs/libraries/js.md) on the frontend, configure [`tracing_headers`](https://posthog.com/docs/libraries/js/config.md#tracing-headers) for your Django backend hostname so browser requests include the session and distinct ID headers. You must also set `POSTHOG_MW_TRUST_TRACING_HEADERS = True` in Django to accept them.
|
|
151
161
|
|
|
152
162
|
### Exception capture
|
|
153
163
|
|
|
@@ -155,120 +165,166 @@ By default, the middleware captures exceptions and sends them to PostHog's error
|
|
|
155
165
|
|
|
156
166
|
Disable this by setting:
|
|
157
167
|
|
|
158
|
-
Python
|
|
159
|
-
|
|
160
168
|
```python
|
|
161
169
|
# settings.py
|
|
162
170
|
POSTHOG_MW_CAPTURE_EXCEPTIONS = False
|
|
163
171
|
```
|
|
164
172
|
|
|
165
|
-
|
|
173
|
+
Set `POSTHOG_MW_CAPTURE_EXCEPTIONS = None` to inherit the global client's `enable_exception_autocapture` setting. When you omit `POSTHOG_MW_CAPTURE_EXCEPTIONS`, the middleware preserves the existing Django default and captures exceptions.
|
|
174
|
+
|
|
175
|
+
### Capture Django REST Framework exceptions
|
|
166
176
|
|
|
167
|
-
|
|
177
|
+
This integration requires version `7.69.0` or later of the Python SDK.
|
|
168
178
|
|
|
169
|
-
|
|
179
|
+
Django REST Framework (DRF) converts many exceptions into responses before Django middleware can observe them. Add PostHog's DRF exception handler to capture these handled errors:
|
|
170
180
|
|
|
171
181
|
```python
|
|
172
182
|
# settings.py
|
|
173
|
-
|
|
183
|
+
REST_FRAMEWORK = {
|
|
184
|
+
# ... other DRF settings
|
|
185
|
+
"EXCEPTION_HANDLER": "posthog.integrations.drf.exception_handler",
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Keep `PosthogContextMiddleware` enabled. The middleware adds request properties and identity to the active context, while the DRF handler captures handled API exceptions. The handler captures responses with a `5xx` status by default and ignores expected `4xx` responses. If DRF doesn't handle an exception, Django re-raises it and the middleware captures it instead.
|
|
190
|
+
|
|
191
|
+
If you already use a custom DRF exception handler, wrap it in an application module:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
# your_app/exception_handlers.py
|
|
195
|
+
from posthog.integrations.drf import create_exception_handler
|
|
196
|
+
from your_app.api import existing_exception_handler
|
|
197
|
+
|
|
198
|
+
exception_handler = create_exception_handler(existing_exception_handler)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Then point DRF to the wrapper:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
# settings.py
|
|
205
|
+
REST_FRAMEWORK = {
|
|
206
|
+
"EXCEPTION_HANDLER": "your_app.exception_handlers.exception_handler",
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
To capture selected `4xx` responses, create a handler with `capture_4xx=True` and an exception filter:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
# your_app/exception_handlers.py
|
|
214
|
+
from posthog.integrations.drf import create_exception_handler
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def capture_auth_errors(exception, response, context):
|
|
218
|
+
return response.status_code >= 500 or response.status_code in {401, 403}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
exception_handler = create_exception_handler(
|
|
222
|
+
capture_4xx=True,
|
|
223
|
+
exception_filter=capture_auth_errors,
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The DRF handler follows `POSTHOG_MW_CAPTURE_EXCEPTIONS` and `POSTHOG_MW_REQUEST_FILTER`. You can also pass `capture_exceptions=True` or `capture_exceptions=False` to `create_exception_handler()` to override the middleware setting.
|
|
228
|
+
|
|
229
|
+
### Add custom properties
|
|
230
|
+
|
|
231
|
+
Use `POSTHOG_MW_EXTRA_PROPERTIES` to add custom properties to all requests:
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
# settings.py
|
|
235
|
+
def add_user_properties(request):
|
|
174
236
|
# type: (HttpRequest) -> Dict[str, Any]
|
|
175
|
-
|
|
176
|
-
if hasattr(request,
|
|
237
|
+
properties = {}
|
|
238
|
+
if hasattr(request, "user") and request.user.is_authenticated:
|
|
177
239
|
# Use pk instead of id so this works with custom User primary keys.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return
|
|
240
|
+
properties["user_id"] = str(request.user.pk)
|
|
241
|
+
properties["email"] = request.user.email
|
|
242
|
+
return properties
|
|
181
243
|
|
|
182
|
-
|
|
244
|
+
POSTHOG_MW_EXTRA_PROPERTIES = add_user_properties
|
|
183
245
|
```
|
|
184
246
|
|
|
185
|
-
|
|
247
|
+
### Filter requests
|
|
186
248
|
|
|
187
249
|
Skip tracking for certain requests using `POSTHOG_MW_REQUEST_FILTER`:
|
|
188
250
|
|
|
189
|
-
Python
|
|
190
|
-
|
|
191
251
|
```python
|
|
192
252
|
# settings.py
|
|
193
253
|
def should_track_request(request):
|
|
194
254
|
# type: (HttpRequest) -> bool
|
|
195
255
|
# Don't track health checks or admin requests
|
|
196
|
-
if request.path.startswith(
|
|
256
|
+
if request.path.startswith("/health") or request.path.startswith("/admin"):
|
|
197
257
|
return False
|
|
198
258
|
return True
|
|
199
259
|
|
|
200
260
|
POSTHOG_MW_REQUEST_FILTER = should_track_request
|
|
201
261
|
```
|
|
202
262
|
|
|
203
|
-
###
|
|
263
|
+
### Modify default properties
|
|
204
264
|
|
|
205
|
-
Use `
|
|
206
|
-
|
|
207
|
-
Python
|
|
265
|
+
Use `POSTHOG_MW_PROPERTIES_MAP` to modify or remove default properties:
|
|
208
266
|
|
|
209
267
|
```python
|
|
210
268
|
# settings.py
|
|
211
|
-
def
|
|
269
|
+
def customize_properties(properties):
|
|
212
270
|
# type: (Dict[str, Any]) -> Dict[str, Any]
|
|
213
271
|
# Remove URL for privacy
|
|
214
|
-
|
|
272
|
+
properties.pop("$current_url", None)
|
|
215
273
|
# Add custom prefix to method
|
|
216
|
-
if
|
|
217
|
-
|
|
218
|
-
return
|
|
274
|
+
if "$request_method" in properties:
|
|
275
|
+
properties["http_method"] = properties.pop("$request_method")
|
|
276
|
+
return properties
|
|
219
277
|
|
|
220
|
-
|
|
278
|
+
POSTHOG_MW_PROPERTIES_MAP = customize_properties
|
|
221
279
|
```
|
|
222
280
|
|
|
223
281
|
### Complete configuration example
|
|
224
282
|
|
|
225
|
-
Python
|
|
226
|
-
|
|
227
283
|
```python
|
|
228
284
|
# settings.py
|
|
229
285
|
def add_request_context(request):
|
|
230
286
|
# type: (HttpRequest) -> Dict[str, Any]
|
|
231
|
-
|
|
232
|
-
if hasattr(request,
|
|
233
|
-
|
|
287
|
+
properties = {}
|
|
288
|
+
if hasattr(request, "user") and request.user.is_authenticated:
|
|
289
|
+
properties["user_type"] = "authenticated"
|
|
234
290
|
# Use pk instead of id so this works with custom User primary keys.
|
|
235
|
-
|
|
291
|
+
properties["user_id"] = str(request.user.pk)
|
|
236
292
|
else:
|
|
237
|
-
|
|
293
|
+
properties["user_type"] = "anonymous"
|
|
238
294
|
|
|
239
295
|
# Add request info
|
|
240
|
-
|
|
241
|
-
return
|
|
296
|
+
properties["user_agent"] = request.META.get("HTTP_USER_AGENT", "")
|
|
297
|
+
return properties
|
|
242
298
|
|
|
243
299
|
def filter_tracking(request):
|
|
244
300
|
# type: (HttpRequest) -> bool
|
|
245
301
|
# Skip internal endpoints
|
|
246
|
-
return not request.path.startswith((
|
|
302
|
+
return not request.path.startswith(("/health", "/metrics", "/admin"))
|
|
247
303
|
|
|
248
|
-
def
|
|
304
|
+
def clean_properties(properties):
|
|
249
305
|
# type: (Dict[str, Any]) -> Dict[str, Any]
|
|
250
306
|
# Remove sensitive data
|
|
251
|
-
|
|
252
|
-
return
|
|
307
|
+
properties.pop("user_agent", None)
|
|
308
|
+
return properties
|
|
253
309
|
|
|
254
|
-
|
|
310
|
+
POSTHOG_MW_EXTRA_PROPERTIES = add_request_context
|
|
255
311
|
POSTHOG_MW_REQUEST_FILTER = filter_tracking
|
|
256
|
-
|
|
312
|
+
POSTHOG_MW_PROPERTIES_MAP = clean_properties
|
|
257
313
|
POSTHOG_MW_CAPTURE_EXCEPTIONS = True
|
|
258
314
|
```
|
|
259
315
|
|
|
260
|
-
All events captured within the request context automatically include the configured
|
|
316
|
+
All events captured within the request context automatically include the configured properties. They use the authenticated Django user as the distinct ID, or the session and distinct ID from request headers when you enable `POSTHOG_MW_TRUST_TRACING_HEADERS`.
|
|
261
317
|
|
|
262
318
|
The middleware supports both sync (WSGI) and async (ASGI) Django applications. In async mode, it uses Django's `request.auser()` API when available to avoid synchronous user access.
|
|
263
319
|
|
|
264
320
|
## Next steps
|
|
265
321
|
|
|
266
|
-
For any technical questions for how to integrate specific PostHog features into Django (such as analytics, feature flags, A/B testing, etc.), have a look at our [Python SDK docs](/docs/libraries/python.md).
|
|
322
|
+
For any technical questions for how to integrate specific PostHog features into Django (such as analytics, feature flags, A/B testing, etc.), have a look at our [Python SDK docs](https://posthog.com/docs/libraries/python.md).
|
|
267
323
|
|
|
268
324
|
Alternatively, the following tutorials can help you get started:
|
|
269
325
|
|
|
270
|
-
- [Setting up Django analytics, feature flags, and more](/tutorials/django-analytics.md)
|
|
271
|
-
- [How to set up A/B tests in Django](/tutorials/django-ab-tests.md)
|
|
326
|
+
- [Setting up Django analytics, feature flags, and more](https://posthog.com/tutorials/django-analytics.md)
|
|
327
|
+
- [How to set up A/B tests in Django](https://posthog.com/tutorials/django-ab-tests.md)
|
|
272
328
|
|
|
273
329
|
## Supported versions
|
|
274
330
|
|
|
@@ -277,11 +333,3 @@ These docs cover version `7.x` of the PostHog Python SDK, which requires Python
|
|
|
277
333
|
Everything on this page works the same way on `6.9.3`. Event capture, the context API (`new_context`, `identify_context`, `set_context_session`), and `PosthogContextMiddleware` are identical on `6.9.3` and `7.0.0` — `7.0.0` only dropped Python 3.9 and bumped the optional LLM provider SDKs. That includes the middleware identifying the request context from the `X-POSTHOG-DISTINCT-ID` header and falling back to the authenticated user, which behaves the same across both lines.
|
|
278
334
|
|
|
279
335
|
Later `7.x` releases add what the 6.x line does not receive, such as the Celery integration, tracing header sanitization, and `set_context_device_id`. They also changed the middleware's own captured properties: `7.x` sends the request IP as `$ip`, where `6.9.3` sends it as `$ip_address`, and `7.x` additionally captures `$request_path`, `$raw_user_agent`, and the authenticated user's `email`.
|
|
280
|
-
|
|
281
|
-
### Still have questions?
|
|
282
|
-
|
|
283
|
-
Ask PostHog AI
|
|
284
|
-
|
|
285
|
-
### Was this page useful?
|
|
286
|
-
|
|
287
|
-
HelpfulCould be better
|