diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 7ec113b..9d51513 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,7 +12,7 @@ "displayName": "PostHog", "source": "./", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from your AI coding tool. Optionally capture Claude Code sessions to PostHog LLM Analytics.", - "version": "1.1.60", + "version": "1.1.61", "author": { "name": "PostHog", "email": "hey@posthog.com", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 12c7a85..9156efc 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "posthog", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from your AI coding tool. Optionally capture Claude Code sessions to PostHog LLM Analytics.", - "version": "1.1.60", + "version": "1.1.61", "author": { "name": "PostHog", "email": "hey@posthog.com", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 42fcf00..375ec8e 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.58", + "version": "1.0.59", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from Codex", "author": { "name": "PostHog", diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index e775d5d..1d01fa8 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "posthog", "displayName": "PostHog", - "version": "1.1.54", + "version": "1.1.55", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from Cursor", "author": { "name": "PostHog", diff --git a/gemini-extension.json b/gemini-extension.json index 9e09822..6c3629a 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.56", + "version": "1.0.57", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from Gemini CLI", "mcpServers": { "posthog": { diff --git a/skills/instrument-error-tracking/references/fingerprints.md b/skills/instrument-error-tracking/references/fingerprints.md index d58a678..6cdd6ce 100644 --- a/skills/instrument-error-tracking/references/fingerprints.md +++ b/skills/instrument-error-tracking/references/fingerprints.md @@ -52,6 +52,22 @@ You can find details about how issue grouping works in the [issues and exception Fingerprints can be manually set during exception capture. This is a very useful way to group exceptions that are not related to each other. You can find examples of how to do this in the [custom issue grouping](/docs/error-tracking/grouping-issues.md#option-2-client-side-fingerprint) section. +When you set a custom fingerprint, you can also name the resulting issue with the `$issue_name` and `$issue_description` properties: + +JavaScript + +PostHog AI + +```javascript +posthog.captureException(error, { + $exception_fingerprint: "MyCustomGroup", + $issue_name: "Checkout failures", + $issue_description: "Payment provider timeouts during checkout", +}) +``` + +PostHog uses these two properties only on the event that creates the issue, and truncates each to 255 characters. Later events on the same fingerprint keep the existing name and description. When you do not set them, PostHog uses the exception type as the name and the exception message as the description. + You can also learn more about grouping issues using rules in the [grouping issues](/docs/error-tracking/grouping-issues.md) guide. ### Still have questions? diff --git a/skills/instrument-integration/references/flutter.md b/skills/instrument-integration/references/flutter.md index d749a6b..1823cb5 100644 --- a/skills/instrument-integration/references/flutter.md +++ b/skills/instrument-integration/references/flutter.md @@ -184,7 +184,9 @@ Future main() async { #### Web setup -For Web, add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file: +If your project has a `web/` directory, this step is required. `Posthog().setup()` is a no-op on web, so a web build without the snippet below captures nothing. + +Add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file. Write your project token into the snippet as a literal string. It's public, the same token ships to every visitor, and it needs no build-time or deploy-time injection: web/index.html @@ -292,12 +294,16 @@ PostHog autocapture automatically tracks the following events for you: - **Application Backgrounded** - when the app is sent to the background by the user - **Application Installed** - when the app is installed. - **Application Updated** - when the app is updated. -- **$screen** - when the user navigates (if using [navigatorObservers](https://docs.flutter.dev/ui/navigation) or [go\_router](https://pub.dev/packages/go_router). You'd need to set up the `PosthogObserver` manually.) +- **$screen** - when the user navigates, once you add the `PosthogObserver` - **$exception** - when the app throws exceptions. ### Capturing screen views -> Note: Your routes should be named. Otherwise, they won't be recorded. +Screen views aren't captured automatically. Add the `PosthogObserver` to your app yourself. Without it, your app sends no `$screen` events at all. + +This works with any routing package, not just the plain `Navigator` API. Add the observer wherever your router takes navigator observers, as shown below for `MaterialApp` and `go_router`. + +> Note: Screen names come from each route's `RouteSettings.name`. Most routing packages set this for you. If yours doesn't, name your routes so `$screen` events are readable. #### Using `navigatorObservers` diff --git a/skills/instrument-integration/references/posthog-node.md b/skills/instrument-integration/references/posthog-node.md index b85e9a1..f94c067 100644 --- a/skills/instrument-integration/references/posthog-node.md +++ b/skills/instrument-integration/references/posthog-node.md @@ -1011,13 +1011,13 @@ await client.enable() Evaluate all feature flags for a user in a single call and return a snapshot. Branch on `.isEnabled()` / `.getFlag()`, then pass the same snapshot to `capture()` via the `flags` option so the captured event carries the exact flag values the code branched on. Prefer this over repeated `isFeatureEnabled()` / `getFeatureFlag()` calls and over `capture({ sendFeatureFlags: true })` — it consolidates flag evaluation into a single `/flags` request per incoming request. -**Local evaluation is transparent.** When the poller can resolve a flag from cached definitions, no network call is made and the snapshot's `$feature_flag_called` events are tagged `locally_evaluated: true`. -**Trim the request.** Pass `flagKeys` to scope the underlying `/flags` request to a subset of flags — useful when you only need a few flags and want to reduce the response payload. +**Local evaluation is transparent.** When the poller can resolve a flag from cached definitions, no network call is made and the snapshot's `$feature_flag_called` events are tagged `locally_evaluated: true`. A requested key missing from local definitions is included in a `/flags` fallback unless `onlyEvaluateLocally` is true. Locally resolved values remain authoritative when remote results are merged. +**Trim the request.** Pass `flagKeys` to scope local evaluation, the underlying `/flags` request, and the returned snapshot to a subset of flags. Remote evaluation responses are not cached, so a key missing both locally and remotely costs one `/flags` request per `evaluateFlags()` call. **Trim the event payload.** Use `flags.only([...])` or `flags.onlyAccessed()` to filter which flags get attached to a captured event without re-fetching. ### Parameters -- **`options?`** (`AllFlagsOptions`) - Optional configuration for flag evaluation. Supports the same fields as `getAllFlags()`, including `flagKeys` to scope the `/flags` request. +- **`options?`** (`AllFlagsOptions`) - Optional configuration for flag evaluation. Supports the same fields as `getAllFlags()`. `flagKeys` scopes local evaluation, the `/flags` request, and the returned snapshot. `onlyEvaluateLocally` prevents fallback and leaves unresolved keys absent. ### Returns diff --git a/skills/instrument-integration/references/posthog-python.md b/skills/instrument-integration/references/posthog-python.md index ae3cd3a..7f525de 100644 --- a/skills/instrument-integration/references/posthog-python.md +++ b/skills/instrument-integration/references/posthog-python.md @@ -2,7 +2,7 @@ # PostHog Python SDK -**SDK Version:** 7.39.2 +**SDK Version:** 7.44.1 Integrate PostHog into any python application. @@ -76,6 +76,7 @@ Initialize a new PostHog client instance. - **`secret_key`** (`any`) - A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:: posthog.Client(project_api_key, secret_key="phx_...") - **`metrics?`** (`dict`) - **`enable_full_ai_capture`** (`bool`) - Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. ``privacy_mode`` always wins. Defaults to False. +- **`capture_trace_context`** (`bool`) - When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as ``$trace_id`` and ``$span_id`` properties to events captured with ``capture()`` and ``capture_ai()``, so they can be correlated with backend traces. Explicit ``$trace_id``/``$span_id`` values passed in ``properties`` win. Exception events (``capture_exception``) always attach these IDs regardless of this setting. Defaults to False. - **`_use_ai_lane`** (`bool`) - **`_enable_multimodal_capture`** (`bool`) @@ -320,7 +321,7 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If True, never fall back to remote evaluation — flags that can't be evaluated locally are simply omitted from the snapshot. - **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. -- **`flag_keys?`** (`list[str]`) - Optional list of flag keys to scope the underlying ``/flags`` request to a subset. +- **`flag_keys?`** (`list[str]`) - Optional list that scopes local evaluation, the underlying ``/flags`` request, and the returned snapshot. When omitted or ``None``, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per ``evaluate_flags`` call unless ``only_evaluate_locally`` is True. If the server also does not know the key, it is omitted from the snapshot. - **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns @@ -1166,9 +1167,9 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat - **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. - **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. -- **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation. +- **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation and omit flags that cannot be evaluated locally. - **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. -- **`flag_keys?`** (`list[str]`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. +- **`flag_keys?`** (`list[str]`) - Optional list that scopes local evaluation, the underlying ``/flags`` request, and the returned snapshot. When omitted or ``None``, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per ``evaluate_flags`` call unless ``only_evaluate_locally`` is ``True``. If the server also does not know the key, it is omitted from the snapshot. - **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns diff --git a/skills/instrument-llm-analytics/references/calculating-costs.md b/skills/instrument-llm-analytics/references/calculating-costs.md index a93784b..38a83af 100644 --- a/skills/instrument-llm-analytics/references/calculating-costs.md +++ b/skills/instrument-llm-analytics/references/calculating-costs.md @@ -192,7 +192,7 @@ When PostHog calculates costs automatically, it sets the following metadata prop These properties are useful for debugging cost discrepancies or understanding which pricing was applied when using model aliases or custom configurations. -You can find the code for this on [GitHub](https://github.com/PostHog/posthog/tree/master/plugin-server/src/ingestion/ai-costs). +You can find the code for this on [GitHub](https://github.com/PostHog/posthog/tree/master/nodejs/src/ingestion/pipelines/ai/costs). ### Still have questions? diff --git a/skills/instrument-llm-analytics/references/manual-capture.md b/skills/instrument-llm-analytics/references/manual-capture.md index 15b352e..d4b826f 100644 --- a/skills/instrument-llm-analytics/references/manual-capture.md +++ b/skills/instrument-llm-analytics/references/manual-capture.md @@ -444,6 +444,10 @@ Skip the manual setup — run this in your project and the wizard installs the S | [Spans](/docs/ai-observability/spans.md) | Review spans and their role in representing individual operations. | | [Anaylze LLM performance](/docs/ai-observability/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | +## Large events + +For large events, use the dedicated AI ingestion path – see [capturing large AI events](/docs/ai-observability/large-events.md). + ### Still have questions? Ask PostHog AI diff --git a/skills/instrument-logs/references/flutter.md b/skills/instrument-logs/references/flutter.md index 04ae732..1d6f33e 100644 --- a/skills/instrument-logs/references/flutter.md +++ b/skills/instrument-logs/references/flutter.md @@ -192,7 +192,9 @@ The PostHog Flutter SDK has built-in support for capturing structured Logs from #### Web setup - For Web, add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file: + If your project has a `web/` directory, this step is required. `Posthog().setup()` is a no-op on web, so a web build without the snippet below captures nothing. + + Add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file. Write your project token into the snippet as a literal string. It's public, the same token ships to every visitor, and it needs no build-time or deploy-time injection: web/index.html diff --git a/skills/instrument-product-analytics/references/flutter.md b/skills/instrument-product-analytics/references/flutter.md index d749a6b..1823cb5 100644 --- a/skills/instrument-product-analytics/references/flutter.md +++ b/skills/instrument-product-analytics/references/flutter.md @@ -184,7 +184,9 @@ Future main() async { #### Web setup -For Web, add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file: +If your project has a `web/` directory, this step is required. `Posthog().setup()` is a no-op on web, so a web build without the snippet below captures nothing. + +Add your `Web snippet` (which you can find in [your project settings](https://us.posthog.com/settings/project#snippet)) in the `
` of your `web/index.html` file. Write your project token into the snippet as a literal string. It's public, the same token ships to every visitor, and it needs no build-time or deploy-time injection: web/index.html @@ -292,12 +294,16 @@ PostHog autocapture automatically tracks the following events for you: - **Application Backgrounded** - when the app is sent to the background by the user - **Application Installed** - when the app is installed. - **Application Updated** - when the app is updated. -- **$screen** - when the user navigates (if using [navigatorObservers](https://docs.flutter.dev/ui/navigation) or [go\_router](https://pub.dev/packages/go_router). You'd need to set up the `PosthogObserver` manually.) +- **$screen** - when the user navigates, once you add the `PosthogObserver` - **$exception** - when the app throws exceptions. ### Capturing screen views -> Note: Your routes should be named. Otherwise, they won't be recorded. +Screen views aren't captured automatically. Add the `PosthogObserver` to your app yourself. Without it, your app sends no `$screen` events at all. + +This works with any routing package, not just the plain `Navigator` API. Add the observer wherever your router takes navigator observers, as shown below for `MaterialApp` and `go_router`. + +> Note: Screen names come from each route's `RouteSettings.name`. Most routing packages set this for you. If yours doesn't, name your routes so `$screen` events are readable. #### Using `navigatorObservers` diff --git a/skills/instrument-product-analytics/references/posthog-python.md b/skills/instrument-product-analytics/references/posthog-python.md index ae3cd3a..7f525de 100644 --- a/skills/instrument-product-analytics/references/posthog-python.md +++ b/skills/instrument-product-analytics/references/posthog-python.md @@ -2,7 +2,7 @@ # PostHog Python SDK -**SDK Version:** 7.39.2 +**SDK Version:** 7.44.1 Integrate PostHog into any python application. @@ -76,6 +76,7 @@ Initialize a new PostHog client instance. - **`secret_key`** (`any`) - A Personal API Key or Project Secret API Key, used to authenticate local feature flag evaluation, remote config payloads, and decrypted flag payloads. Example:: posthog.Client(project_api_key, secret_key="phx_...") - **`metrics?`** (`dict`) - **`enable_full_ai_capture`** (`bool`) - Route PostHog AI wrapper events through the dedicated AI capture endpoint and capture full AI content: skips string truncation and passes media (base64/data URIs) through unredacted. ``privacy_mode`` always wins. Defaults to False. +- **`capture_trace_context`** (`bool`) - When OpenTelemetry is installed and a valid span is active at capture time, add its trace and span IDs as ``$trace_id`` and ``$span_id`` properties to events captured with ``capture()`` and ``capture_ai()``, so they can be correlated with backend traces. Explicit ``$trace_id``/``$span_id`` values passed in ``properties`` win. Exception events (``capture_exception``) always attach these IDs regardless of this setting. Defaults to False. - **`_use_ai_lane`** (`bool`) - **`_enable_multimodal_capture`** (`bool`) @@ -320,7 +321,7 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If True, never fall back to remote evaluation — flags that can't be evaluated locally are simply omitted from the snapshot. - **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. -- **`flag_keys?`** (`list[str]`) - Optional list of flag keys to scope the underlying ``/flags`` request to a subset. +- **`flag_keys?`** (`list[str]`) - Optional list that scopes local evaluation, the underlying ``/flags`` request, and the returned snapshot. When omitted or ``None``, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per ``evaluate_flags`` call unless ``only_evaluate_locally`` is True. If the server also does not know the key, it is omitted from the snapshot. - **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns @@ -1166,9 +1167,9 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat - **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. - **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. -- **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation. +- **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation and omit flags that cannot be evaluated locally. - **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. -- **`flag_keys?`** (`list[str]`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. +- **`flag_keys?`** (`list[str]`) - Optional list that scopes local evaluation, the underlying ``/flags`` request, and the returned snapshot. When omitted or ``None``, all flags are evaluated. An empty list returns an empty snapshot without evaluating flags. A requested key absent from loaded local definitions is included in one remote fallback per ``evaluate_flags`` call unless ``only_evaluate_locally`` is ``True``. If the server also does not know the key, it is omitted from the snapshot. - **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns