From c98e4a9f4acb0881cb09400556d8867e45f457ba Mon Sep 17 00:00:00 2001 From: "releaser-ai-plugin[bot]" <273148615+releaser-ai-plugin[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 13:08:52 +0000 Subject: [PATCH] chore: sync skills (agent-skills-v0.112.0) --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- .cursor-plugin/plugin.json | 2 +- gemini-extension.json | 2 +- skills/.sync-manifest | 1 + .../downloading-batch-export-files/SKILL.md | 127 ++++ skills/instrument-error-tracking/SKILL.md | 7 +- .../references/django.md | 259 ++++++++ .../references/flask.md | 113 ++++ .../references/laravel.md | 150 +++++ .../references/nuxt.md | 2 +- .../references/php.md | 222 +++++++ .../references/react.md | 10 +- .../references/ruby-on-rails.md | 625 +++++++++++++---- .../references/ruby.md | 6 +- skills/instrument-feature-flags/SKILL.md | 4 + .../references/adding-feature-flag-code.md | 74 ++- .../references/django.md | 259 ++++++++ .../references/flask.md | 113 ++++ .../references/laravel.md | 150 +++++ .../references/react.md | 10 +- .../references/ruby-on-rails.md | 595 +++++++++++++++++ skills/instrument-integration/SKILL.md | 4 +- .../references/EXAMPLE-php.md | 527 +++++++++++++++ .../references/django.md | 58 +- .../references/flask.md | 46 +- .../instrument-integration/references/js.md | 1 - .../references/laravel.md | 127 +++- .../instrument-integration/references/node.md | 4 +- .../instrument-integration/references/php.md | 629 ++++++++++++++++++ .../references/posthog-js.md | 2 +- .../references/posthog-node.md | 2 +- .../references/posthog-python.md | 298 +++++---- .../references/python.md | 12 +- .../references/react-router-v6.md | 14 +- .../references/react-router-v7-data-mode.md | 14 +- .../react-router-v7-declarative-mode.md | 14 +- .../react-router-v7-framework-mode.md | 14 +- .../references/react.md | 10 +- .../references/ruby-on-rails.md | 227 +++++-- .../instrument-integration/references/ruby.md | 294 ++++++-- skills/instrument-llm-analytics/SKILL.md | 70 +- .../references/anthropic.md | 18 +- .../references/autogen.md | 18 +- .../references/azure-openai.md | 18 +- .../references/basics.md | 18 +- .../references/calculating-costs.md | 4 +- .../references/cerebras.md | 18 +- .../references/cohere.md | 18 +- .../references/crewai.md | 18 +- .../references/deepseek.md | 18 +- .../references/dspy.md | 18 +- .../references/fireworks-ai.md | 18 +- .../references/google.md | 18 +- .../references/groq.md | 18 +- .../references/helicone.md | 18 +- .../references/hugging-face.md | 18 +- .../references/instructor.md | 18 +- .../references/langchain.md | 18 +- .../references/langgraph.md | 18 +- .../references/litellm.md | 18 +- .../references/llamaindex.md | 18 +- .../references/manual-capture.md | 16 +- .../references/mastra.md | 18 +- .../references/mirascope.md | 18 +- .../references/mistral.md | 18 +- .../references/ollama.md | 18 +- .../references/openai-agents.md | 20 +- .../references/openai.md | 16 +- .../references/openrouter.md | 18 +- .../references/perplexity.md | 18 +- .../references/portkey.md | 18 +- .../references/pydantic-ai.md | 18 +- .../references/semantic-kernel.md | 18 +- .../references/smolagents.md | 18 +- .../references/together-ai.md | 18 +- .../references/traces.md | 12 +- .../references/vercel-ai.md | 18 +- .../references/xai.md | 18 +- skills/instrument-logs/references/search.md | 15 +- skills/instrument-product-analytics/SKILL.md | 4 +- .../references/EXAMPLE-php.md | 527 +++++++++++++++ .../references/django.md | 58 +- .../references/flask.md | 46 +- .../references/laravel.md | 127 +++- .../references/php.md | 629 ++++++++++++++++++ .../references/posthog-python.md | 298 +++++---- .../references/python.md | 12 +- .../references/react-router-v6.md | 14 +- .../references/react-router-v7-data-mode.md | 14 +- .../react-router-v7-declarative-mode.md | 14 +- .../react-router-v7-framework-mode.md | 14 +- .../references/ruby-on-rails.md | 227 +++++-- .../references/ruby.md | 294 ++++++-- .../references/available-functions.md | 2 + .../references/example-error-tracking.md | 4 +- .../references/example-funnel-trends.md | 2 +- .../references/example-logs.md | 2 +- .../references/example-session-replay.md | 8 +- .../references/example-sessions.md | 2 +- 100 files changed, 6981 insertions(+), 1078 deletions(-) create mode 100644 skills/downloading-batch-export-files/SKILL.md create mode 100644 skills/instrument-error-tracking/references/django.md create mode 100644 skills/instrument-error-tracking/references/flask.md create mode 100644 skills/instrument-error-tracking/references/laravel.md create mode 100644 skills/instrument-error-tracking/references/php.md create mode 100644 skills/instrument-feature-flags/references/django.md create mode 100644 skills/instrument-feature-flags/references/flask.md create mode 100644 skills/instrument-feature-flags/references/laravel.md create mode 100644 skills/instrument-feature-flags/references/ruby-on-rails.md create mode 100644 skills/instrument-integration/references/EXAMPLE-php.md create mode 100644 skills/instrument-integration/references/php.md create mode 100644 skills/instrument-product-analytics/references/EXAMPLE-php.md create mode 100644 skills/instrument-product-analytics/references/php.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index b7ff50d..bd3e4ee 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 Claude Code. Optionally capture Claude Code sessions to PostHog LLM Analytics.", - "version": "1.1.26", + "version": "1.1.27", "author": { "name": "PostHog", "email": "hey@posthog.com", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index f36e833..b0721b0 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.24", + "version": "1.0.25", "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 8695ded..0d9ede6 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "posthog", "displayName": "PostHog", - "version": "1.1.21", + "version": "1.1.22", "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 9068f1d..29c35d7 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.23", + "version": "1.0.24", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from Gemini CLI", "mcpServers": { "posthog": { diff --git a/skills/.sync-manifest b/skills/.sync-manifest index 20ead84..befab56 100644 --- a/skills/.sync-manifest +++ b/skills/.sync-manifest @@ -13,6 +13,7 @@ diagnosing-failed-warehouse-syncs diagnosing-missing-recordings diagnosing-sdk-health diagnosing-stacktrace-symbolication +downloading-batch-export-files exploring-apm-traces exploring-autocapture-events exploring-live-traffic diff --git a/skills/downloading-batch-export-files/SKILL.md b/skills/downloading-batch-export-files/SKILL.md new file mode 100644 index 0000000..6b3c7bd --- /dev/null +++ b/skills/downloading-batch-export-files/SKILL.md @@ -0,0 +1,127 @@ +--- +name: downloading-batch-export-files +description: > + Export PostHog events, persons, or sessions on demand and download the resulting files. Use when the user asks to + download/export raw PostHog data, create a one-off file export, fetch a Parquet or JSONLines export, or use the + file_download_batch_exports API. Covers starting the export with MCP, polling completion, and downloading via the + existing REST redirect endpoint. +--- + +# Downloading batch export files + +Use this skill when a user wants a one-off downloadable export of PostHog data. +The export is started and monitored through MCP, but the final file download uses the existing REST endpoint directly. + +## Available MCP tools + +| Tool | Purpose | +| ---------------------------------------------- | -------------------------------------------------------- | +| `posthog:file-download-batch-exports-create` | Start an on-demand export and return the run ID | +| `posthog:file-download-batch-exports-retrieve` | Poll the run status and return file IDs after completion | + +Do not rely on a generated MCP tool for the `/download/` endpoint. +That endpoint is a redirecting file download endpoint, so raw HTTP/download handling is the right interface until MCP has explicit redirect support. + +## Workflow + +### 1. Choose the export shape + +Ask a short clarifying question if the user did not specify the required inputs: + +- `model`: one of `events`, `persons`, or `sessions` +- `data_interval_start` and `data_interval_end`: ISO 8601 datetimes; the range must be at most one week +- `file.format`: `Parquet` or `JSONLines`; prefer `Parquet` for compact analytics exports and `JSONLines` for line-oriented text processing +- `file.compression`: optional, one of `zstd`, `gzip`, `brotli`, `lz4`, or `snappy`. If `JSONLines` was chosen as format, only `gzip` and `brotli` are supported. +- `file.max_size_mb`: optional maximum part size in MB; set this when the user wants multiple smaller files instead of a single (potentially large) file. + +For `events`, `include` and `exclude` are optional event-name filters. +Use them only when the user asks for specific events or wants to omit specific events. + +### 2. Start the export + +Call `posthog:file-download-batch-exports-create` with the selected shape. +The response contains an `id` for the export run. + +Example request: + +```json +{ + "model": "events", + "file": { + "format": "JSONLines", + "compression": "gzip" + }, + "include": ["$pageview"], + "data_interval_start": "2026-05-25T00:00:00Z", + "data_interval_end": "2026-05-26T00:00:00Z" +} +``` + +### 3. Poll until completion + +Call `posthog:file-download-batch-exports-retrieve` with the returned `id`. + +Status handling: + +| Status | Action | +| ------------------------------------------------------------------------- | --------------------------------------------- | +| `Starting` or `Running` | Wait briefly and poll again | +| `Completed` | Read the `files` array and download each file | +| `Cancelled` | Stop and report that the run was cancelled | +| `Failed`, `FailedRetryable`, `FailedBilling`, `Terminated`, or `TimedOut` | Stop and report the `error` field | + +When `Completed`, the `files` array contains file UUIDs. +For single-file exports it usually contains one UUID. +For split exports, download every UUID unless the user asked for a specific part. + +### 4. Optionally, cancel a running export + +If required by the user, a running export can be cancelled by calling `posthog:file-download-batch-exports-cancel-create` with the returned `id`. + +An export that has already finished or has already failed may not be cancelled. + +After cancelling an export, the `id` may not be used anymore and the export must start again from the beginning. However, you may still use the `id` to retrieve the export status (which will always be `Cancelled`). + +### 5. Download files through REST + +Use a direct authenticated HTTP request to the existing endpoint: + +```text +GET /api/projects/{project_id}/file_download_batch_exports/{run_id}/download/{part}/ +``` + +`part` can be either: + +- a file UUID from the `files` array returned by `file-download-batch-exports-retrieve` +- a zero-based file index, ordered by key + +If there is only one file, this also works without `part`: + +```text +GET /api/projects/{project_id}/file_download_batch_exports/{run_id}/download/ +``` + +Let the HTTP client follow the redirect, or inspect the `Location` header if you need the temporary signed URL. +Use the same PostHog authentication context as other API calls. + +### 6. Save, do not print, file contents + +Treat the result as a file download, not a chat response. +Parquet is binary and must be written as bytes. +JSONLines may still be large; save it to a file rather than pasting the contents unless the user explicitly asks for a tiny sample. + +Use a filename that includes the model, run ID, and part identifier when possible, for example: + +```text +posthog-events--.jsonl.gz +posthog-persons--.parquet +``` + +## Watch-outs + +- The maximum export interval is one week. Split longer user requests into separate export runs or ask which week to export. +- A run can briefly report `Running` after completion while file records are being created. Poll again instead of failing immediately. +- Download URLs are temporary. If a URL expires, call the REST download endpoint again for a fresh redirect. +- Do not send the signed URL to unrelated services unless the user explicitly asks; it grants temporary access to the exported file. +- If the user wants all parts of a split export, iterate over every UUID in `files`; do not assume part `0` is enough. +- Large batch exports may take a few minutes or even longer to complete. Suggest to the user that they can speed-up their download by including only certain events or narrowing the date range. diff --git a/skills/instrument-error-tracking/SKILL.md b/skills/instrument-error-tracking/SKILL.md index 0c05821..0f60ee1 100644 --- a/skills/instrument-error-tracking/SKILL.md +++ b/skills/instrument-error-tracking/SKILL.md @@ -13,7 +13,7 @@ metadata: Use this skill to add PostHog error tracking that captures and monitors exceptions in your application. Use it after implementing features or reviewing PRs to ensure errors are tracked with full stack traces and source maps. If PostHog is not yet installed, this skill also covers initial SDK setup. Supports any platform or language. -Supported platforms: React, Next.js, Web (JavaScript), Node.js, Python, Ruby, Ruby on Rails, Go, Angular, Svelte, Nuxt, React Native, Flutter, Android, and Hono. +Supported platforms: React, Next.js, Web (JavaScript), Node.js, Python, PHP, Ruby, Ruby on Rails, Go, Angular, Svelte, Nuxt, React Native, Flutter, Android, and Hono. ## Instructions @@ -65,8 +65,13 @@ STEP 8: Verify and clean up. - `references/nextjs.md` - Next.js error tracking installation - docs - `references/node.md` - Node.js error tracking installation - docs - `references/python.md` - Python error tracking installation - docs +- `references/django.md` - Django - docs +- `references/flask.md` - Flask - docs +- `references/php.md` - Php error tracking installation - docs +- `references/laravel.md` - Laravel - docs - `references/ruby.md` - Ruby error tracking installation - docs - `references/ruby-on-rails.md` - Ruby on rails error tracking installation - docs +- `references/ruby-on-rails.md` - Ruby on rails - docs - `references/go.md` - Go error tracking installation - docs - `references/angular.md` - Angular error tracking installation - docs - `references/svelte.md` - Sveltekit error tracking installation - docs diff --git a/skills/instrument-error-tracking/references/django.md b/skills/instrument-error-tracking/references/django.md new file mode 100644 index 0000000..af5d8ba --- /dev/null +++ b/skills/instrument-error-tracking/references/django.md @@ -0,0 +1,259 @@ +# Django - Docs + +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. + +This guide walks you through integrating PostHog into your Django app using the [Python SDK](/docs/libraries/python.md). + +## Beta: integration via LLM + +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. + +`npx @posthog/wizard@latest` + +[Learn more](/wizard.md) + +Or, to integrate manually, continue with the rest of this guide. + +## Installation + +To start, run `pip install posthog` to install PostHog’s Python SDK. + +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, configure PostHog in your app config so it's initialized when Django starts: + +your\_app/apps.py + +PostHog AI + +```python +from django.apps import AppConfig +import posthog +class YourAppConfig(AppConfig): + name = 'your_app_name' + def ready(self): + posthog.api_key = '' + posthog.host = 'https://us.i.posthog.com' +``` + +Next, if you haven't done so already, add your `AppConfig` to `INSTALLED_APPS` in `settings.py`: + +settings.py + +PostHog AI + +```python +INSTALLED_APPS = [ + # ... other apps + 'your_app_name.apps.YourAppConfig', +] +``` + +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +To capture events from any file, import `posthog` and call the method you need. For example: + +Python + +PostHog AI + +```python +import posthog +from posthog import identify_context +def some_request(request): + with posthog.new_context(): + # Django includes request.user for anonymous visitors too. Only identify + # the context when the visitor is logged in. + if request.user.is_authenticated: + identify_context(str(request.user.pk)) + posthog.capture('event_name') +``` + +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. + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Django contexts middleware + +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 tags all events captured during that request with relevant metadata. + +### Basic setup + +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. + +Python + +PostHog AI + +```python +MIDDLEWARE = [ + # ... other middleware + 'posthog.integrations.django.PosthogContextMiddleware', + # ... other middleware +] +``` + +The middleware uses the globally configured `posthog` client by default, so you don't need to create or pass it a separate client instance. + +The middleware automatically extracts and uses: + +- **Session ID** from the `X-POSTHOG-SESSION-ID` header, if present +- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present, falling back to the authenticated Django user's `pk` (Django's primary-key alias, which works with custom user models) +- **User email** from the authenticated Django user's `email` as `email` +- **Current URL** as `$current_url` +- **Request method** as `$request_method` +- **Request path** as `$request_path` +- **Forwarded IP address** from `X-Forwarded-For` as `$ip` +- **User agent** from `User-Agent` as `$user_agent` + +The session and distinct ID headers are sanitized before use. Empty values are ignored, control characters are removed, values are trimmed, and values are capped at 1000 characters. + +All events captured during the request (including exceptions) include these properties and are associated with the extracted session and distinct ID. + +If you are using PostHog on your frontend, the JavaScript Web SDK will add the session and distinct ID headers automatically if you enable tracing headers. + +JavaScript + +PostHog AI + +```javascript +posthog.init('', { + __add_tracing_headers: ['your-backend-domain.com'] +}) +``` + +### Exception capture + +By default, the middleware captures exceptions and sends them to PostHog's error tracking using the globally configured `posthog` client. This includes Django view exceptions that Django converts into error responses. + +Disable this by setting: + +Python + +PostHog AI + +```python +# settings.py +POSTHOG_MW_CAPTURE_EXCEPTIONS = False +``` + +### Adding custom tags + +Use `POSTHOG_MW_EXTRA_TAGS` to add custom properties to all requests: + +Python + +PostHog AI + +```python +# settings.py +def add_user_tags(request): + # type: (HttpRequest) -> Dict[str, Any] + tags = {} + if hasattr(request, 'user') and request.user.is_authenticated: + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) + tags['email'] = request.user.email + return tags +POSTHOG_MW_EXTRA_TAGS = add_user_tags +``` + +#### Filtering requests + +Skip tracking for certain requests using `POSTHOG_MW_REQUEST_FILTER`: + +Python + +PostHog AI + +```python +# settings.py +def should_track_request(request): + # type: (HttpRequest) -> bool + # Don't track health checks or admin requests + if request.path.startswith('/health') or request.path.startswith('/admin'): + return False + return True +POSTHOG_MW_REQUEST_FILTER = should_track_request +``` + +### Modifying default tags + +Use `POSTHOG_MW_TAG_MAP` to modify or remove default tags: + +Python + +PostHog AI + +```python +# settings.py +def customize_tags(tags): + # type: (Dict[str, Any]) -> Dict[str, Any] + # Remove URL for privacy + tags.pop('$current_url', None) + # Add custom prefix to method + if '$request_method' in tags: + tags['http_method'] = tags.pop('$request_method') + return tags +POSTHOG_MW_TAG_MAP = customize_tags +``` + +### Complete configuration example + +Python + +PostHog AI + +```python +# settings.py +def add_request_context(request): + # type: (HttpRequest) -> Dict[str, Any] + tags = {} + if hasattr(request, 'user') and request.user.is_authenticated: + tags['user_type'] = 'authenticated' + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) + else: + tags['user_type'] = 'anonymous' + # Add request info + tags['user_agent'] = request.META.get('HTTP_USER_AGENT', '') + return tags +def filter_tracking(request): + # type: (HttpRequest) -> bool + # Skip internal endpoints + return not request.path.startswith(('/health', '/metrics', '/admin')) +def clean_tags(tags): + # type: (Dict[str, Any]) -> Dict[str, Any] + # Remove sensitive data + tags.pop('user_agent', None) + return tags +POSTHOG_MW_EXTRA_TAGS = add_request_context +POSTHOG_MW_REQUEST_FILTER = filter_tracking +POSTHOG_MW_TAG_MAP = clean_tags +POSTHOG_MW_CAPTURE_EXCEPTIONS = True +``` + +All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers or Django authentication. + +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. + +## Next steps + +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). + +Alternatively, the following tutorials can help you get started: + +- [Setting up Django analytics, feature flags, and more](/tutorials/django-analytics.md) +- [How to set up A/B tests in Django](/tutorials/django-ab-tests.md) + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-error-tracking/references/flask.md b/skills/instrument-error-tracking/references/flask.md new file mode 100644 index 0000000..e8ec7bf --- /dev/null +++ b/skills/instrument-error-tracking/references/flask.md @@ -0,0 +1,113 @@ +# Flask - Docs + +PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, error tracking, and more. + +This guide walks you through integrating PostHog into your Flask app using the [Python SDK](/docs/libraries/python.md). + +## Installation + +To start, run `pip install posthog` to install PostHog’s Python SDK. + +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, initialize PostHog where you'd like to use it. For example, here's how to capture an event in a simple route: + +app.py + +PostHog AI + +```python +from flask import Flask +from posthog import Posthog +app = Flask(__name__) +posthog = Posthog( + '', + host='https://us.i.posthog.com', +) +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + posthog.capture( + 'dashboard_api_called', + distinct_id='distinct_id_of_your_user', + ) + return '', 204 +``` + +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Request contexts + +Use [contexts](/docs/libraries/python.md#contexts) to share identity, session IDs, and tags across multiple captures during a request: + +Python + +PostHog AI + +```python +from flask import request, session +from posthog import identify_context, set_context_session, tag +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + with posthog.new_context(): + distinct_id = request.headers.get('X-POSTHOG-DISTINCT-ID') or session.get('user_id') + if distinct_id: + identify_context(str(distinct_id)) + session_id = request.headers.get('X-POSTHOG-SESSION-ID') + if session_id: + set_context_session(session_id) + tag('$current_url', request.url) + tag('$request_method', request.method) + tag('$request_path', request.path) + posthog.capture('dashboard_api_called') + return '', 204 +``` + +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. + +## Error tracking + +Flask has built-in error handlers. This means PostHog’s default exception autocapture won’t work and we need to manually capture errors instead using `capture_exception()`: + +Python + +PostHog AI + +```python +from flask import Flask, jsonify +from posthog import Posthog +app = Flask(__name__) +posthog = Posthog('', host='https://us.i.posthog.com') +@app.errorhandler(Exception) +def handle_exception(e): + # Capture methods, including capture_exception, return the UUID of the captured event, + # which you can use to find specific errors users encountered + event_id = posthog.capture_exception(e) + # You can show the event ID to your user, and ask them to include it in bug reports + response = jsonify({'message': str(e), 'error_id': event_id}) + response.status_code = 500 + return response +``` + +## Next steps + +For any technical questions for how to integrate specific PostHog features into Flask (such as analytics, feature flags, A/B testing, etc.), have a look at our [Python SDK docs](/docs/libraries/python.md). + +Alternatively, the following tutorials can help you get started: + +- [How to set up analytics in Python and Flask](/tutorials/python-analytics.md) +- [How to set up feature flags in Python and Flask](/tutorials/python-feature-flags.md) +- [How to set up A/B tests in Python and Flask](/tutorials/python-ab-testing.md) + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-error-tracking/references/laravel.md b/skills/instrument-error-tracking/references/laravel.md new file mode 100644 index 0000000..022f900 --- /dev/null +++ b/skills/instrument-error-tracking/references/laravel.md @@ -0,0 +1,150 @@ +# Laravel - Docs + +PostHog integrates with Laravel through the [PostHog PHP SDK](/docs/libraries/php.md). This page covers Laravel-specific setup. For SDK features such as event capture, identifying users, feature flags, group analytics, and configuration options, see the [PHP SDK docs](/docs/libraries/php.md). + +## Installation + +Install the PHP SDK as described in the [PHP installation guide](/docs/libraries/php.md#installation), then add your project token and host to `.env`: + +.env + +PostHog AI + +```bash +POSTHOG_API_KEY= +POSTHOG_HOST=https://us.i.posthog.com +``` + +Add PostHog to Laravel's services config: + +config/services.php + +PostHog AI + +```php +'posthog' => [ + 'api_key' => env('POSTHOG_API_KEY'), + 'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'), +], +``` + +Initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: + +app/Providers/AppServiceProvider.php + +PostHog AI + +```php + config('services.posthog.host'), + ] + ); + } +} +``` + +## Request context middleware + +Client SDKs such as [PostHog JS](/docs/libraries/js.md) can send tracing headers to your Laravel backend. The PHP SDK can read `X-PostHog-Distinct-Id` and `X-PostHog-Session-Id` headers and apply them to events captured during the request. Add middleware like this: + +app/Http/Middleware/PostHogRequestContext.php + +PostHog AI + +```php +headers->all()); + $context['properties'] = array_merge( + $context['properties'] ?? [], + array_filter([ + '$current_url' => $request->fullUrl(), + '$request_method' => $request->method(), + '$request_path' => $request->getPathInfo(), + '$user_agent' => $request->userAgent(), + '$ip' => $request->ip(), + ], static fn ($value): bool => $value !== null && $value !== '') + ); + return PostHog::withContext( + $context, + static fn (): Response => $next($request), + ['fresh' => true] + ); + } +} +``` + +Register this middleware using your Laravel version's normal middleware registration. + +## Error tracking in Laravel + +The PHP SDK supports [error tracking](/docs/libraries/php.md#error-tracking), but Laravel handles most request exceptions before they become uncaught PHP exceptions. Capture Laravel-reported exceptions explicitly. + +In Laravel 11 and later, add a report callback in `bootstrap/app.php`: + +bootstrap/app.php + +PostHog AI + +```php +use Illuminate\Foundation\Configuration\Exceptions; +use PostHog\PostHog; +use Throwable; +->withExceptions(function (Exceptions $exceptions): void { + $exceptions->report(function (Throwable $e): void { + if (! config('services.posthog.api_key')) { + return; + } + PostHog::captureException( + $e, + auth()->id() !== null ? (string) auth()->id() : null, + [ + '$current_url' => request()->fullUrl(), + '$request_method' => request()->method(), + ] + ); + }); +}) +``` + +For older Laravel versions, call `PostHog::captureException()` from your exception handler's `report` method. + +## Long-running processes + +In normal PHP request lifecycles, queued events flush when the client is destroyed. In long-running Laravel processes such as queue workers, Horizon, or Octane, call `PostHog::flush()` after capturing important events or at the end of a job/request. + +## Next steps + +See the [PHP SDK docs](/docs/libraries/php.md) for usage examples and the full API reference. + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-error-tracking/references/nuxt.md b/skills/instrument-error-tracking/references/nuxt.md index 9356c06..e68ffce 100644 --- a/skills/instrument-error-tracking/references/nuxt.md +++ b/skills/instrument-error-tracking/references/nuxt.md @@ -65,7 +65,7 @@ }, sourcemaps: { enabled: true, - project: '', // Your project ID from PostHog settings https://app.posthog.com/settings/environment#variables + projectId: '', // Your project ID, found in your environment settings: https://app.posthog.com/settings/environment#variables personalApiKey: '', // Your personal API key from PostHog settings https://app.posthog.com/settings/user-api-keys (requires organization:read and error_tracking:write scopes) releaseName: 'my-application', // Optional: defaults to git repository name releaseVersion: '1.0.0', // Optional: defaults to current git commit diff --git a/skills/instrument-error-tracking/references/php.md b/skills/instrument-error-tracking/references/php.md new file mode 100644 index 0000000..4e7c67d --- /dev/null +++ b/skills/instrument-error-tracking/references/php.md @@ -0,0 +1,222 @@ +# PHP Error Tracking installation - Docs + +1. 1 + + ## Install the PHP SDK + + Required + + Install the [PostHog PHP SDK](/docs/libraries/php.md) via Composer: + + Terminal + + PostHog AI + + ```bash + composer require posthog/posthog-php + ``` + +2. 2 + + ## Initialize the client + + Required + + Set your project token and instance address before making any calls: + + PHP + + PostHog AI + + ```php + PostHog\PostHog::init( + '', + ['host' => 'https://us.i.posthog.com'] + ); + ``` + + You can find your project token and instance address in the [project settings](https://app.posthog.com/settings/project) page in PostHog. + +3. 3 + + ## Capture exceptions + + Required + + Use `captureException` to manually capture exceptions and send them to PostHog as `$exception` events with full stack traces. + + ### Basic usage + + PHP + + PostHog AI + + ```php + try { + // Your code that might throw + riskyOperation(); + } catch (\Throwable $e) { + PostHog\PostHog::captureException($e, 'user_distinct_id'); + } + ``` + + ### With additional properties + + You can pass extra properties to include with the exception event: + + PHP + + PostHog AI + + ```php + try { + processOrder($orderId); + } catch (\Throwable $e) { + PostHog\PostHog::captureException($e, 'user_distinct_id', [ + 'order_id' => $orderId, + 'environment' => 'production', + ]); + } + ``` + + You can also pass a plain string if you want to send an error message without a `Throwable`. + +4. 4 + + ## Enable automatic capture + + Recommended + + Automatic capture is opt-in for PHP. When enabled, the SDK installs handlers for uncaught exceptions. With the default `capture_errors: true`, it also captures PHP errors and fatal shutdown errors. + + PHP + + PostHog AI + + ```php + PostHog\PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + ], + ] + ); + ``` + + **Existing handlers are preserved** + + The SDK chains existing exception and error handlers instead of replacing your app's behavior. + +5. 5 + + ## Identify users and attach request context + + Recommended + + By default, automatically captured errors are anonymous. Use `context_provider` to attach a `distinctId` and request metadata to every automatically captured error event. + + PHP + + PostHog AI + + ```php + PostHog\PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + 'context_provider' => static function (array $payload): array { + return [ + 'distinctId' => $_SESSION['user_id'] ?? null, + 'properties' => [ + '$current_url' => $_SERVER['REQUEST_URI'] ?? null, + '$request_method' => $_SERVER['REQUEST_METHOD'] ?? null, + '$exception_source' => $payload['source'] ?? null, + ], + ]; + }, + ], + ] + ); + ``` + + If `distinctId` is omitted, PostHog sends the event with an auto-generated ID and sets `$process_person_profile` to `false`. + +6. 6 + + ## Configure error tracking options + + Optional + + PHP + + PostHog AI + + ```php + PostHog\PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + 'capture_errors' => true, + 'excluded_exceptions' => [ + \InvalidArgumentException::class, + ], + 'max_frames' => 20, + 'context_provider' => static function (array $payload): array { + return [ + 'distinctId' => $_SESSION['user_id'] ?? null, + 'properties' => [], + ]; + }, + ], + ] + ); + ``` + + | Option | Type | Default | Description | + | --- | --- | --- | --- | + | enabled | boolean | false | Enables automatic error tracking handlers. Manual captureException works regardless. | + | capture_errors | boolean | true | When enabled, also captures PHP errors and fatal shutdown errors in addition to uncaught exceptions. | + | excluded_exceptions | array of class strings | [] | Throwable classes to skip during automatic capture. | + | max_frames | integer | 20 | Maximum number of stack frames included in $exception_list. | + | context_provider | callable or null | null | Callback that returns distinctId and extra event properties for automatic captures. | + +7. ## Verify error tracking + + Recommended + + Trigger a test exception to confirm events are being sent to PostHog. You should see them appear in the [Error Tracking](https://app.posthog.com/error_tracking) tab. + + PHP + + PostHog AI + + ```php + PostHog\PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + ], + ] + ); + try { + throw new \Exception('Test exception from PHP'); + } catch (\Throwable $e) { + PostHog\PostHog::captureException($e, 'test_user'); + } + ``` + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-error-tracking/references/react.md b/skills/instrument-error-tracking/references/react.md index 88351b0..583df03 100644 --- a/skills/instrument-error-tracking/references/react.md +++ b/skills/instrument-error-tracking/references/react.md @@ -34,15 +34,15 @@ Required - Add your PostHog project token and host to your environment variables. For Vite-based React apps, use the `VITE_PUBLIC_` prefix: + Add your PostHog project token and host to your environment variables. For Vite-based React apps, use the `VITE_` prefix to expose them to the client: .env PostHog AI ```bash - VITE_PUBLIC_POSTHOG_PROJECT_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -64,12 +64,12 @@ import App from './App.jsx' import { PostHogProvider } from '@posthog/react' const options = { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', } as const createRoot(document.getElementById('root')).render( - + diff --git a/skills/instrument-error-tracking/references/ruby-on-rails.md b/skills/instrument-error-tracking/references/ruby-on-rails.md index de1d156..ad8cb5b 100644 --- a/skills/instrument-error-tracking/references/ruby-on-rails.md +++ b/skills/instrument-error-tracking/references/ruby-on-rails.md @@ -1,187 +1,590 @@ -# Ruby on Rails error tracking installation - Docs +# Ruby on Rails - Docs -1. 1 +PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom event capture, feature flags, and automatic exception tracking. - ## Install the gems +This guide walks you through integrating PostHog into your Rails app using the [posthog-rails gem](https://github.com/PostHog/posthog-ruby/tree/main/posthog-rails). - Required +## Beta: integration via LLM - Add the `posthog-ruby` and `posthog-rails` gems to your Gemfile: +Install PostHog for Rails 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. - Gemfile +`npx @posthog/wizard@latest` - PostHog AI +[Learn more](/wizard.md) - ```ruby - gem "posthog-ruby" - gem "posthog-rails" - ``` +Or, to integrate manually, continue with the rest of this guide. - Then run: +## Features - Terminal +- **Automatic exception tracking** – Captures unhandled and rescued exceptions +- **ActiveJob instrumentation** – Tracks background job exceptions +- **User context** – Automatically associates exceptions with the current user +- **Smart filtering** – Excludes common Rails exceptions (404s, etc.) by default +- **Request context** – Adds request metadata and optional PostHog tracing header identity/session context to captured events +- **Rails 7.0+ error reporter** – Integrates with Rails' built-in error reporting - PostHog AI +## Installation - ```bash - bundle install - ``` +Add both gems to your Gemfile: -2. 2 +Gemfile - ## Generate the initializer +PostHog AI - Required +```ruby +gem 'posthog-ruby' +gem 'posthog-rails' +``` - Run the install generator to create the PostHog initializer: +Then run: + +Terminal + +PostHog AI + +```bash +bundle install +``` + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +### Generate the initializer + +Run the install generator to create the PostHog initializer: + +Terminal + +PostHog AI + +```bash +rails generate posthog:install +``` + +This creates `config/initializers/posthog.rb` with sensible defaults and documentation. + +## Configuration + +`PostHog.init` creates a single client instance used across your app. Avoid creating multiple `PostHog::Client` instances with the same API key, as this can cause dropped events and inconsistent behavior. + +The generated initializer includes the most common options: + +config/initializers/posthog.rb + +PostHog AI + +```ruby +# Rails-specific configuration +PostHog::Rails.configure do |config| + config.auto_capture_exceptions = true # Enable automatic exception capture (default: false) + config.report_rescued_exceptions = true # Report exceptions Rails rescues (default: false) + config.auto_instrument_active_job = true # Instrument background jobs (default: false) + config.use_tracing_headers = true # Use PostHog tracing headers for identity/session context (default: true) + config.capture_user_context = true # Include authenticated user info in exceptions (default: true) + config.current_user_method = :current_user # Method to get current user (default: :current_user) + config.user_id_method = nil # Method to get ID from user object (default: auto-detect) + # Add additional exceptions to ignore + config.excluded_exceptions = ['MyCustomError'] +end +# Core PostHog client initialization +PostHog.init do |config| + # Required: Your PostHog project API key + config.api_key = '' + # Optional: Your PostHog instance URL + config.host = 'https://us.i.posthog.com' + # Optional: Personal API key for feature flags + config.personal_api_key = 'phx_xxxxxxxxx' + # Maximum number of events to queue before dropping (default: 10000) + config.max_queue_size = 10_000 + # Send events synchronously on the calling thread (default: false) + config.sync_mode = false + # Feature flags polling interval in seconds (default: 30) + config.feature_flags_polling_interval = 30 + # Feature flag request timeout in seconds (default: 3) + config.feature_flag_request_timeout_seconds = 3 + # Error callback to detect misconfiguration + config.on_error = proc { |status, msg| + Rails.logger.error("PostHog error: #{msg}") + } + # Before-send callback to modify or drop events + config.before_send = proc { |event| + event[:properties] ||= {} + event[:properties]['environment'] = Rails.env + event + } + # Disable network calls in test mode + config.test_mode = true if Rails.env.test? +end +``` + +You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). + +> **Tip:** Use [`Rails.application.credentials`](https://guides.rubyonrails.org/security.html#custom-credentials) to avoid hardcoding API keys. First, add your keys and then reference them in your initializer: +> +> Terminal +> +> PostHog AI +> +> ```bash +> rails credentials:edit +> ``` +> +> config/credentials.yml.enc +> +> PostHog AI +> +> ```yaml +> posthog: +> api_key: +> host: https://us.i.posthog.com +> personal_api_key: phx_xxxxxxxxx +> ``` +> +> config/initializers/posthog.rb +> +> PostHog AI +> +> ```ruby +> config.api_key = Rails.application.credentials.posthog[:api_key] +> config.host = Rails.application.credentials.posthog[:host] +> config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key] +> ``` + +## Capturing events + +Track custom events anywhere in your Rails app: + +Ruby + +PostHog AI + +```ruby +PostHog.capture({ + distinct_id: current_user.id, + event: 'post_created', + properties: { title: @post.title } +}) +``` + +Identify a user and set their person properties: + +Ruby + +PostHog AI + +```ruby +PostHog.identify({ + distinct_id: current_user.id, + properties: { + email: current_user.email, + plan: current_user.plan + } +}) +``` + +The Rails integration delegates methods like `capture`, `identify`, `alias`, `group_identify`, `evaluate_flags`, `capture_exception`, `flush`, and `shutdown` to the initialized `PostHog::Client`. + +## Request context + +PostHog Rails automatically applies request-scoped context to events captured during web requests. Request metadata such as `$current_url`, `$request_method`, `$request_path`, `$user_agent`, and `$ip` is added to event properties. + +When `use_tracing_headers` is enabled, PostHog tracing headers (`X-PostHog-Distinct-Id` and `X-PostHog-Session-Id`) are also used as default `distinct_id` and `$session_id` values. Explicit `distinct_id` and properties passed to `PostHog.capture` always take precedence. + +Disable tracing header identity/session capture if you do not want client-supplied tracing headers used for server-side events. Request metadata is still captured: - Terminal +Ruby - PostHog AI +PostHog AI - ```bash - rails generate posthog:install - ``` +```ruby +PostHog::Rails.config.use_tracing_headers = false +``` - This will create `config/initializers/posthog.rb` with sensible defaults and documentation. +## Error tracking -3. 3 +For full details on setting up error tracking with Rails, see our [Rails error tracking installation guide](/docs/error-tracking/installation/ruby-on-rails.md). - ## Configure PostHog +### Automatic exception tracking - Required +When `auto_capture_exceptions` is enabled, exceptions are automatically captured: - Update `config/initializers/posthog.rb` with your project token and host: +Ruby - config/initializers/posthog.rb +PostHog AI - PostHog AI +```ruby +class PostsController < ApplicationController + def show + @post = Post.find(params[:id]) + # Any exception here is automatically captured + end +end +``` - ```ruby - PostHog.init do |config| - config.api_key = '' - config.host = 'https://us.i.posthog.com' - end - ``` +`report_rescued_exceptions` controls whether exceptions Rails rescues (for example, exceptions rendered by Rails error pages) are captured. Enable it along with `auto_capture_exceptions` for complete error visibility, or leave it disabled to capture only unhandled exceptions. -4. 4 +### Manual exception capture - ## Send events +You can also manually capture exceptions: - Recommended +Ruby - Once installed, you can manually send events to test your integration: +PostHog AI - Ruby +```ruby +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' } +) +``` - PostHog AI +If you evaluated feature flags for the request, pass the same snapshot to include matching flag properties on the exception event: - ```ruby - PostHog.capture({ - distinct_id: 'user_123', - event: 'button_clicked', - properties: { - button_name: 'signup' - } - }) - ``` +Ruby -5. 5 +PostHog AI - ## Configure error tracking +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' }, + flags: flags +) +``` - Required +### Background job exceptions - Update `config/initializers/posthog.rb` to enable automatic exception capture: +When `auto_instrument_active_job` is enabled, ActiveJob exceptions are automatically captured with job context: - config/initializers/posthog.rb +Ruby - PostHog AI +PostHog AI - ```ruby - PostHog::Rails.configure do |config| - config.auto_capture_exceptions = true - config.report_rescued_exceptions = true - config.auto_instrument_active_job = true - config.capture_user_context = true - config.current_user_method = :current_user - end - ``` +```ruby +class EmailJob < ApplicationJob + def perform(user_id) + user = User.find(user_id) + UserMailer.welcome(user).deliver_now + # Exceptions are automatically captured + end +end +``` -6. 6 +#### Associating jobs with users - ## Automatic exception capture +By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key in hash arguments: - Recommended +Ruby - With `auto_capture_exceptions` enabled, exceptions are automatically captured from your controllers: +PostHog AI - app/controllers/posts\_controller.rb +```ruby +# PostHog will automatically use options[:user_id] as the distinct_id +ProcessOrderJob.perform_later(order.id, user_id: current_user.id) +``` - PostHog AI +For more control, use the `posthog_distinct_id` class method. The proc or block receives the same arguments as `perform`: - ```ruby - class PostsController < ApplicationController - def show - @post = Post.find(params[:id]) - # Any exception here is automatically captured - end +Ruby + +PostHog AI + +```ruby +class SendWelcomeEmailJob < ApplicationJob + posthog_distinct_id ->(user, _options) { user.id } + def perform(user, options = {}) + UserMailer.welcome(user).deliver_now + end +end +``` + +You can also use a block: + +Ruby + +PostHog AI + +```ruby +class ProcessOrderJob < ApplicationJob + posthog_distinct_id do |_order, notify_user_id| + notify_user_id + end + def perform(order, notify_user_id) + # Process the order... + end +end +``` + +### Rails 7.0+ error reporter + +PostHog integrates with Rails' built-in error reporting: + +Ruby + +PostHog AI + +```ruby +# These errors are automatically sent to PostHog +Rails.error.handle do + # Code that might raise an error +end +Rails.error.record(exception, context: { user_id: current_user.id }) +``` + +PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. Other context keys are included as properties on the exception event. + +### User context + +PostHog Rails automatically captures authenticated user information from your controllers for exceptions. Authenticated Rails user context takes precedence over client-supplied tracing headers for exception identity. + +If your user method has a different name, configure it: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.current_user_method = :logged_in_user +``` + +#### User ID extraction + +By default, PostHog Rails auto-detects the user's distinct ID by trying these methods in order: + +1. `posthog_distinct_id` – Define this on your User model for full control +2. `distinct_id` – Common analytics convention +3. `id` – Standard ActiveRecord primary key +4. `pk` – Primary key alias +5. `uuid` – For UUID-based primary keys + +It also checks hash-like users for `id`, `pk`, and `uuid` keys. + +You can configure a specific method: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.user_id_method = :email +``` + +Or define a method on your User model: + +Ruby + +PostHog AI + +```ruby +class User < ApplicationRecord + def posthog_distinct_id + "user_#{id}" # or external_id, or any unique identifier + end +end +``` + +### Excluded exceptions + +The following exceptions are not reported by default (common 4xx errors): + +- `AbstractController::ActionNotFound` +- `ActionController::BadRequest` +- `ActionController::InvalidAuthenticityToken` +- `ActionController::InvalidCrossOriginRequest` +- `ActionController::MethodNotAllowed` +- `ActionController::NotImplemented` +- `ActionController::ParameterMissing` +- `ActionController::RoutingError` +- `ActionController::UnknownFormat` +- `ActionController::UnknownHttpMethod` +- `ActionDispatch::Http::Parameters::ParseError` +- `ActiveRecord::RecordNotFound` +- `ActiveRecord::RecordNotUnique` + +Add more with: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.excluded_exceptions = ['MyException'] +``` + +## Feature flags + +Evaluate flags once for the current user, then read values from the returned snapshot: + +Ruby + +PostHog AI + +```ruby +class PostsController < ApplicationController + def show + flags = PostHog.evaluate_flags(current_user.id) + if flags.enabled?('new-post-design') + render 'posts/show_new' + else + render 'posts/show' end - ``` + end +end +``` + +For multivariate flags and experiments, use `get_flag`: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +variant = flags.get_flag('checkout-experiment') +if variant == 'test' + # Do something differently +end +``` + +When capturing an event after branching on a flag, pass the same `flags` snapshot so the event includes the exact flag values used by your code: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture({ + distinct_id: current_user.id, + event: 'checkout_started', + flags: flags.only_accessed +}) +``` + +For local evaluation, ensure you've set `personal_api_key`: -7. 7 +Ruby - ## Background jobs +PostHog AI - Optional +```ruby +config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key] +``` - When `auto_instrument_active_job` is enabled, ActiveJob exceptions are automatically captured: +See our [Ruby SDK docs](/docs/libraries/ruby.md#local-evaluation) for details on local evaluation with Puma and Unicorn servers. - app/jobs/email\_job.rb +> **Note:** `PostHog.is_feature_enabled`, `PostHog.get_feature_flag`, `PostHog.get_feature_flag_result`, `PostHog.get_feature_flag_payload`, and `PostHog.capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `PostHog.evaluate_flags` for new code. + +## Testing + +In your test environment, disable network calls with test mode: + +config/environments/test.rb + +PostHog AI + +```ruby +PostHog.init do |config| + config.api_key = '' + config.test_mode = true +end +``` + +Or in your specs: + +spec/rails\_helper.rb + +PostHog AI + +```ruby +RSpec.configure do |config| + config.before(:each) do + allow(PostHog).to receive(:capture) + end +end +``` + +## Configuration reference + +### Core PostHog options + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. | +| personal_api_key | String | nil | Personal API key for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error). | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | + +The `PostHog.init` block supports the options above. Less common core options like `batch_size`, `disable_singleton_warning`, `skip_ssl_verification`, and the experimental `flag_definition_cache_provider` can be passed as an options hash to `PostHog.init(...)`; see the [Ruby SDK docs](/docs/libraries/ruby.md#configuration) for details. + +### Rails-specific options + +Configure these via `PostHog::Rails.configure` or `PostHog::Rails.config`: + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| auto_capture_exceptions | Boolean | false | Automatically capture exceptions. | +| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues. | +| auto_instrument_active_job | Boolean | false | Capture ActiveJob exceptions with job context. | +| excluded_exceptions | Array | [] | Additional exception class names to ignore. | +| use_tracing_headers | Boolean | true | Use X-PostHog-Distinct-Id and X-PostHog-Session-Id as request-scoped defaults. | +| capture_user_context | Boolean | true | Include authenticated user info in exceptions. | +| current_user_method | Symbol | :current_user | Controller method used to fetch the current user. | +| user_id_method | Symbol | nil | Method used to extract the distinct ID from the user object. Auto-detects when nil. | + +## Troubleshooting + +### Exceptions not being captured + +1. Verify PostHog is initialized: + + Ruby PostHog AI ```ruby - class EmailJob < ApplicationJob - def perform(user_id) - user = User.find(user_id) - UserMailer.welcome(user).deliver_now - # Exceptions are automatically captured with job context - end - end + Rails.console + > PostHog.initialized? + => true ``` -8. 8 - - ## Manually capture exceptions - - Optional +2. Check your excluded exceptions list. - You can also manually capture exceptions that you handle in your application: +3. Verify middleware is installed: Ruby PostHog AI ```ruby - PostHog.capture_exception( - exception, - current_user.id, - { custom_property: 'value' } - ) + Rails.application.middleware ``` -9. ## Verify error tracking +### User context not working - Recommended +1. Verify `current_user_method` matches your controller method. +2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, `id`, `pk`, or `uuid`. +3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method`. - *Confirm events are being sent to PostHog* +### Feature flags not working - Before proceeding, let's make sure exception events are being captured and sent to PostHog. You should see events appear in the activity feed. +Ensure you've set `personal_api_key` in your configuration. - ![Activity feed with events](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250729_ouxl_f788dd8cd2.png)![Activity feed with events](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250729_owae_7c3490822c.png) +## Next steps - [Check for exceptions in PostHog](https://app.posthog.com/activity/explore) +For any technical questions for how to integrate specific PostHog features into Rails (such as analytics, feature flags, A/B testing, etc.), have a look at our [Ruby SDK docs](/docs/libraries/ruby.md). ### Community questions diff --git a/skills/instrument-error-tracking/references/ruby.md b/skills/instrument-error-tracking/references/ruby.md index 337af28..214ef13 100644 --- a/skills/instrument-error-tracking/references/ruby.md +++ b/skills/instrument-error-tracking/references/ruby.md @@ -80,8 +80,8 @@ rescue => e posthog.capture_exception( e, - distinct_id: 'user_distinct_id', - properties: { + 'user_distinct_id', + { custom_property: 'custom_value' } ) @@ -94,7 +94,7 @@ | --- | --- | --- | | exception | Exception | The exception object to capture (required) | | distinct_id | String | The distinct ID of the user (optional) | - | properties | Hash | Additional properties to attach to the exception event (optional) | + | additional_properties | Hash | Additional properties to attach to the exception event (optional) | 5. ## Verify error tracking diff --git a/skills/instrument-feature-flags/SKILL.md b/skills/instrument-feature-flags/SKILL.md index af51634..e308f44 100644 --- a/skills/instrument-feature-flags/SKILL.md +++ b/skills/instrument-feature-flags/SKILL.md @@ -55,8 +55,12 @@ STEP 6: Set up environment variables. - `references/web.md` - Web feature flags installation - docs - `references/nodejs.md` - Node.js feature flags installation - docs - `references/python.md` - Python feature flags installation - docs +- `references/django.md` - Django - docs +- `references/flask.md` - Flask - docs - `references/php.md` - Php feature flags installation - docs +- `references/laravel.md` - Laravel - docs - `references/ruby.md` - Ruby feature flags installation - docs +- `references/ruby-on-rails.md` - Ruby on rails - docs - `references/go.md` - Go feature flags installation - docs - `references/java.md` - Java feature flags installation - docs - `references/rust.md` - Rust feature flags installation - docs diff --git a/skills/instrument-feature-flags/references/adding-feature-flag-code.md b/skills/instrument-feature-flags/references/adding-feature-flag-code.md index 718d475..b23a8eb 100644 --- a/skills/instrument-feature-flags/references/adding-feature-flag-code.md +++ b/skills/instrument-feature-flags/references/adding-feature-flag-code.md @@ -65,6 +65,24 @@ The `onFeatureFlags` callback receives the following parameters: You won't usually need to use these, but they are useful if you want to be extra careful about feature flags not being loaded yet because of a network error and/or a network timeout (see `feature_flag_request_timeout_ms`). +### Evaluating only specific flags + +By default, the JavaScript SDK requests that every eligible feature flag be evaluated for the current user. If you'd only like to evaluate and return a subset of flags, pass `flag_keys` when initializing PostHog: + +Web + +PostHog AI + +```javascript +posthog.init('', { + api_host: 'https://us.i.posthog.com', + defaults: '2026-01-30', + flag_keys: ['checkout-flow', 'new-dashboard'], +}) +``` + +PostHog scopes evaluation and the response to those keys for this SDK instance. Dependency flags required to evaluate requested flags may also be evaluated and returned. Leave `flag_keys` unset to evaluate all eligible flags. + ### Reloading feature flags Feature flag values are cached. If something has changed with your user and you'd like to refetch their flag values, call: @@ -896,6 +914,8 @@ if ($enabledVariant === 'variant-key') { // replace 'variant-key' with the key o `$flags->getFlag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `null` when the flag wasn't returned by the evaluation. +You can also call `$flags->getKeys()` to list the evaluated flag keys, or `$flags->getEventProperties()` to get the `$feature/` and `$active_feature_flags` properties that would be attached to a captured event. + > **Note:** `PostHog::isFeatureEnabled()`, `PostHog::getFeatureFlag()`, `PostHog::getFeatureFlagPayload()`, and `capture(['send_feature_flags' => true])` still work during the migration period, but they're deprecated. Prefer `evaluateFlags()` for new code. ### Step 2: Include feature flag information when capturing events @@ -985,11 +1005,31 @@ $flags = PostHog::evaluateFlags( ); ``` +### Optional evaluation parameters + +`evaluateFlags()` also accepts optional parameters for local evaluation and GeoIP behavior: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_your_user', + groups: ['company' => 'company_id_in_your_db'], + personProperties: ['plan' => 'pro'], + groupProperties: ['company' => ['employees' => 11]], + onlyEvaluateLocally: false, // Defaults to false. Set to true to avoid a remote fallback. + disableGeoip: false, // Defaults to false. Set to true to disable GeoIP enrichment during remote evaluation. + flagKeys: ['checkout-flow', 'new-dashboard'], +); +``` + ### Sending `$feature_flag_called` events Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluateFlags()`, the SDK sends this event when you call `$flags->isEnabled()` or `$flags->getFlag()` for a flag. -The SDK deduplicates these events per `(distinct_id, flag, value)` in a local cache. If you reinitialize the PostHog client, the cache resets and `$feature_flag_called` events may be sent again. PostHog handles duplicates, so duplicate `$feature_flag_called` events don't affect your analytics. +The SDK deduplicates these events per `(flag key, distinct_id)` in a local cache. If you reinitialize the PostHog client, the cache resets and `$feature_flag_called` events may be sent again. PostHog handles duplicates, so duplicate `$feature_flag_called` events don't affect your analytics. `$flags->getFlagPayload()` doesn't send `$feature_flag_called` events and doesn't count as an access for `onlyAccessed()`. @@ -1108,7 +1148,7 @@ end `flags.get_flag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `nil` when the flag wasn't returned by the evaluation. -> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_payload()`, and `capture(send_feature_flags: true)` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. +> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_result()`, `posthog.get_feature_flag_payload()`, and `capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. ### Step 2: Include feature flag information when capturing events @@ -1197,6 +1237,36 @@ flags = posthog.evaluate_flags( ) ``` +### Evaluating locally only + +If you want to skip the remote `/flags` request and only use locally cached definitions, pass `only_evaluate_locally: true`: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + only_evaluate_locally: true, +) +``` + +### Disabling GeoIP for flag evaluation + +Pass `disable_geoip: true` to disable GeoIP lookup for remote flag evaluation: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + disable_geoip: true, +) +``` + ### Sending `$feature_flag_called` events Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluate_flags()`, the SDK sends this event when you call `flags.enabled?()` or `flags.get_flag()` for a flag. diff --git a/skills/instrument-feature-flags/references/django.md b/skills/instrument-feature-flags/references/django.md new file mode 100644 index 0000000..af5d8ba --- /dev/null +++ b/skills/instrument-feature-flags/references/django.md @@ -0,0 +1,259 @@ +# Django - Docs + +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. + +This guide walks you through integrating PostHog into your Django app using the [Python SDK](/docs/libraries/python.md). + +## Beta: integration via LLM + +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. + +`npx @posthog/wizard@latest` + +[Learn more](/wizard.md) + +Or, to integrate manually, continue with the rest of this guide. + +## Installation + +To start, run `pip install posthog` to install PostHog’s Python SDK. + +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, configure PostHog in your app config so it's initialized when Django starts: + +your\_app/apps.py + +PostHog AI + +```python +from django.apps import AppConfig +import posthog +class YourAppConfig(AppConfig): + name = 'your_app_name' + def ready(self): + posthog.api_key = '' + posthog.host = 'https://us.i.posthog.com' +``` + +Next, if you haven't done so already, add your `AppConfig` to `INSTALLED_APPS` in `settings.py`: + +settings.py + +PostHog AI + +```python +INSTALLED_APPS = [ + # ... other apps + 'your_app_name.apps.YourAppConfig', +] +``` + +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +To capture events from any file, import `posthog` and call the method you need. For example: + +Python + +PostHog AI + +```python +import posthog +from posthog import identify_context +def some_request(request): + with posthog.new_context(): + # Django includes request.user for anonymous visitors too. Only identify + # the context when the visitor is logged in. + if request.user.is_authenticated: + identify_context(str(request.user.pk)) + posthog.capture('event_name') +``` + +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. + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Django contexts middleware + +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 tags all events captured during that request with relevant metadata. + +### Basic setup + +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. + +Python + +PostHog AI + +```python +MIDDLEWARE = [ + # ... other middleware + 'posthog.integrations.django.PosthogContextMiddleware', + # ... other middleware +] +``` + +The middleware uses the globally configured `posthog` client by default, so you don't need to create or pass it a separate client instance. + +The middleware automatically extracts and uses: + +- **Session ID** from the `X-POSTHOG-SESSION-ID` header, if present +- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present, falling back to the authenticated Django user's `pk` (Django's primary-key alias, which works with custom user models) +- **User email** from the authenticated Django user's `email` as `email` +- **Current URL** as `$current_url` +- **Request method** as `$request_method` +- **Request path** as `$request_path` +- **Forwarded IP address** from `X-Forwarded-For` as `$ip` +- **User agent** from `User-Agent` as `$user_agent` + +The session and distinct ID headers are sanitized before use. Empty values are ignored, control characters are removed, values are trimmed, and values are capped at 1000 characters. + +All events captured during the request (including exceptions) include these properties and are associated with the extracted session and distinct ID. + +If you are using PostHog on your frontend, the JavaScript Web SDK will add the session and distinct ID headers automatically if you enable tracing headers. + +JavaScript + +PostHog AI + +```javascript +posthog.init('', { + __add_tracing_headers: ['your-backend-domain.com'] +}) +``` + +### Exception capture + +By default, the middleware captures exceptions and sends them to PostHog's error tracking using the globally configured `posthog` client. This includes Django view exceptions that Django converts into error responses. + +Disable this by setting: + +Python + +PostHog AI + +```python +# settings.py +POSTHOG_MW_CAPTURE_EXCEPTIONS = False +``` + +### Adding custom tags + +Use `POSTHOG_MW_EXTRA_TAGS` to add custom properties to all requests: + +Python + +PostHog AI + +```python +# settings.py +def add_user_tags(request): + # type: (HttpRequest) -> Dict[str, Any] + tags = {} + if hasattr(request, 'user') and request.user.is_authenticated: + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) + tags['email'] = request.user.email + return tags +POSTHOG_MW_EXTRA_TAGS = add_user_tags +``` + +#### Filtering requests + +Skip tracking for certain requests using `POSTHOG_MW_REQUEST_FILTER`: + +Python + +PostHog AI + +```python +# settings.py +def should_track_request(request): + # type: (HttpRequest) -> bool + # Don't track health checks or admin requests + if request.path.startswith('/health') or request.path.startswith('/admin'): + return False + return True +POSTHOG_MW_REQUEST_FILTER = should_track_request +``` + +### Modifying default tags + +Use `POSTHOG_MW_TAG_MAP` to modify or remove default tags: + +Python + +PostHog AI + +```python +# settings.py +def customize_tags(tags): + # type: (Dict[str, Any]) -> Dict[str, Any] + # Remove URL for privacy + tags.pop('$current_url', None) + # Add custom prefix to method + if '$request_method' in tags: + tags['http_method'] = tags.pop('$request_method') + return tags +POSTHOG_MW_TAG_MAP = customize_tags +``` + +### Complete configuration example + +Python + +PostHog AI + +```python +# settings.py +def add_request_context(request): + # type: (HttpRequest) -> Dict[str, Any] + tags = {} + if hasattr(request, 'user') and request.user.is_authenticated: + tags['user_type'] = 'authenticated' + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) + else: + tags['user_type'] = 'anonymous' + # Add request info + tags['user_agent'] = request.META.get('HTTP_USER_AGENT', '') + return tags +def filter_tracking(request): + # type: (HttpRequest) -> bool + # Skip internal endpoints + return not request.path.startswith(('/health', '/metrics', '/admin')) +def clean_tags(tags): + # type: (Dict[str, Any]) -> Dict[str, Any] + # Remove sensitive data + tags.pop('user_agent', None) + return tags +POSTHOG_MW_EXTRA_TAGS = add_request_context +POSTHOG_MW_REQUEST_FILTER = filter_tracking +POSTHOG_MW_TAG_MAP = clean_tags +POSTHOG_MW_CAPTURE_EXCEPTIONS = True +``` + +All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers or Django authentication. + +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. + +## Next steps + +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). + +Alternatively, the following tutorials can help you get started: + +- [Setting up Django analytics, feature flags, and more](/tutorials/django-analytics.md) +- [How to set up A/B tests in Django](/tutorials/django-ab-tests.md) + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-feature-flags/references/flask.md b/skills/instrument-feature-flags/references/flask.md new file mode 100644 index 0000000..e8ec7bf --- /dev/null +++ b/skills/instrument-feature-flags/references/flask.md @@ -0,0 +1,113 @@ +# Flask - Docs + +PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, error tracking, and more. + +This guide walks you through integrating PostHog into your Flask app using the [Python SDK](/docs/libraries/python.md). + +## Installation + +To start, run `pip install posthog` to install PostHog’s Python SDK. + +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, initialize PostHog where you'd like to use it. For example, here's how to capture an event in a simple route: + +app.py + +PostHog AI + +```python +from flask import Flask +from posthog import Posthog +app = Flask(__name__) +posthog = Posthog( + '', + host='https://us.i.posthog.com', +) +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + posthog.capture( + 'dashboard_api_called', + distinct_id='distinct_id_of_your_user', + ) + return '', 204 +``` + +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Request contexts + +Use [contexts](/docs/libraries/python.md#contexts) to share identity, session IDs, and tags across multiple captures during a request: + +Python + +PostHog AI + +```python +from flask import request, session +from posthog import identify_context, set_context_session, tag +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + with posthog.new_context(): + distinct_id = request.headers.get('X-POSTHOG-DISTINCT-ID') or session.get('user_id') + if distinct_id: + identify_context(str(distinct_id)) + session_id = request.headers.get('X-POSTHOG-SESSION-ID') + if session_id: + set_context_session(session_id) + tag('$current_url', request.url) + tag('$request_method', request.method) + tag('$request_path', request.path) + posthog.capture('dashboard_api_called') + return '', 204 +``` + +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. + +## Error tracking + +Flask has built-in error handlers. This means PostHog’s default exception autocapture won’t work and we need to manually capture errors instead using `capture_exception()`: + +Python + +PostHog AI + +```python +from flask import Flask, jsonify +from posthog import Posthog +app = Flask(__name__) +posthog = Posthog('', host='https://us.i.posthog.com') +@app.errorhandler(Exception) +def handle_exception(e): + # Capture methods, including capture_exception, return the UUID of the captured event, + # which you can use to find specific errors users encountered + event_id = posthog.capture_exception(e) + # You can show the event ID to your user, and ask them to include it in bug reports + response = jsonify({'message': str(e), 'error_id': event_id}) + response.status_code = 500 + return response +``` + +## Next steps + +For any technical questions for how to integrate specific PostHog features into Flask (such as analytics, feature flags, A/B testing, etc.), have a look at our [Python SDK docs](/docs/libraries/python.md). + +Alternatively, the following tutorials can help you get started: + +- [How to set up analytics in Python and Flask](/tutorials/python-analytics.md) +- [How to set up feature flags in Python and Flask](/tutorials/python-feature-flags.md) +- [How to set up A/B tests in Python and Flask](/tutorials/python-ab-testing.md) + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-feature-flags/references/laravel.md b/skills/instrument-feature-flags/references/laravel.md new file mode 100644 index 0000000..022f900 --- /dev/null +++ b/skills/instrument-feature-flags/references/laravel.md @@ -0,0 +1,150 @@ +# Laravel - Docs + +PostHog integrates with Laravel through the [PostHog PHP SDK](/docs/libraries/php.md). This page covers Laravel-specific setup. For SDK features such as event capture, identifying users, feature flags, group analytics, and configuration options, see the [PHP SDK docs](/docs/libraries/php.md). + +## Installation + +Install the PHP SDK as described in the [PHP installation guide](/docs/libraries/php.md#installation), then add your project token and host to `.env`: + +.env + +PostHog AI + +```bash +POSTHOG_API_KEY= +POSTHOG_HOST=https://us.i.posthog.com +``` + +Add PostHog to Laravel's services config: + +config/services.php + +PostHog AI + +```php +'posthog' => [ + 'api_key' => env('POSTHOG_API_KEY'), + 'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'), +], +``` + +Initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: + +app/Providers/AppServiceProvider.php + +PostHog AI + +```php + config('services.posthog.host'), + ] + ); + } +} +``` + +## Request context middleware + +Client SDKs such as [PostHog JS](/docs/libraries/js.md) can send tracing headers to your Laravel backend. The PHP SDK can read `X-PostHog-Distinct-Id` and `X-PostHog-Session-Id` headers and apply them to events captured during the request. Add middleware like this: + +app/Http/Middleware/PostHogRequestContext.php + +PostHog AI + +```php +headers->all()); + $context['properties'] = array_merge( + $context['properties'] ?? [], + array_filter([ + '$current_url' => $request->fullUrl(), + '$request_method' => $request->method(), + '$request_path' => $request->getPathInfo(), + '$user_agent' => $request->userAgent(), + '$ip' => $request->ip(), + ], static fn ($value): bool => $value !== null && $value !== '') + ); + return PostHog::withContext( + $context, + static fn (): Response => $next($request), + ['fresh' => true] + ); + } +} +``` + +Register this middleware using your Laravel version's normal middleware registration. + +## Error tracking in Laravel + +The PHP SDK supports [error tracking](/docs/libraries/php.md#error-tracking), but Laravel handles most request exceptions before they become uncaught PHP exceptions. Capture Laravel-reported exceptions explicitly. + +In Laravel 11 and later, add a report callback in `bootstrap/app.php`: + +bootstrap/app.php + +PostHog AI + +```php +use Illuminate\Foundation\Configuration\Exceptions; +use PostHog\PostHog; +use Throwable; +->withExceptions(function (Exceptions $exceptions): void { + $exceptions->report(function (Throwable $e): void { + if (! config('services.posthog.api_key')) { + return; + } + PostHog::captureException( + $e, + auth()->id() !== null ? (string) auth()->id() : null, + [ + '$current_url' => request()->fullUrl(), + '$request_method' => request()->method(), + ] + ); + }); +}) +``` + +For older Laravel versions, call `PostHog::captureException()` from your exception handler's `report` method. + +## Long-running processes + +In normal PHP request lifecycles, queued events flush when the client is destroyed. In long-running Laravel processes such as queue workers, Horizon, or Octane, call `PostHog::flush()` after capturing important events or at the end of a job/request. + +## Next steps + +See the [PHP SDK docs](/docs/libraries/php.md) for usage examples and the full API reference. + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-feature-flags/references/react.md b/skills/instrument-feature-flags/references/react.md index 5e0244d..3a8e829 100644 --- a/skills/instrument-feature-flags/references/react.md +++ b/skills/instrument-feature-flags/references/react.md @@ -34,15 +34,15 @@ Required - Add your PostHog project token and host to your environment variables. For Vite-based React apps, use the `VITE_PUBLIC_` prefix: + Add your PostHog project token and host to your environment variables. For Vite-based React apps, use the `VITE_` prefix to expose them to the client: .env PostHog AI ```bash - VITE_PUBLIC_POSTHOG_PROJECT_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -64,12 +64,12 @@ import App from './App.jsx' import { PostHogProvider } from '@posthog/react' const options = { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', } as const createRoot(document.getElementById('root')).render( - + diff --git a/skills/instrument-feature-flags/references/ruby-on-rails.md b/skills/instrument-feature-flags/references/ruby-on-rails.md new file mode 100644 index 0000000..ad8cb5b --- /dev/null +++ b/skills/instrument-feature-flags/references/ruby-on-rails.md @@ -0,0 +1,595 @@ +# Ruby on Rails - Docs + +PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom event capture, feature flags, and automatic exception tracking. + +This guide walks you through integrating PostHog into your Rails app using the [posthog-rails gem](https://github.com/PostHog/posthog-ruby/tree/main/posthog-rails). + +## Beta: integration via LLM + +Install PostHog for Rails 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. + +`npx @posthog/wizard@latest` + +[Learn more](/wizard.md) + +Or, to integrate manually, continue with the rest of this guide. + +## Features + +- **Automatic exception tracking** – Captures unhandled and rescued exceptions +- **ActiveJob instrumentation** – Tracks background job exceptions +- **User context** – Automatically associates exceptions with the current user +- **Smart filtering** – Excludes common Rails exceptions (404s, etc.) by default +- **Request context** – Adds request metadata and optional PostHog tracing header identity/session context to captured events +- **Rails 7.0+ error reporter** – Integrates with Rails' built-in error reporting + +## Installation + +Add both gems to your Gemfile: + +Gemfile + +PostHog AI + +```ruby +gem 'posthog-ruby' +gem 'posthog-rails' +``` + +Then run: + +Terminal + +PostHog AI + +```bash +bundle install +``` + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +### Generate the initializer + +Run the install generator to create the PostHog initializer: + +Terminal + +PostHog AI + +```bash +rails generate posthog:install +``` + +This creates `config/initializers/posthog.rb` with sensible defaults and documentation. + +## Configuration + +`PostHog.init` creates a single client instance used across your app. Avoid creating multiple `PostHog::Client` instances with the same API key, as this can cause dropped events and inconsistent behavior. + +The generated initializer includes the most common options: + +config/initializers/posthog.rb + +PostHog AI + +```ruby +# Rails-specific configuration +PostHog::Rails.configure do |config| + config.auto_capture_exceptions = true # Enable automatic exception capture (default: false) + config.report_rescued_exceptions = true # Report exceptions Rails rescues (default: false) + config.auto_instrument_active_job = true # Instrument background jobs (default: false) + config.use_tracing_headers = true # Use PostHog tracing headers for identity/session context (default: true) + config.capture_user_context = true # Include authenticated user info in exceptions (default: true) + config.current_user_method = :current_user # Method to get current user (default: :current_user) + config.user_id_method = nil # Method to get ID from user object (default: auto-detect) + # Add additional exceptions to ignore + config.excluded_exceptions = ['MyCustomError'] +end +# Core PostHog client initialization +PostHog.init do |config| + # Required: Your PostHog project API key + config.api_key = '' + # Optional: Your PostHog instance URL + config.host = 'https://us.i.posthog.com' + # Optional: Personal API key for feature flags + config.personal_api_key = 'phx_xxxxxxxxx' + # Maximum number of events to queue before dropping (default: 10000) + config.max_queue_size = 10_000 + # Send events synchronously on the calling thread (default: false) + config.sync_mode = false + # Feature flags polling interval in seconds (default: 30) + config.feature_flags_polling_interval = 30 + # Feature flag request timeout in seconds (default: 3) + config.feature_flag_request_timeout_seconds = 3 + # Error callback to detect misconfiguration + config.on_error = proc { |status, msg| + Rails.logger.error("PostHog error: #{msg}") + } + # Before-send callback to modify or drop events + config.before_send = proc { |event| + event[:properties] ||= {} + event[:properties]['environment'] = Rails.env + event + } + # Disable network calls in test mode + config.test_mode = true if Rails.env.test? +end +``` + +You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). + +> **Tip:** Use [`Rails.application.credentials`](https://guides.rubyonrails.org/security.html#custom-credentials) to avoid hardcoding API keys. First, add your keys and then reference them in your initializer: +> +> Terminal +> +> PostHog AI +> +> ```bash +> rails credentials:edit +> ``` +> +> config/credentials.yml.enc +> +> PostHog AI +> +> ```yaml +> posthog: +> api_key: +> host: https://us.i.posthog.com +> personal_api_key: phx_xxxxxxxxx +> ``` +> +> config/initializers/posthog.rb +> +> PostHog AI +> +> ```ruby +> config.api_key = Rails.application.credentials.posthog[:api_key] +> config.host = Rails.application.credentials.posthog[:host] +> config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key] +> ``` + +## Capturing events + +Track custom events anywhere in your Rails app: + +Ruby + +PostHog AI + +```ruby +PostHog.capture({ + distinct_id: current_user.id, + event: 'post_created', + properties: { title: @post.title } +}) +``` + +Identify a user and set their person properties: + +Ruby + +PostHog AI + +```ruby +PostHog.identify({ + distinct_id: current_user.id, + properties: { + email: current_user.email, + plan: current_user.plan + } +}) +``` + +The Rails integration delegates methods like `capture`, `identify`, `alias`, `group_identify`, `evaluate_flags`, `capture_exception`, `flush`, and `shutdown` to the initialized `PostHog::Client`. + +## Request context + +PostHog Rails automatically applies request-scoped context to events captured during web requests. Request metadata such as `$current_url`, `$request_method`, `$request_path`, `$user_agent`, and `$ip` is added to event properties. + +When `use_tracing_headers` is enabled, PostHog tracing headers (`X-PostHog-Distinct-Id` and `X-PostHog-Session-Id`) are also used as default `distinct_id` and `$session_id` values. Explicit `distinct_id` and properties passed to `PostHog.capture` always take precedence. + +Disable tracing header identity/session capture if you do not want client-supplied tracing headers used for server-side events. Request metadata is still captured: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.use_tracing_headers = false +``` + +## Error tracking + +For full details on setting up error tracking with Rails, see our [Rails error tracking installation guide](/docs/error-tracking/installation/ruby-on-rails.md). + +### Automatic exception tracking + +When `auto_capture_exceptions` is enabled, exceptions are automatically captured: + +Ruby + +PostHog AI + +```ruby +class PostsController < ApplicationController + def show + @post = Post.find(params[:id]) + # Any exception here is automatically captured + end +end +``` + +`report_rescued_exceptions` controls whether exceptions Rails rescues (for example, exceptions rendered by Rails error pages) are captured. Enable it along with `auto_capture_exceptions` for complete error visibility, or leave it disabled to capture only unhandled exceptions. + +### Manual exception capture + +You can also manually capture exceptions: + +Ruby + +PostHog AI + +```ruby +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' } +) +``` + +If you evaluated feature flags for the request, pass the same snapshot to include matching flag properties on the exception event: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' }, + flags: flags +) +``` + +### Background job exceptions + +When `auto_instrument_active_job` is enabled, ActiveJob exceptions are automatically captured with job context: + +Ruby + +PostHog AI + +```ruby +class EmailJob < ApplicationJob + def perform(user_id) + user = User.find(user_id) + UserMailer.welcome(user).deliver_now + # Exceptions are automatically captured + end +end +``` + +#### Associating jobs with users + +By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key in hash arguments: + +Ruby + +PostHog AI + +```ruby +# PostHog will automatically use options[:user_id] as the distinct_id +ProcessOrderJob.perform_later(order.id, user_id: current_user.id) +``` + +For more control, use the `posthog_distinct_id` class method. The proc or block receives the same arguments as `perform`: + +Ruby + +PostHog AI + +```ruby +class SendWelcomeEmailJob < ApplicationJob + posthog_distinct_id ->(user, _options) { user.id } + def perform(user, options = {}) + UserMailer.welcome(user).deliver_now + end +end +``` + +You can also use a block: + +Ruby + +PostHog AI + +```ruby +class ProcessOrderJob < ApplicationJob + posthog_distinct_id do |_order, notify_user_id| + notify_user_id + end + def perform(order, notify_user_id) + # Process the order... + end +end +``` + +### Rails 7.0+ error reporter + +PostHog integrates with Rails' built-in error reporting: + +Ruby + +PostHog AI + +```ruby +# These errors are automatically sent to PostHog +Rails.error.handle do + # Code that might raise an error +end +Rails.error.record(exception, context: { user_id: current_user.id }) +``` + +PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. Other context keys are included as properties on the exception event. + +### User context + +PostHog Rails automatically captures authenticated user information from your controllers for exceptions. Authenticated Rails user context takes precedence over client-supplied tracing headers for exception identity. + +If your user method has a different name, configure it: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.current_user_method = :logged_in_user +``` + +#### User ID extraction + +By default, PostHog Rails auto-detects the user's distinct ID by trying these methods in order: + +1. `posthog_distinct_id` – Define this on your User model for full control +2. `distinct_id` – Common analytics convention +3. `id` – Standard ActiveRecord primary key +4. `pk` – Primary key alias +5. `uuid` – For UUID-based primary keys + +It also checks hash-like users for `id`, `pk`, and `uuid` keys. + +You can configure a specific method: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.user_id_method = :email +``` + +Or define a method on your User model: + +Ruby + +PostHog AI + +```ruby +class User < ApplicationRecord + def posthog_distinct_id + "user_#{id}" # or external_id, or any unique identifier + end +end +``` + +### Excluded exceptions + +The following exceptions are not reported by default (common 4xx errors): + +- `AbstractController::ActionNotFound` +- `ActionController::BadRequest` +- `ActionController::InvalidAuthenticityToken` +- `ActionController::InvalidCrossOriginRequest` +- `ActionController::MethodNotAllowed` +- `ActionController::NotImplemented` +- `ActionController::ParameterMissing` +- `ActionController::RoutingError` +- `ActionController::UnknownFormat` +- `ActionController::UnknownHttpMethod` +- `ActionDispatch::Http::Parameters::ParseError` +- `ActiveRecord::RecordNotFound` +- `ActiveRecord::RecordNotUnique` + +Add more with: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.excluded_exceptions = ['MyException'] +``` + +## Feature flags + +Evaluate flags once for the current user, then read values from the returned snapshot: + +Ruby + +PostHog AI + +```ruby +class PostsController < ApplicationController + def show + flags = PostHog.evaluate_flags(current_user.id) + if flags.enabled?('new-post-design') + render 'posts/show_new' + else + render 'posts/show' + end + end +end +``` + +For multivariate flags and experiments, use `get_flag`: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +variant = flags.get_flag('checkout-experiment') +if variant == 'test' + # Do something differently +end +``` + +When capturing an event after branching on a flag, pass the same `flags` snapshot so the event includes the exact flag values used by your code: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture({ + distinct_id: current_user.id, + event: 'checkout_started', + flags: flags.only_accessed +}) +``` + +For local evaluation, ensure you've set `personal_api_key`: + +Ruby + +PostHog AI + +```ruby +config.personal_api_key = Rails.application.credentials.posthog[:personal_api_key] +``` + +See our [Ruby SDK docs](/docs/libraries/ruby.md#local-evaluation) for details on local evaluation with Puma and Unicorn servers. + +> **Note:** `PostHog.is_feature_enabled`, `PostHog.get_feature_flag`, `PostHog.get_feature_flag_result`, `PostHog.get_feature_flag_payload`, and `PostHog.capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `PostHog.evaluate_flags` for new code. + +## Testing + +In your test environment, disable network calls with test mode: + +config/environments/test.rb + +PostHog AI + +```ruby +PostHog.init do |config| + config.api_key = '' + config.test_mode = true +end +``` + +Or in your specs: + +spec/rails\_helper.rb + +PostHog AI + +```ruby +RSpec.configure do |config| + config.before(:each) do + allow(PostHog).to receive(:capture) + end +end +``` + +## Configuration reference + +### Core PostHog options + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. | +| personal_api_key | String | nil | Personal API key for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error). | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | + +The `PostHog.init` block supports the options above. Less common core options like `batch_size`, `disable_singleton_warning`, `skip_ssl_verification`, and the experimental `flag_definition_cache_provider` can be passed as an options hash to `PostHog.init(...)`; see the [Ruby SDK docs](/docs/libraries/ruby.md#configuration) for details. + +### Rails-specific options + +Configure these via `PostHog::Rails.configure` or `PostHog::Rails.config`: + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| auto_capture_exceptions | Boolean | false | Automatically capture exceptions. | +| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues. | +| auto_instrument_active_job | Boolean | false | Capture ActiveJob exceptions with job context. | +| excluded_exceptions | Array | [] | Additional exception class names to ignore. | +| use_tracing_headers | Boolean | true | Use X-PostHog-Distinct-Id and X-PostHog-Session-Id as request-scoped defaults. | +| capture_user_context | Boolean | true | Include authenticated user info in exceptions. | +| current_user_method | Symbol | :current_user | Controller method used to fetch the current user. | +| user_id_method | Symbol | nil | Method used to extract the distinct ID from the user object. Auto-detects when nil. | + +## Troubleshooting + +### Exceptions not being captured + +1. Verify PostHog is initialized: + + Ruby + + PostHog AI + + ```ruby + Rails.console + > PostHog.initialized? + => true + ``` + +2. Check your excluded exceptions list. + +3. Verify middleware is installed: + + Ruby + + PostHog AI + + ```ruby + Rails.application.middleware + ``` + +### User context not working + +1. Verify `current_user_method` matches your controller method. +2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, `id`, `pk`, or `uuid`. +3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method`. + +### Feature flags not working + +Ensure you've set `personal_api_key` in your configuration. + +## Next steps + +For any technical questions for how to integrate specific PostHog features into Rails (such as analytics, feature flags, A/B testing, etc.), have a look at our [Ruby SDK docs](/docs/libraries/ruby.md). + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-integration/SKILL.md b/skills/instrument-integration/SKILL.md index 66b3a62..0cf1192 100644 --- a/skills/instrument-integration/SKILL.md +++ b/skills/instrument-integration/SKILL.md @@ -12,7 +12,7 @@ metadata: Use this skill to add the PostHog SDK to an application. Use it when setting up PostHog for the first time, or reviewing PRs that need PostHog initialization. Covers SDK installation, provider setup, and basic configuration. Supports any framework or language. -Supported frameworks: Next.js, React, React Router, Vue, Nuxt, TanStack Start, SvelteKit, Astro, Angular, Django, Flask, FastAPI, Laravel, Ruby on Rails, Android, Swift, React Native, Expo, Node.js, and vanilla JavaScript. +Supported frameworks: Next.js, React, React Router, Vue, Nuxt, TanStack Start, SvelteKit, Astro, Angular, Django, Flask, FastAPI, Laravel, PHP, Ruby on Rails, Android, Swift, React Native, Expo, Node.js, and vanilla JavaScript. ## Instructions @@ -79,6 +79,7 @@ STEP 7: Verify and clean up. - `references/EXAMPLE-fastapi.md` - fastapi example project code - `references/EXAMPLE-python.md` - python example project code - `references/EXAMPLE-laravel.md` - laravel example project code +- `references/EXAMPLE-php.md` - php example project code - `references/EXAMPLE-ruby-on-rails.md` - ruby-on-rails example project code - `references/EXAMPLE-ruby.md` - ruby example project code - `references/EXAMPLE-android.md` - android example project code @@ -107,6 +108,7 @@ STEP 7: Verify and clean up. - `references/python.md` - Python - docs - `references/posthog-python.md` - PostHog python SDK - `references/laravel.md` - Laravel - docs +- `references/php.md` - Php - docs - `references/ruby-on-rails.md` - Ruby on rails - docs - `references/ruby.md` - Ruby - docs - `references/android.md` - Android - docs diff --git a/skills/instrument-integration/references/EXAMPLE-php.md b/skills/instrument-integration/references/EXAMPLE-php.md new file mode 100644 index 0000000..d530bd4 --- /dev/null +++ b/skills/instrument-integration/references/EXAMPLE-php.md @@ -0,0 +1,527 @@ +# PostHog php Example Project + +Repository: https://github.com/PostHog/context-mill +Path: basics/php + +--- + +## README.md + +# PostHog PHP Example - CLI Todo App + +A simple command-line todo application built with plain PHP (no framework) demonstrating PostHog integration for CLIs, scripts, data pipelines, and non-web PHP applications. + +## Purpose + +This example serves as: +- **Verification** that the context-mill wizard works for plain PHP projects +- **Reference implementation** of PostHog best practices for non-framework PHP code +- **Working example** you can run and modify + +## Features Demonstrated + +- **SDK initialization** - Uses `PostHog::init(...)` once with environment-based configuration +- **Event tracking** - Captures user actions with `distinctId` and properties +- **User identification** - Associates properties with users via `PostHog::identify(...)` +- **Error tracking** - Enables automatic PHP error tracking and manually captures handled exceptions +- **Proper flushing** - Calls `PostHog::flush()` before CLI exit + +## Quick Start + +### 1. Install Dependencies + +```bash +composer install +``` + +### 2. Configure PostHog + +```bash +# Copy environment template +cp .env.example .env + +# Edit .env and add your PostHog API key +# POSTHOG_API_KEY=phc_your_api_key_here +# POSTHOG_HOST=https://us.i.posthog.com +``` + +### 3. Run the App + +```bash +# Add a todo +php todo.php add "Buy groceries" + +# List all todos +php todo.php list + +# Complete a todo +php todo.php complete 1 + +# Delete a todo +php todo.php delete 1 + +# Show statistics +php todo.php stats +``` + +## What Gets Tracked + +The app tracks these events in PostHog: + +| Event | Properties | Purpose | +|-------|-----------|---------| +| `todo_added` | `todo_id`, `todo_length`, `total_todos` | When user adds a new todo | +| `todos_viewed` | `total_todos`, `completed_todos` | When user lists todos | +| `todo_completed` | `todo_id`, `time_to_complete_hours` | When user completes a todo | +| `todo_deleted` | `todo_id`, `was_completed` | When user deletes a todo | +| `stats_viewed` | `total_todos`, `completed_todos`, `pending_todos` | When user views stats | +| `$exception` | exception details and command context | When handled errors occur | + +## Code Structure + +``` +basics/php/ +├── todo.php # Main CLI application +├── composer.json # PHP dependencies +├── .env.example # Environment variable template +├── .gitignore # Git ignore rules +└── README.md # This file +``` + +## Key Implementation Patterns + +### 1. Initialize Once + +```php +PostHog::init($apiKey, [ + 'host' => $host, + 'error_tracking' => [ + 'enabled' => true, + ], +]); +``` + +### 2. Event Tracking Pattern + +```php +PostHog::capture([ + 'distinctId' => 'user_123', + 'event' => 'event_name', + 'properties' => ['key' => 'value'], +]); +``` + +### 3. Identifying Users + +```php +PostHog::identify([ + 'distinctId' => 'user_123', + 'properties' => ['app_language' => 'php'], +]); +``` + +### 4. Exception Tracking + +```php +try { + riskyOperation(); +} catch (Throwable $e) { + PostHog::captureException($e, 'user_123', [ + 'command' => 'example_command', + ]); +} +``` + +### 5. Flush Before CLI Exit + +```php +PostHog::flush(); +``` + +## Running Without PostHog + +The app works fine without PostHog configured - it simply won't track analytics. You'll see a warning message but the app continues to function normally. + +## Next Steps + +- Modify `todo.php` to experiment with PostHog tracking +- Add new commands and track their usage +- Explore feature flags: `PostHog::isFeatureEnabled('flag-name', 'user_id')` +- Check your PostHog dashboard to see tracked events + +## Learn More + +- [PostHog PHP SDK Documentation](https://posthog.com/docs/libraries/php) +- [PostHog PHP Error Tracking](https://posthog.com/docs/error-tracking/installation/php) +- [PostHog Product Analytics PHP installation](https://posthog.com/docs/product-analytics/installation/php) + +--- + +## .env.example + +```example +# PostHog configuration +POSTHOG_API_KEY=phc_your_api_key_here +POSTHOG_HOST=https://us.i.posthog.com + +``` + +--- + +## todo.php + +```php + getenv('POSTHOG_HOST') ?: 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + 'context_provider' => static function (array $payload): array { + return [ + 'distinctId' => getUserId(), + 'properties' => [ + 'app' => 'php_todo_cli', + 'runtime' => PHP_VERSION, + '$exception_source' => $payload['source'] ?? null, + ], + ]; + }, + ], + ]); + + return true; +} + +function getUserId(): string +{ + $path = dataFilePath(); + if (file_exists($path)) { + $data = json_decode((string) file_get_contents($path), true); + if (is_array($data) && isset($data['user_id'])) { + return (string) $data['user_id']; + } + } + + return 'user_' . bin2hex(random_bytes(4)); +} + +function loadTodos(): array +{ + $path = dataFilePath(); + if (!file_exists($path)) { + return ['user_id' => getUserId(), 'todos' => []]; + } + + $data = json_decode((string) file_get_contents($path), true); + if (!is_array($data)) { + return ['user_id' => getUserId(), 'todos' => []]; + } + + $data['todos'] = $data['todos'] ?? []; + $data['user_id'] = $data['user_id'] ?? getUserId(); + return $data; +} + +function saveTodos(array $data): void +{ + file_put_contents(dataFilePath(), json_encode($data, JSON_PRETTY_PRINT) . PHP_EOL); +} + +function identifyUser(bool $posthogEnabled): void +{ + if (!$posthogEnabled) { + return; + } + + PostHog::identify([ + 'distinctId' => getUserId(), + 'properties' => [ + 'app_language' => 'php', + 'app_type' => 'cli', + ], + ]); +} + +function trackEvent(bool $posthogEnabled, string $eventName, array $properties = []): void +{ + if (!$posthogEnabled) { + return; + } + + PostHog::capture([ + 'distinctId' => getUserId(), + 'event' => $eventName, + 'properties' => $properties, + ]); +} + +function cmdAdd(string $text, bool $posthogEnabled): void +{ + $data = loadTodos(); + + $todo = [ + 'id' => count($data['todos']) + 1, + 'text' => $text, + 'completed' => false, + 'created_at' => date(DATE_ATOM), + ]; + + $data['todos'][] = $todo; + saveTodos($data); + + echo "Added todo #{$todo['id']}: {$todo['text']}\n"; + + trackEvent($posthogEnabled, 'todo_added', [ + 'todo_id' => $todo['id'], + 'todo_length' => strlen($todo['text']), + 'total_todos' => count($data['todos']), + ]); +} + +function cmdList(bool $posthogEnabled): void +{ + $data = loadTodos(); + + if (count($data['todos']) === 0) { + echo "No todos yet! Add one with: php todo.php add 'Your task'\n"; + return; + } + + echo "\nYour Todos (" . count($data['todos']) . " total):\n\n"; + + foreach ($data['todos'] as $todo) { + $status = $todo['completed'] ? 'X' : ' '; + echo " [{$status}] #{$todo['id']}: {$todo['text']}\n"; + } + + echo "\n"; + + trackEvent($posthogEnabled, 'todos_viewed', [ + 'total_todos' => count($data['todos']), + 'completed_todos' => count(array_filter($data['todos'], static fn (array $todo): bool => (bool) $todo['completed'])), + ]); +} + +function cmdComplete(int $id, bool $posthogEnabled): void +{ + $data = loadTodos(); + + foreach ($data['todos'] as &$todo) { + if ((int) $todo['id'] !== $id) { + continue; + } + + if ($todo['completed']) { + echo "Todo #{$id} is already completed\n"; + return; + } + + $todo['completed'] = true; + $todo['completed_at'] = date(DATE_ATOM); + saveTodos($data); + + echo "Completed todo #{$todo['id']}: {$todo['text']}\n"; + + $timeToComplete = (strtotime($todo['completed_at']) - strtotime($todo['created_at'])) / 3600; + trackEvent($posthogEnabled, 'todo_completed', [ + 'todo_id' => $todo['id'], + 'time_to_complete_hours' => $timeToComplete, + ]); + return; + } + + echo "ERROR: Todo #{$id} not found\n"; +} + +function cmdDelete(int $id, bool $posthogEnabled): void +{ + $data = loadTodos(); + + foreach ($data['todos'] as $index => $todo) { + if ((int) $todo['id'] !== $id) { + continue; + } + + unset($data['todos'][$index]); + $data['todos'] = array_values($data['todos']); + saveTodos($data); + + echo "Deleted todo #{$id}\n"; + + trackEvent($posthogEnabled, 'todo_deleted', [ + 'todo_id' => $todo['id'], + 'was_completed' => $todo['completed'], + ]); + return; + } + + echo "ERROR: Todo #{$id} not found\n"; +} + +function cmdStats(bool $posthogEnabled): void +{ + $data = loadTodos(); + + $total = count($data['todos']); + $completed = count(array_filter($data['todos'], static fn (array $todo): bool => (bool) $todo['completed'])); + $pending = $total - $completed; + $rate = $total > 0 ? number_format($completed / $total * 100, 1) : '0.0'; + + echo "\nStats:\n\n"; + echo " Total todos: {$total}\n"; + echo " Completed: {$completed}\n"; + echo " Pending: {$pending}\n"; + echo " Completion rate: {$rate}%\n\n"; + + trackEvent($posthogEnabled, 'stats_viewed', [ + 'total_todos' => $total, + 'completed_todos' => $completed, + 'pending_todos' => $pending, + ]); +} + +function printUsage(): void +{ + echo << Mark todo as completed + php todo.php delete Delete a todo + php todo.php stats Show statistics +USAGE; +} + +$posthogEnabled = false; + +try { + $posthogEnabled = initializePostHog(); + identifyUser($posthogEnabled); + + $command = $argv[1] ?? null; + if (!$command) { + printUsage(); + exit(0); + } + + switch ($command) { + case 'add': + $text = $argv[2] ?? null; + if (!$text) { + echo "ERROR: Please provide todo text\n"; + echo "Usage: php todo.php add \"Your task\"\n"; + exit(1); + } + cmdAdd($text, $posthogEnabled); + break; + + case 'list': + cmdList($posthogEnabled); + break; + + case 'complete': + $id = (int) ($argv[2] ?? 0); + if ($id <= 0) { + echo "ERROR: Please provide a valid todo ID\n"; + echo "Usage: php todo.php complete \n"; + exit(1); + } + cmdComplete($id, $posthogEnabled); + break; + + case 'delete': + $id = (int) ($argv[2] ?? 0); + if ($id <= 0) { + echo "ERROR: Please provide a valid todo ID\n"; + echo "Usage: php todo.php delete \n"; + exit(1); + } + cmdDelete($id, $posthogEnabled); + break; + + case 'stats': + cmdStats($posthogEnabled); + break; + + default: + echo "ERROR: Unknown command '{$command}'\n"; + printUsage(); + exit(1); + } +} catch (Throwable $e) { + echo "ERROR: {$e->getMessage()}\n"; + + if ($posthogEnabled) { + PostHog::captureException($e, getUserId(), [ + 'command' => $argv[1] ?? null, + 'app' => 'php_todo_cli', + ]); + } + + exit(1); +} finally { + if ($posthogEnabled) { + PostHog::flush(); + } +} + +``` + +--- + diff --git a/skills/instrument-integration/references/django.md b/skills/instrument-integration/references/django.md index dc8a1af..af5d8ba 100644 --- a/skills/instrument-integration/references/django.md +++ b/skills/instrument-integration/references/django.md @@ -1,6 +1,6 @@ # Django - Docs -PostHog makes it easy to get data about traffic and usage of your Django app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. +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. This guide walks you through integrating PostHog into your Django app using the [Python SDK](/docs/libraries/python.md). @@ -18,7 +18,9 @@ Or, to integrate manually, continue with the rest of this guide. To start, run `pip install posthog` to install PostHog’s Python SDK. -Then, set the PostHog API key and host in your `AppConfig` in your `your_app/apps.py` so that's it's available everywhere: +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, configure PostHog in your app config so it's initialized when Django starts: your\_app/apps.py @@ -28,15 +30,13 @@ PostHog AI from django.apps import AppConfig import posthog class YourAppConfig(AppConfig): - name = "your_app_name" + name = 'your_app_name' def ready(self): posthog.api_key = '' posthog.host = 'https://us.i.posthog.com' ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). - -Next, if you haven't done so already, make sure you add your `AppConfig` to your `settings.py` under `INSTALLED_APPS`: +Next, if you haven't done so already, add your `AppConfig` to `INSTALLED_APPS` in `settings.py`: settings.py @@ -44,12 +44,14 @@ PostHog AI ```python INSTALLED_APPS = [ - # other apps - 'your_app_name.apps.MyAppConfig', # Add your app config + # ... other apps + 'your_app_name.apps.YourAppConfig', ] ``` -Lastly, to access PostHog in any file, simply `import posthog` and call the method you'd like. For example, to capture an event: +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +To capture events from any file, import `posthog` and call the method you need. For example: Python @@ -57,12 +59,18 @@ PostHog AI ```python import posthog +from posthog import identify_context def some_request(request): with posthog.new_context(): - posthog.identify_context(request.user.id) + # Django includes request.user for anonymous visitors too. Only identify + # the context when the visitor is logged in. + if request.user.is_authenticated: + identify_context(str(request.user.pk)) posthog.capture('event_name') ``` +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. + ## Identifying users > **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). @@ -71,11 +79,11 @@ def some_request(request): ## Django contexts middleware -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 request headers and tags all events captured during the request with relevant metadata. +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 tags all events captured during that request with relevant metadata. ### Basic setup -Add the middleware to your Django settings: +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. Python @@ -89,14 +97,22 @@ MIDDLEWARE = [ ] ``` +The middleware uses the globally configured `posthog` client by default, so you don't need to create or pass it a separate client instance. + The middleware automatically extracts and uses: - **Session ID** from the `X-POSTHOG-SESSION-ID` header, if present -- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present +- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present, falling back to the authenticated Django user's `pk` (Django's primary-key alias, which works with custom user models) +- **User email** from the authenticated Django user's `email` as `email` - **Current URL** as `$current_url` - **Request method** as `$request_method` +- **Request path** as `$request_path` +- **Forwarded IP address** from `X-Forwarded-For` as `$ip` +- **User agent** from `User-Agent` as `$user_agent` + +The session and distinct ID headers are sanitized before use. Empty values are ignored, control characters are removed, values are trimmed, and values are capped at 1000 characters. -All events captured during the request (including exceptions) will include these properties and be associated with the extracted session and distinct ID. +All events captured during the request (including exceptions) include these properties and are associated with the extracted session and distinct ID. If you are using PostHog on your frontend, the JavaScript Web SDK will add the session and distinct ID headers automatically if you enable tracing headers. @@ -112,7 +128,9 @@ posthog.init('', { ### Exception capture -By default, the middleware captures exceptions and sends them to PostHog's error tracking. Disable this by setting: +By default, the middleware captures exceptions and sends them to PostHog's error tracking using the globally configured `posthog` client. This includes Django view exceptions that Django converts into error responses. + +Disable this by setting: Python @@ -137,7 +155,8 @@ def add_user_tags(request): # type: (HttpRequest) -> Dict[str, Any] tags = {} if hasattr(request, 'user') and request.user.is_authenticated: - tags['user_id'] = request.user.id + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) tags['email'] = request.user.email return tags POSTHOG_MW_EXTRA_TAGS = add_user_tags @@ -196,7 +215,8 @@ def add_request_context(request): tags = {} if hasattr(request, 'user') and request.user.is_authenticated: tags['user_type'] = 'authenticated' - tags['user_id'] = str(request.user.id) + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) else: tags['user_type'] = 'anonymous' # Add request info @@ -217,7 +237,9 @@ POSTHOG_MW_TAG_MAP = clean_tags POSTHOG_MW_CAPTURE_EXCEPTIONS = True ``` -All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers. +All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers or Django authentication. + +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. ## Next steps diff --git a/skills/instrument-integration/references/flask.md b/skills/instrument-integration/references/flask.md index f631b4b..e8ec7bf 100644 --- a/skills/instrument-integration/references/flask.md +++ b/skills/instrument-integration/references/flask.md @@ -1,6 +1,6 @@ # Flask - Docs -PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. +PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, error tracking, and more. This guide walks you through integrating PostHog into your Flask app using the [Python SDK](/docs/libraries/python.md). @@ -8,6 +8,8 @@ This guide walks you through integrating PostHog into your Flask app using the [ To start, run `pip install posthog` to install PostHog’s Python SDK. +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + Then, initialize PostHog where you'd like to use it. For example, here's how to capture an event in a simple route: app.py @@ -15,23 +17,23 @@ app.py PostHog AI ```python -package main -from flask import Flask, render_template, request, redirect, session, url_for +from flask import Flask from posthog import Posthog +app = Flask(__name__) posthog = Posthog( - '', - host='https://us.i.posthog.com' + '', + host='https://us.i.posthog.com', ) @app.route('/api/dashboard', methods=['POST']) def api_dashboard(): posthog.capture( - 'dashboard_api_called' + 'dashboard_api_called', distinct_id='distinct_id_of_your_user', ) return '', 204 ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). ## Identifying users @@ -39,6 +41,35 @@ You can find your project token and instance address in [your project settings]( > > See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. +## Request contexts + +Use [contexts](/docs/libraries/python.md#contexts) to share identity, session IDs, and tags across multiple captures during a request: + +Python + +PostHog AI + +```python +from flask import request, session +from posthog import identify_context, set_context_session, tag +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + with posthog.new_context(): + distinct_id = request.headers.get('X-POSTHOG-DISTINCT-ID') or session.get('user_id') + if distinct_id: + identify_context(str(distinct_id)) + session_id = request.headers.get('X-POSTHOG-SESSION-ID') + if session_id: + set_context_session(session_id) + tag('$current_url', request.url) + tag('$request_method', request.method) + tag('$request_path', request.path) + posthog.capture('dashboard_api_called') + return '', 204 +``` + +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. + ## Error tracking Flask has built-in error handlers. This means PostHog’s default exception autocapture won’t work and we need to manually capture errors instead using `capture_exception()`: @@ -50,6 +81,7 @@ PostHog AI ```python from flask import Flask, jsonify from posthog import Posthog +app = Flask(__name__) posthog = Posthog('', host='https://us.i.posthog.com') @app.errorhandler(Exception) def handle_exception(e): diff --git a/skills/instrument-integration/references/js.md b/skills/instrument-integration/references/js.md index 50a7ad3..c674787 100644 --- a/skills/instrument-integration/references/js.md +++ b/skills/instrument-integration/references/js.md @@ -196,7 +196,6 @@ posthog.init('', { | ErrorTrackingExtensions | [Error Tracking](/docs/error-tracking.md) | | SurveysExtensions | [Surveys](/docs/surveys.md) | | ExperimentsExtensions | [Experiments](/docs/experiments.md) | -| ProductToursExtensions | [Product Tours](/docs/product-tours.md) | | SiteAppsExtensions | [Site apps](/docs/site-apps.md) | | TracingExtensions | Distributed tracing header injection | | ToolbarExtensions | [Toolbar](/docs/toolbar.md) | diff --git a/skills/instrument-integration/references/laravel.md b/skills/instrument-integration/references/laravel.md index 5038330..022f900 100644 --- a/skills/instrument-integration/references/laravel.md +++ b/skills/instrument-integration/references/laravel.md @@ -1,14 +1,34 @@ # Laravel - Docs -PostHog makes it easy to get data about traffic and usage of your Laravel app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. - -This guide walks you through integrating PostHog into your Laravel app using the [PHP SDK](/docs/libraries/php.md). +PostHog integrates with Laravel through the [PostHog PHP SDK](/docs/libraries/php.md). This page covers Laravel-specific setup. For SDK features such as event capture, identifying users, feature flags, group analytics, and configuration options, see the [PHP SDK docs](/docs/libraries/php.md). ## Installation -First, ensure [Composer](https://getcomposer.org/) is installed. Then run `composer require posthog/posthog-php` to install PostHog’s PHP SDK. +Install the PHP SDK as described in the [PHP installation guide](/docs/libraries/php.md#installation), then add your project token and host to `.env`: + +.env + +PostHog AI + +```bash +POSTHOG_API_KEY= +POSTHOG_HOST=https://us.i.posthog.com +``` + +Add PostHog to Laravel's services config: -Next, initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: +config/services.php + +PostHog AI + +```php +'posthog' => [ + 'api_key' => env('POSTHOG_API_KEY'), + 'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'), +], +``` + +Initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: app/Providers/AppServiceProvider.php @@ -23,48 +43,103 @@ class AppServiceProvider extends ServiceProvider { public function boot(): void { + if (! config('services.posthog.api_key')) { + return; + } PostHog::init( - '', + config('services.posthog.api_key'), [ - 'host' => 'https://us.i.posthog.com' + 'host' => config('services.posthog.host'), ] ); } } ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). +## Request context middleware -## Usage +Client SDKs such as [PostHog JS](/docs/libraries/js.md) can send tracing headers to your Laravel backend. The PHP SDK can read `X-PostHog-Distinct-Id` and `X-PostHog-Session-Id` headers and apply them to events captured during the request. Add middleware like this: -To access your PostHog client anywhere in your app, import `use PostHog\PostHog;` and call `PostHog::method_name`. For example, below is how to capture an event in a simple route: - -routes/web.php +app/Http/Middleware/PostHogRequestContext.php PostHog AI ```php 'distinct_id_of_your_user', - 'event' => 'route_called' - ]); - return view('welcome'); -}); +use Symfony\Component\HttpFoundation\Response; +final class PostHogRequestContext +{ + public function handle(Request $request, Closure $next): Response + { + if (! config('services.posthog.api_key')) { + return $next($request); + } + $context = PostHog::contextFromHeaders($request->headers->all()); + $context['properties'] = array_merge( + $context['properties'] ?? [], + array_filter([ + '$current_url' => $request->fullUrl(), + '$request_method' => $request->method(), + '$request_path' => $request->getPathInfo(), + '$user_agent' => $request->userAgent(), + '$ip' => $request->ip(), + ], static fn ($value): bool => $value !== null && $value !== '') + ); + return PostHog::withContext( + $context, + static fn (): Response => $next($request), + ['fresh' => true] + ); + } +} ``` -## Next steps +Register this middleware using your Laravel version's normal middleware registration. + +## Error tracking in Laravel + +The PHP SDK supports [error tracking](/docs/libraries/php.md#error-tracking), but Laravel handles most request exceptions before they become uncaught PHP exceptions. Capture Laravel-reported exceptions explicitly. + +In Laravel 11 and later, add a report callback in `bootstrap/app.php`: + +bootstrap/app.php + +PostHog AI + +```php +use Illuminate\Foundation\Configuration\Exceptions; +use PostHog\PostHog; +use Throwable; +->withExceptions(function (Exceptions $exceptions): void { + $exceptions->report(function (Throwable $e): void { + if (! config('services.posthog.api_key')) { + return; + } + PostHog::captureException( + $e, + auth()->id() !== null ? (string) auth()->id() : null, + [ + '$current_url' => request()->fullUrl(), + '$request_method' => request()->method(), + ] + ); + }); +}) +``` + +For older Laravel versions, call `PostHog::captureException()` from your exception handler's `report` method. -For any technical questions for how to integrate specific PostHog features into Laravel (such as analytics, feature flags, A/B testing, etc.), have a look at our [PHP SDK docs](/docs/libraries/php.md). +## Long-running processes -Alternatively, the following tutorials can help you get started: +In normal PHP request lifecycles, queued events flush when the client is destroyed. In long-running Laravel processes such as queue workers, Horizon, or Octane, call `PostHog::flush()` after capturing important events or at the end of a job/request. + +## Next steps -- [How to set up analytics in Laravel](/tutorials/laravel-analytics.md) -- [How to set up feature flags in Laravel](/tutorials/laravel-feature-flags.md) -- [How to set up A/B tests in Laravel](/tutorials/laravel-ab-tests.md) +See the [PHP SDK docs](/docs/libraries/php.md) for usage examples and the full API reference. ### Community questions diff --git a/skills/instrument-integration/references/node.md b/skills/instrument-integration/references/node.md index b673d7c..676fa79 100644 --- a/skills/instrument-integration/references/node.md +++ b/skills/instrument-integration/references/node.md @@ -812,9 +812,9 @@ export const handler() { This is also useful for shutting down a standard Node.js app. -## LLM analytics +## AI Observability -You can capture LLM usage and performance data by combining the `posthog-node` and `@posthog/ai` libraries. These work with LLM providers like OpenAI and Vercel's AI SDKs. Learn more in our [LLM analytics docs](/docs/llm-analytics.md). +You can capture LLM usage and performance data by combining the `posthog-node` and `@posthog/ai` libraries. These work with LLM providers like OpenAI and Vercel's AI SDKs. Learn more in our [AI Observability docs](/docs/ai-observability.md). ## Error tracking diff --git a/skills/instrument-integration/references/php.md b/skills/instrument-integration/references/php.md new file mode 100644 index 0000000..1c2e1fe --- /dev/null +++ b/skills/instrument-integration/references/php.md @@ -0,0 +1,629 @@ +# PHP - Docs + +This is an optional library you can install if you're working with PHP. It uses an internal queue to batch requests, flushes at the end of the request, and optionally does so in an async manner. + +## Installation + +Install the package with Composer: + +Terminal + +PostHog AI + +```bash +composer require posthog/posthog-php +``` + +In your app, set your project token before making any calls. + +PHP + +PostHog AI + +```php +PostHog\PostHog::init("", + ['host' => 'https://us.i.posthog.com'] +); +``` + +> **Note:** As a rule of thumb, we do not recommend having API keys or tokens in plaintext. Setting them as environment variables is best. The PHP SDK reads `POSTHOG_API_KEY` and `POSTHOG_HOST` when you omit the project token or host. + +You can find your project token and instance address in the [project settings](https://app.posthog.com/project/settings) page in PostHog. + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Capturing events + +You can send custom events using `capture`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => 'user_signed_up' +]); +``` + +> **Tip:** We recommend using a `[object] [verb]` format for your event names, where `[object]` is the entity that the behavior relates to, and `[verb]` is the behavior itself. For example, `project created`, `user signed up`, or `invite sent`. + +### Setting event properties + +Optionally, you can include additional information with the event by including a [properties](/docs/data/events.md#event-properties) object: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => 'user_signed_up', + 'properties' => [ + 'login_type' => 'email', + 'is_free_trial' => 'true' + ] +]); +``` + +### Sending page views + +If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send `pageviews` from your backend like so: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => '$pageview', + 'properties' => [ + '$current_url' => 'https://example.com' + ] +]); +``` + +## Person profiles and properties + +The PHP SDK captures identified events by default. These create [person profiles](/docs/data/persons.md). To set [person properties](/docs/data/user-properties.md), call `identify` with the user's distinct ID and properties: + +PHP + +PostHog AI + +```php +PostHog::identify([ + 'distinctId' => 'distinct_id', + 'properties' => [ + 'email' => 'max@example.com', + 'name' => 'Max Hedgehog', + ], +]); +``` + +You can also include person properties when capturing an event: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id', + 'event' => 'event_name', + 'properties' => [ + '$set' => [ + 'name' => 'Max Hedgehog' + ], + '$set_once' => [ + 'initial_url' => '/blog' + ] + ] +]); +``` + +For more details on the difference between `$set` and `$set_once`, see our [person properties docs](/docs/data/user-properties.md#what-is-the-difference-between-set-and-set_once). + +To capture [anonymous events](/docs/data/anonymous-vs-identified-events.md) without person profiles, set the event's `$process_person_profile` property to `false`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id', + 'event' => 'event_name', + 'properties' => [ + '$process_person_profile' => false + ] +]); +``` + +## Alias + +Sometimes, you want to assign multiple distinct IDs to a single user. This is helpful when your primary distinct ID is inaccessible. For example, if a distinct ID used on the frontend is not available in your backend. + +In this case, you can use `alias` to assign another distinct ID to the same user. + +PHP + +PostHog AI + +```php +PostHog::alias([ + 'distinctId' => 'distinct_id', + 'alias' => 'alias_id' +]); +``` + +We strongly recommend reading our docs on [alias](/docs/data/identify.md#alias-assigning-multiple-distinct-ids-to-the-same-user) to best understand how to correctly use this method. + +## Feature flags + +PostHog's [feature flags](/docs/feature-flags.md) enable you to safely deploy and roll back new features as well as target specific users and groups with them. + +There are two steps to implement feature flags in PHP: + +### Step 1: Evaluate flags once + +Call `PostHog::evaluateFlags()` once for the user, then read values from the returned snapshot. + +#### Boolean feature flags + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user + // Optional: fetch the payload + $matchedFlagPayload = $flags->getFlagPayload('flag-key'); +} +``` + +#### Multivariate feature flags + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +$enabledVariant = $flags->getFlag('flag-key'); +if ($enabledVariant === 'variant-key') { // replace 'variant-key' with the key of your variant + // Do something differently for this user + // Optional: fetch the payload + $matchedFlagPayload = $flags->getFlagPayload('flag-key'); +} +``` + +`$flags->getFlag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `null` when the flag wasn't returned by the evaluation. + +You can also call `$flags->getKeys()` to list the evaluated flag keys, or `$flags->getEventProperties()` to get the `$feature/` and `$active_feature_flags` properties that would be attached to a captured event. + +> **Note:** `PostHog::isFeatureEnabled()`, `PostHog::getFeatureFlag()`, `PostHog::getFeatureFlagPayload()`, and `capture(['send_feature_flags' => true])` still work during the migration period, but they're deprecated. Prefer `evaluateFlags()` for new code. + +### Step 2: Include feature flag information when capturing events + +If you want use your feature flag to breakdown or filter events in your [insights](/docs/product-analytics/insights.md), you'll need to include feature flag information in those events. This ensures that the feature flag value is attributed correctly to the event. + +> **Note:** This step is only required for events captured using our server-side SDKs or [API](/docs/api.md). + +There are two methods you can use to include feature flag information in your events: + +#### Method 1: Pass the evaluated flags snapshot to `capture()` + +Pass the same `flags` object that you used for branching. This attaches the exact flag values from that evaluation and doesn't make another `/flags` request. + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user +} +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags, +]); +``` + +By default, this attaches every flag in the snapshot using `$feature/` properties and `$active_feature_flags`. + +To reduce event property bloat, pass a filtered snapshot: + +PHP + +PostHog AI + +```php +// Attach only flags accessed with isEnabled() or getFlag() before this call +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags->onlyAccessed(), +]); +// Attach only specific flags +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags->only(['checkout-flow', 'new-dashboard']), +]); +``` + +`onlyAccessed()` is order-dependent. If you call it before accessing any flags with `isEnabled()` or `getFlag()`, no feature flag properties are attached. + +#### Method 2: Include the `$feature/feature_flag_name` property manually + +In the event properties, include `$feature/feature_flag_name: variant_key`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'properties' => [ + // Replace feature-flag-key with your flag key and 'variant-key' with the key of your variant + '$feature/feature-flag-key' => 'variant-key', + ], +]); +``` + +### Evaluating only specific flags + +By default, `evaluateFlags()` evaluates every flag for the user. If you only need a few flags, pass `flagKeys` to request only those flags: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_your_user', + flagKeys: ['checkout-flow', 'new-dashboard'], +); +``` + +### Optional evaluation parameters + +`evaluateFlags()` also accepts optional parameters for local evaluation and GeoIP behavior: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_your_user', + groups: ['company' => 'company_id_in_your_db'], + personProperties: ['plan' => 'pro'], + groupProperties: ['company' => ['employees' => 11]], + onlyEvaluateLocally: false, // Defaults to false. Set to true to avoid a remote fallback. + disableGeoip: false, // Defaults to false. Set to true to disable GeoIP enrichment during remote evaluation. + flagKeys: ['checkout-flow', 'new-dashboard'], +); +``` + +### Sending `$feature_flag_called` events + +Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluateFlags()`, the SDK sends this event when you call `$flags->isEnabled()` or `$flags->getFlag()` for a flag. + +The SDK deduplicates these events per `(flag key, distinct_id)` in a local cache. If you reinitialize the PostHog client, the cache resets and `$feature_flag_called` events may be sent again. PostHog handles duplicates, so duplicate `$feature_flag_called` events don't affect your analytics. + +`$flags->getFlagPayload()` doesn't send `$feature_flag_called` events and doesn't count as an access for `onlyAccessed()`. + +### Advanced: Overriding server properties + +Sometimes, you may want to evaluate feature flags using [person properties](/docs/product-analytics/person-properties.md), [groups](/docs/product-analytics/group-analytics.md), or group properties that haven't been ingested yet, or were set incorrectly earlier. + +You can provide properties to evaluate the flag with by using the `person properties`, `groups`, and `group properties` arguments. PostHog will then use these values to evaluate the flag, instead of any properties currently stored on your PostHog server. + +For example: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_the_user', + groups: [ + 'your_group_type' => 'your_group_id', + 'another_group_type' => 'your_group_id', + ], + personProperties: ['property_name' => 'value'], + groupProperties: [ + 'your_group_type' => ['group_property_name' => 'value'], + 'another_group_type' => ['group_property_name' => 'value'], + ], +); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user +} +``` + +### Overriding GeoIP properties + +By default, a user's GeoIP properties are set using the IP address they use to capture events on the frontend. You may want to override the these properties when evaluating feature flags. A common reason to do this is when you're not using PostHog on your frontend, so the user has no GeoIP properties. + +You can override GeoIP properties by including them in the `person_properties` parameter when evaluating feature flags. This is useful when you're evaluating flags on your backend and want to use the client's location instead of your server's location. + +The following GeoIP properties can be overridden: + +- `$geoip_country_code` +- `$geoip_country_name` +- `$geoip_city_name` +- `$geoip_city_confidence` +- `$geoip_continent_code` +- `$geoip_continent_name` +- `$geoip_latitude` +- `$geoip_longitude` +- `$geoip_postal_code` +- `$geoip_subdivision_1_code` +- `$geoip_subdivision_1_name` +- `$geoip_subdivision_2_code` +- `$geoip_subdivision_2_name` +- `$geoip_subdivision_3_code` +- `$geoip_subdivision_3_name` +- `$geoip_time_zone` + +Simply include any of these properties in the `person_properties` parameter alongside your other person properties when calling feature flags. + +### Request timeout + +You can configure the `feature_flag_request_timeout_ms` parameter when initializing your PostHog client to set a flag request timeout. This helps prevent your code from being blocked if PostHog's servers are too slow to respond. By default, this is set to 3 seconds. + +PHP + +PostHog AI + +```php +PostHog::init("", + [ + 'host' => 'https://us.i.posthog.com', + 'feature_flag_request_timeout_ms' => 3000, // Time in milliseconds. Defaults to 3000 (3 seconds). + ] +); +``` + +### Local Evaluation + +Evaluating feature flags requires making a request to PostHog for each flag. However, you can improve performance by evaluating flags locally. Instead of making a request for each flag, PostHog will periodically request and store feature flag definitions locally, enabling you to evaluate flags without making additional requests. + +It is best practice to use local evaluation flags when possible, since this enables you to resolve flags faster and with fewer API calls. + +To load feature flag definitions for local evaluation, initialize the SDK with your feature flags secure API key as `personalAPIKey`: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + ['host' => 'https://us.i.posthog.com'], + personalAPIKey: 'your feature flags secure API key' +); +``` + +For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). + +### Experiments (A/B tests) + +Since [experiments](/docs/experiments/start-here.md) use feature flags, the code for running an experiment is very similar to the feature flags code: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('user_distinct_id'); +$variant = $flags->getFlag('experiment-feature-flag-key'); +if ($variant === 'variant-name') { + // Do something differently for this user +} +``` + +It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags.md). + +### Group analytics + +Group analytics allows you to associate an event with a group (e.g. teams, organizations, etc.). This feature requires version `2.1.0` or above of the PHP SDK. Read the [group analytics guide](/docs/product-analytics/group-analytics.md) for more information. + +> **Note:** This is a paid feature and is not available on the open-source or free cloud plan. Learn more on the [pricing page](/pricing.md). + +To create a group or update its properties, use `groupIdentify`: + +PHP + +PostHog AI + +```php +PostHog::groupIdentify([ + 'groupType' => 'company', + 'groupKey' => 'company_id_in_your_db', + 'properties' => [ + 'name' => 'Awesome Inc.', + 'employees' => 11, + ], + // Optional distinct ID to associate this event with an existing person. + // Requires posthog-php 4.4.0 or later. + 'distinctId' => 'user_distinct_id' +]); +``` + +`name` is a special property which is used in the PostHog UI for the name of the group. If you don't specify a `name` property, the group ID is used instead. + +If the optional `distinctId` parameter is not provided in the group identify call, it defaults to `${groupType}_${groupKey}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior results in each group appearing as a separate person in PostHog. To avoid this, use a consistent `distinctId`, such as `group_identifier`, or a real user distinct ID. + +Once a group is created, you can use the `capture` method and pass in the `groups` parameter to capture an event with group analytics. + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'user_distinct_id', + 'event' => 'some_event', + 'groups' => ['company' => 'company_id_in_your_db'] +]); +``` + +## Request context + +Use request context to apply a distinct ID, session ID, and common properties to all captures inside a callback. This is useful when connecting frontend activity to backend events, session replay, and error tracking. + +PHP + +PostHog AI + +```php +PostHog::withContext([ + 'distinctId' => 'user_distinct_id', + 'sessionId' => 'session_id_from_frontend', + 'properties' => [ + '$current_url' => 'https://example.com/account', + ], +], function () { + PostHog::capture([ + 'event' => 'backend_event', + ]); +}); +``` + +You can extract PostHog context from frontend tracing headers with `contextFromHeaders()`: + +PHP + +PostHog AI + +```php +$context = PostHog::contextFromHeaders($_SERVER); +PostHog::withContext($context, function () { + PostHog::capture([ + 'event' => 'backend_event', + ]); +}); +``` + +Call `PostHog::getContext()` to read the currently active context. Pass `['fresh' => true]` as the third argument to `withContext()` if you don't want to inherit any existing context. + +## Error tracking + +The PHP SDK supports both manual exception capture and opt-in automatic error tracking. + +To automatically capture uncaught exceptions, PHP errors, and fatal shutdown errors, enable `error_tracking` when initializing the client: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + ], + ], +); +``` + +You can also call `PostHog::captureException()` directly for manual capture. When source files are readable at runtime, PostHog includes surrounding source lines for in-app stack frames automatically. + +For the full setup guide, including `context_provider`, excluded exceptions, and verification steps, see the [PHP error tracking installation docs](/docs/error-tracking/installation/php.md). + +## Config options + +When calling `PostHog::init`, there are various configuration options you can set apart from the host. Pass them into your client initialisation like so: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'debug' => true, + 'ssl' => false, + // all options go here + ], +); +``` + +All possible options below: + +| Attribute | Description | +| --- | --- | +| hostType: StringDefault: us.i.posthog.com | URL of your PostHog instance. | +| sslType: BooleanDefault: true | Whether to use SSL for API requests or not. If host includes http:// or https://, the SDK infers this option unless you set it explicitly. | +| timeoutType: IntegerDefault: 10000 | Request timeout in milliseconds. | +| verify_batch_events_requestType: BooleanDefault: true | Whether to verify successful delivery of batch events (true, synchronous) or fire and forget (false, asynchronous) with the lib_curl consumer. | +| feature_flag_request_timeout_msType: IntegerDefault: 3000 | Request timeout for feature flags in milliseconds. | +| maximum_backoff_durationType: IntegerDefault: 10000 | Request retry backoff. Retries stop after this duration is hit. | +| consumerType: StringDefault: lib_curl | One of socket, file, lib_curl, and fork_curl. Determines what transport option to use for analytics capture. | +| debugType: BooleanDefault: false | Output debug logs or not. | +| max_queue_sizeType: IntegerDefault: 1000 | Maximum number of events to queue before rejecting new events. Applies to queued consumers. | +| batch_sizeType: IntegerDefault: 100 | Number of queued events to send in each batch. Applies to queued consumers. | +| compress_requestType: Boolean/StringDefault: false | Whether to gzip batch request payloads. | +| error_handlerType: CallableDefault: null | Callback invoked for SDK transport errors. | +| filenameType: StringDefault: sys_get_temp_dir() . '/posthog.log' | File path used when consumer is set to file. | +| error_trackingType: ArrayDefault: [] | Enables automatic error tracking. See the options below or the [PHP error tracking setup guide](/docs/error-tracking/installation/php.md). | + +### Error tracking options + +| Attribute | Description | +| --- | --- | +| enabledType: BooleanDefault: false | Enables automatic error tracking handlers. Manual captureException works regardless. | +| capture_errorsType: BooleanDefault: true | When enabled, captures PHP errors and fatal shutdown errors in addition to uncaught exceptions. | +| excluded_exceptionsType: Array of class stringsDefault: [] | Throwable classes to skip during automatic capture. | +| max_framesType: IntegerDefault: 20 | Maximum number of stack frames included in $exception_list. | +| context_providerType: Callable or nullDefault: null | Callback that returns distinctId and extra event properties for automatic captures. | + +## Debug mode + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'debug' => true, + ], +); +``` + +## Thank you + +This library is largely based on the `analytics-php` package. + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-integration/references/posthog-js.md b/skills/instrument-integration/references/posthog-js.md index 716a8e2..e0942c1 100644 --- a/skills/instrument-integration/references/posthog-js.md +++ b/skills/instrument-integration/references/posthog-js.md @@ -1,6 +1,6 @@ # PostHog JavaScript Web SDK -**SDK Version:** 1.373.4 +**SDK Version:** 1.376.2 Posthog-js allows you to automatically capture usage and send events to PostHog. diff --git a/skills/instrument-integration/references/posthog-node.md b/skills/instrument-integration/references/posthog-node.md index bfe628d..eb9f922 100644 --- a/skills/instrument-integration/references/posthog-node.md +++ b/skills/instrument-integration/references/posthog-node.md @@ -1,6 +1,6 @@ # PostHog Node.js SDK -**SDK Version:** 5.34.1 +**SDK Version:** 5.35.4 PostHog Node.js SDK allows you to capture events and send them to PostHog from your Node.js applications. diff --git a/skills/instrument-integration/references/posthog-python.md b/skills/instrument-integration/references/posthog-python.md index 50c8ae7..8c27cd2 100644 --- a/skills/instrument-integration/references/posthog-python.md +++ b/skills/instrument-integration/references/posthog-python.md @@ -1,6 +1,6 @@ # PostHog Python SDK -**SDK Version:** 7.14.2 +**SDK Version:** 7.15.4 Integrate PostHog into any python application. @@ -29,38 +29,38 @@ Initialize a new PostHog client instance. ### Parameters -- **`project_api_key?`** (`str`) - The project API key. -- **`host`** (`any`) - The host to use for the client. -- **`debug`** (`bool`) - Whether to enable debug mode. -- **`max_queue_size`** (`int`) -- **`send`** (`bool`) -- **`on_error`** (`any`) -- **`flush_at`** (`int`) -- **`flush_interval`** (`float`) -- **`gzip`** (`bool`) -- **`max_retries`** (`int`) -- **`sync_mode`** (`bool`) -- **`timeout`** (`int`) -- **`thread`** (`int`) -- **`poll_interval`** (`int`) -- **`personal_api_key`** (`any`) -- **`disabled`** (`bool`) -- **`disable_geoip`** (`bool`) -- **`historical_migration`** (`bool`) -- **`feature_flags_request_timeout_seconds`** (`int`) -- **`super_properties`** (`any`) -- **`enable_exception_autocapture`** (`bool`) -- **`log_captured_exceptions`** (`bool`) -- **`project_root`** (`any`) -- **`privacy_mode`** (`bool`) -- **`before_send`** (`any`) -- **`flag_fallback_cache_url`** (`any`) -- **`enable_local_evaluation`** (`bool`) -- **`flag_definition_cache_provider?`** (`FlagDefinitionCacheProvider`) -- **`capture_exception_code_variables`** (`bool`) -- **`code_variables_mask_patterns`** (`any`) -- **`code_variables_ignore_patterns`** (`any`) -- **`in_app_modules`** (`UnionType[list[str], any]`) +- **`project_api_key?`** (`str`) - PostHog project API key/token. +- **`host`** (`any`) - PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as ``https://us.posthog.com`` are mapped to the corresponding ingestion host. +- **`debug`** (`bool`) - Enable verbose SDK logging and re-raise errors from public API methods. +- **`max_queue_size`** (`int`) - Maximum number of events buffered before upload. +- **`send`** (`bool`) - If False, queueing succeeds but events are not sent. +- **`on_error`** (`any`) - Optional callback invoked by background consumers when an upload fails. +- **`flush_at`** (`int`) - Number of queued events that triggers a batch upload. +- **`flush_interval`** (`float`) - Maximum seconds a background consumer waits before flushing a partial batch. +- **`gzip`** (`bool`) - Whether to gzip event upload payloads. +- **`max_retries`** (`int`) - Number of upload retries for background consumers. +- **`sync_mode`** (`bool`) - If True, send each event synchronously instead of using background worker threads. +- **`timeout`** (`int`) - HTTP request timeout in seconds for event uploads. +- **`thread`** (`int`) - Number of background consumer threads. +- **`poll_interval`** (`int`) - Seconds between local feature flag definition refreshes. +- **`personal_api_key`** (`any`) - Personal API key used for local feature flag evaluation and remote config payloads. +- **`disabled`** (`bool`) - If True, disable captures and API requests. Useful in tests. +- **`disable_geoip`** (`bool`) - Whether to disable server-side GeoIP enrichment. Defaults to True. +- **`historical_migration`** (`bool`) - Mark events as historical migration imports. +- **`feature_flags_request_timeout_seconds`** (`int`) - Timeout in seconds for feature flag and remote config requests. +- **`super_properties`** (`any`) - Properties merged into every captured event. +- **`enable_exception_autocapture`** (`bool`) - Automatically capture uncaught exceptions. +- **`log_captured_exceptions`** (`bool`) - Also log exceptions captured by error tracking. +- **`project_root`** (`any`) - Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. +- **`privacy_mode`** (`bool`) - For AI observability, capture usage metadata without prompt inputs or outputs. +- **`before_send`** (`any`) - Optional callback that can modify or drop events before upload. Return ``None`` to drop an event. +- **`flag_fallback_cache_url`** (`any`) - Optional feature flag fallback cache URL, such as ``memory://local/?ttl=300&size=10000`` or a Redis URL. +- **`enable_local_evaluation`** (`bool`) - Whether to poll feature flag definitions for local evaluation when a personal API key is configured. +- **`flag_definition_cache_provider?`** (`FlagDefinitionCacheProvider`) - Optional external cache provider for sharing feature flag definitions across workers. +- **`capture_exception_code_variables`** (`bool`) - Capture local variable values on exception stack frames. +- **`code_variables_mask_patterns`** (`any`) - Variable-name patterns to mask when capturing code variables. +- **`code_variables_ignore_patterns`** (`any`) - Variable-name patterns to omit when capturing code variables. +- **`in_app_modules`** (`UnionType[list[str], any]`) - Module/package prefixes treated as in-app frames in captured exceptions. ### Returns @@ -341,6 +341,18 @@ if is_my_flag_enabled: --- +#### feature_flag_definitions() + +**Release Tag:** public + +Return feature flag definitions loaded for local evaluation. Returns: The currently loaded feature flag definitions, or ``None`` before local evaluation has loaded definitions. + +### Returns + +- `None` + +--- + #### get_all_flags() **Release Tag:** public @@ -575,6 +587,22 @@ decision = posthog.get_flags_decision('user123') --- +#### get_remote_config_payload() + +**Release Tag:** public + +Get the payload for a remote config feature flag. + +### Parameters + +- **`key?`** (`str`) - The remote config feature flag key. + +### Returns + +- `None` + +--- + #### load_feature_flags() **Release Tag:** public @@ -827,15 +855,8 @@ This will overwrite previous people property values. Generally operates similar ```python # Set person properties -from posthog import capture -capture( - 'distinct_id', - event='event_name', - properties={ - '$set': {'name': 'Max Hedgehog'}, - '$set_once': {'initial_url': '/blog'} - } -) +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) ``` --- @@ -862,15 +883,8 @@ This will not overwrite previous people property values, unlike `set`. Otherwise ```python # Set property once -from posthog import capture -capture( - 'distinct_id', - event='event_name', - properties={ - '$set': {'name': 'Max Hedgehog'}, - '$set_once': {'initial_url': '/blog'} - } -) +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) ``` --- @@ -957,7 +971,7 @@ Capture exception is idempotent - if it is called twice with the same exception ### Parameters -- **`exception`** (`BaseException`) - The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` +- **`exception`** (`BaseException`) - The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` **kwargs: Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. - **`kwargs?`** (`Unpack[OptionalCaptureArgs]`) ### Returns @@ -1032,7 +1046,7 @@ You can call `posthog.load_feature_flags()` before to make sure you're not doing - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags ### Returns @@ -1091,7 +1105,7 @@ Flags are key-value pairs where the key is the flag key and the value is the fla - **`group_properties`** (`any`) - Group properties - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags - **`flag_keys_to_evaluate`** (`any`) - Optional list of flag keys to evaluate (evaluates all if None) ### Returns @@ -1108,6 +1122,29 @@ get_all_flags('distinct_id_of_your_user') --- +#### get_all_flags_and_payloads() + +**Release Tag:** public + +Get all feature flag values and payloads for a user. + +### Parameters + +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. +- **`flag_keys_to_evaluate`** (`any`) - Optional list of flag keys to evaluate. Evaluates all flags when omitted. + +### Returns + +- `FlagsAndPayloads` + +--- + #### get_feature_flag() **Release Tag:** public @@ -1128,7 +1165,7 @@ Get feature flag variant for users. Used with experiments. - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags ### Returns @@ -1146,6 +1183,31 @@ if enabled_variant == 'variant-key': --- +#### get_feature_flag_payload() + +**Release Tag:** public + +Get the payload associated with a feature flag value. Deprecated for new code. Prefer ``evaluate_flags()`` and ``flags.get_flag_payload(key)`` so flag evaluation happens once per request. + +### Parameters + +- **`key?`** (`any`) - The feature flag key. +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`match_value`** (`any`) - Optional flag value to use when selecting a payload. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`send_feature_flag_events`** (`bool`) - Whether to send a $feature_flag_called event. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. + +### Returns + +- `Optional[str]` + +--- + #### load_feature_flags() **Release Tag:** public @@ -1230,19 +1292,19 @@ shutdown() **Release Tag:** public -Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: - enabled: Whether the flag is enabled - variant: The variant value if the flag has variants - payload: The payload associated with the flag (automatically deserialized from JSON) - key: The flag key - reason: Why the flag was enabled/disabled Example: ```python result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') if result and result.enabled: # Use the variant and payload print(f"Variant: {result.variant}") print(f"Payload: {result.payload}") ``` +Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: - enabled: Whether the flag is enabled - variant: The variant value if the flag has variants - payload: The payload associated with the flag (automatically deserialized from JSON) - key: The flag key - reason: Why the flag was enabled/disabled ### Parameters -- **`key?`** (`any`) -- **`distinct_id?`** (`any`) -- **`groups`** (`any`) -- **`person_properties`** (`any`) -- **`group_properties`** (`any`) -- **`only_evaluate_locally`** (`bool`) -- **`send_feature_flag_events`** (`bool`) -- **`disable_geoip`** (`any`) -- **`device_id`** (`any`) +- **`key?`** (`any`) - The feature flag key. +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`send_feature_flag_events`** (`bool`) - Whether to send a $feature_flag_called event. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. ### Returns @@ -1266,120 +1328,120 @@ Get the payload for a remote config feature flag. --- -#### set_capture_exception_code_variables_context() - -**Release Tag:** public +### Contexts methods -Set whether code variables are captured for the current context. +#### get_tags() -### Parameters +**Release Tag:** public -- **`enabled?`** (`bool`) +Get all tags from the current context. Returns: Dict of all tags in the current context ### Returns -- `None` +- `dict[str, Any]` --- -#### set_code_variables_ignore_patterns_context() +#### new_context() **Release Tag:** public -Variable names matching these patterns will be ignored completely when capturing code variables. +Create a new context scope that will be active for the duration of the with block. ### Parameters -- **`ignore_patterns?`** (`list`) +- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) +- **`capture_exceptions`** (`bool`) - Whether to capture exceptions raised within the context (default: True) +- **`client?`** (`Client`) - Optional Posthog client instance to use for this context (default: None) ### Returns - `None` +### Examples + +```python +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) +``` + --- -#### set_code_variables_mask_patterns_context() +#### scoped() **Release Tag:** public -Variable names matching these patterns will be masked with *** when capturing code variables. +Decorator that creates a new context for the function. ### Parameters -- **`mask_patterns?`** (`list`) +- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) +- **`capture_exceptions`** (`bool`) - Whether to capture and track exceptions with posthog error tracking (default: True) ### Returns - `None` ---- +### Examples -### Contexts methods +```python +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") +``` -#### get_tags() +--- + +#### set_capture_exception_code_variables_context() **Release Tag:** public -Get all tags from the current context. Returns: Dict of all tags in the current context +Override code-variable capture for exceptions in the current context. + +### Parameters + +- **`enabled?`** (`bool`) - Whether exceptions captured in this context should include local variable values from stack frames. ### Returns -- `dict[str, Any]` +- `None` --- -#### new_context() +#### set_code_variables_ignore_patterns_context() **Release Tag:** public -Create a new context scope that will be active for the duration of the with block. +Override code-variable ignore patterns for exceptions in the current context. ### Parameters -- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) -- **`capture_exceptions`** (`bool`) - Whether to capture exceptions raised within the context (default: True) -- **`client?`** (`Client`) - Optional Posthog client instance to use for this context (default: None) +- **`ignore_patterns?`** (`list`) - Variable-name patterns that should be omitted entirely when code variables are captured. ### Returns - `None` -### Examples - -```python -from posthog import new_context, tag, capture -with new_context(): - tag("request_id", "123") - capture("event_name", properties={"property": "value"}) -``` - --- -#### scoped() +#### set_code_variables_mask_patterns_context() **Release Tag:** public -Decorator that creates a new context for the function. +Override code-variable mask patterns for exceptions in the current context. ### Parameters -- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) -- **`capture_exceptions`** (`bool`) - Whether to capture and track exceptions with posthog error tracking (default: True) +- **`mask_patterns?`** (`list`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. ### Returns - `None` -### Examples - -```python -from posthog import scoped, tag, capture -@scoped() -def process_payment(payment_id): - tag("payment_id", payment_id) - capture("payment_started") -``` - --- #### set_context_device_id() @@ -1450,4 +1512,18 @@ from posthog import tag tag("user_id", "123") ``` +--- + +### Initialization methods + +#### setup() + +**Release Tag:** public + +Create or return the global PostHog client configured by module settings. Most applications should either instantiate ``Posthog`` directly or set ``posthog.api_key``/other module settings before calling top-level helpers. ``setup()`` is called automatically by global APIs such as ``capture()``. Returns: The global ``Client`` instance. Raises: ValueError: If ``api_key`` has not been configured. + +### Returns + +- `Client` + --- \ No newline at end of file diff --git a/skills/instrument-integration/references/python.md b/skills/instrument-integration/references/python.md index 166ab38..154b1cd 100644 --- a/skills/instrument-integration/references/python.md +++ b/skills/instrument-integration/references/python.md @@ -224,7 +224,7 @@ Python PostHog AI ```python -from posthog import new_context +from posthog import new_context, tag with new_context(fresh=True): tag("some-key", "value-2") # This event only has the property some-key="value-2" from the fresh context @@ -266,7 +266,7 @@ You can read more about identifying users in the [user identification documentat ### Contexts and sessions -Contexts can be associated with a session ID by calling `posthog.set_context_session`. Session IDs must be UUIDv7 strings. +Contexts can be associated with a session ID by calling `posthog.set_context_session`. When linking backend events to frontend sessions, use the session ID from the frontend SDK (PostHog session IDs are UUIDv7 strings). Python @@ -324,7 +324,7 @@ with new_context(capture_exceptions=False): ### Decorating functions -The SDK exposes a function decorator. It takes the same arguments as `new_context` and provides a handy way to mark a whole function as being in a new context. For example: +The SDK exposes a function decorator. It takes the same `fresh` and `capture_exceptions` arguments as `new_context` and provides a handy way to mark a whole function as being in a new context. For example: Python @@ -609,9 +609,9 @@ if variant == "variant-name": It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags.md). -## LLM analytics +## AI Observability -Our Python SDK includes a built-in LLM analytics feature. It enables you to capture LLM usage, performance, and more. Check out our [analytics docs](/docs/llm-analytics.md) for more details on setting it up. +Our Python SDK includes a built-in AI Observability feature. It enables you to capture LLM usage, performance, and more. Check out our [analytics docs](/docs/ai-observability.md) for more details on setting it up. ## Error tracking @@ -633,7 +633,7 @@ Python PostHog AI ```python -posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) +posthog.capture_exception(e, distinct_id='user_distinct_id', properties=additional_properties) ``` Contexts automatically capture exceptions thrown inside them, unless disable it by passing `capture_exceptions=False` to `new_context()`. diff --git a/skills/instrument-integration/references/react-router-v6.md b/skills/instrument-integration/references/react-router-v6.md index b651e1e..291000d 100644 --- a/skills/instrument-integration/references/react-router-v6.md +++ b/skills/instrument-integration/references/react-router-v6.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V6. If you're u Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V6. If you're u import posthog from 'posthog-js'; import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // Initialize PostHog - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const root = document.getElementById("root"); @@ -341,8 +341,8 @@ This guide walks you through setting up PostHog for React Router V6. If you're u PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-integration/references/react-router-v7-data-mode.md b/skills/instrument-integration/references/react-router-v7-data-mode.md index 17d61a0..fa07c5b 100644 --- a/skills/instrument-integration/references/react-router-v7-data-mode.md +++ b/skills/instrument-integration/references/react-router-v7-data-mode.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V7 in data mode Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V7 in data mode import Root, { RootErrorBoundary } from "./app/root"; import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const router = createBrowserRouter([...]); @@ -329,8 +329,8 @@ This guide walks you through setting up PostHog for React Router V7 in data mode PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-integration/references/react-router-v7-declarative-mode.md b/skills/instrument-integration/references/react-router-v7-declarative-mode.md index f88d210..e13d45a 100644 --- a/skills/instrument-integration/references/react-router-v7-declarative-mode.md +++ b/skills/instrument-integration/references/react-router-v7-declarative-mode.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V7 in declarati Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V7 in declarati import posthog from 'posthog-js'; import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // Initialize PostHog - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const root = document.getElementById("root"); @@ -341,8 +341,8 @@ This guide walks you through setting up PostHog for React Router V7 in declarati PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-integration/references/react-router-v7-framework-mode.md b/skills/instrument-integration/references/react-router-v7-framework-mode.md index 2d92274..a2ee8ea 100644 --- a/skills/instrument-integration/references/react-router-v7-framework-mode.md +++ b/skills/instrument-integration/references/react-router-v7-framework-mode.md @@ -58,15 +58,15 @@ This guide walks you through setting up PostHog for React Router V7 in framework Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -87,8 +87,8 @@ This guide walks you through setting up PostHog for React Router V7 in framework import { HydratedRouter } from "react-router/dom"; import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); @@ -393,8 +393,8 @@ This guide walks you through setting up PostHog for React Router V7 in framework posthog?: PostHog; } export const posthogMiddleware: Route.MiddlewareFunction = async ({ request, context }, next) => { - const posthog = new PostHog(process.env.VITE_PUBLIC_POSTHOG_TOKEN!, { - host: process.env.VITE_PUBLIC_POSTHOG_HOST!, + const posthog = new PostHog(process.env.VITE_POSTHOG_TOKEN!, { + host: process.env.VITE_POSTHOG_HOST!, flushAt: 1, flushInterval: 0, }); diff --git a/skills/instrument-integration/references/react.md b/skills/instrument-integration/references/react.md index e2a5e4b..f680c9d 100644 --- a/skills/instrument-integration/references/react.md +++ b/skills/instrument-integration/references/react.md @@ -56,15 +56,15 @@ pnpm add posthog-js @posthog/react bun add posthog-js @posthog/react ``` -2. Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, include `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. +2. Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell -VITE_PUBLIC_POSTHOG_TOKEN= -VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com +VITE_POSTHOG_TOKEN= +VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. Integrate PostHog at the root of your app (such as `main.jsx` for Vite apps and `root.tsx` for React Router V7). @@ -81,8 +81,8 @@ import './index.css' import App from './App.jsx' import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' -posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, +posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); createRoot(document.getElementById('root')).render( diff --git a/skills/instrument-integration/references/ruby-on-rails.md b/skills/instrument-integration/references/ruby-on-rails.md index f4b7119..ad8cb5b 100644 --- a/skills/instrument-integration/references/ruby-on-rails.md +++ b/skills/instrument-integration/references/ruby-on-rails.md @@ -1,6 +1,6 @@ # Ruby on Rails - Docs -PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom events capture, feature flags, and automatic exception tracking. +PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom event capture, feature flags, and automatic exception tracking. This guide walks you through integrating PostHog into your Rails app using the [posthog-rails gem](https://github.com/PostHog/posthog-ruby/tree/main/posthog-rails). @@ -20,6 +20,7 @@ Or, to integrate manually, continue with the rest of this guide. - **ActiveJob instrumentation** – Tracks background job exceptions - **User context** – Automatically associates exceptions with the current user - **Smart filtering** – Excludes common Rails exceptions (404s, etc.) by default +- **Request context** – Adds request metadata and optional PostHog tracing header identity/session context to captured events - **Rails 7.0+ error reporter** – Integrates with Rails' built-in error reporting ## Installation @@ -67,35 +68,55 @@ This creates `config/initializers/posthog.rb` with sensible defaults and documen ## Configuration -The generated initializer includes all available options: +`PostHog.init` creates a single client instance used across your app. Avoid creating multiple `PostHog::Client` instances with the same API key, as this can cause dropped events and inconsistent behavior. + +The generated initializer includes the most common options: config/initializers/posthog.rb PostHog AI ```ruby +# Rails-specific configuration +PostHog::Rails.configure do |config| + config.auto_capture_exceptions = true # Enable automatic exception capture (default: false) + config.report_rescued_exceptions = true # Report exceptions Rails rescues (default: false) + config.auto_instrument_active_job = true # Instrument background jobs (default: false) + config.use_tracing_headers = true # Use PostHog tracing headers for identity/session context (default: true) + config.capture_user_context = true # Include authenticated user info in exceptions (default: true) + config.current_user_method = :current_user # Method to get current user (default: :current_user) + config.user_id_method = nil # Method to get ID from user object (default: auto-detect) + # Add additional exceptions to ignore + config.excluded_exceptions = ['MyCustomError'] +end # Core PostHog client initialization PostHog.init do |config| - # Required: Your PostHog API key + # Required: Your PostHog project API key config.api_key = '' # Optional: Your PostHog instance URL config.host = 'https://us.i.posthog.com' # Optional: Personal API key for feature flags config.personal_api_key = 'phx_xxxxxxxxx' + # Maximum number of events to queue before dropping (default: 10000) + config.max_queue_size = 10_000 + # Send events synchronously on the calling thread (default: false) + config.sync_mode = false + # Feature flags polling interval in seconds (default: 30) + config.feature_flags_polling_interval = 30 + # Feature flag request timeout in seconds (default: 3) + config.feature_flag_request_timeout_seconds = 3 # Error callback to detect misconfiguration config.on_error = proc { |status, msg| Rails.logger.error("PostHog error: #{msg}") } -end -# Rails-specific configuration -PostHog::Rails.configure do |config| - config.auto_capture_exceptions = true # Enable automatic exception capture - config.report_rescued_exceptions = true # Report exceptions Rails rescues - config.auto_instrument_active_job = true # Instrument background jobs - config.capture_user_context = true # Include user info in exceptions - config.current_user_method = :current_user # Method to get current user - # Add additional exceptions to ignore - config.excluded_exceptions = ['MyCustomError'] + # Before-send callback to modify or drop events + config.before_send = proc { |event| + event[:properties] ||= {} + event[:properties]['environment'] = Rails.env + event + } + # Disable network calls in test mode + config.test_mode = true if Rails.env.test? end ``` @@ -141,20 +162,45 @@ Ruby PostHog AI ```ruby -# Track an event -PostHog.capture( +PostHog.capture({ distinct_id: current_user.id, event: 'post_created', properties: { title: @post.title } -) -# Identify a user -PostHog.identify( +}) +``` + +Identify a user and set their person properties: + +Ruby + +PostHog AI + +```ruby +PostHog.identify({ distinct_id: current_user.id, properties: { email: current_user.email, plan: current_user.plan } -) +}) +``` + +The Rails integration delegates methods like `capture`, `identify`, `alias`, `group_identify`, `evaluate_flags`, `capture_exception`, `flush`, and `shutdown` to the initialized `PostHog::Client`. + +## Request context + +PostHog Rails automatically applies request-scoped context to events captured during web requests. Request metadata such as `$current_url`, `$request_method`, `$request_path`, `$user_agent`, and `$ip` is added to event properties. + +When `use_tracing_headers` is enabled, PostHog tracing headers (`X-PostHog-Distinct-Id` and `X-PostHog-Session-Id`) are also used as default `distinct_id` and `$session_id` values. Explicit `distinct_id` and properties passed to `PostHog.capture` always take precedence. + +Disable tracing header identity/session capture if you do not want client-supplied tracing headers used for server-side events. Request metadata is still captured: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.use_tracing_headers = false ``` ## Error tracking @@ -178,6 +224,8 @@ class PostsController < ApplicationController end ``` +`report_rescued_exceptions` controls whether exceptions Rails rescues (for example, exceptions rendered by Rails error pages) are captured. Enable it along with `auto_capture_exceptions` for complete error visibility, or leave it disabled to capture only unhandled exceptions. + ### Manual exception capture You can also manually capture exceptions: @@ -194,6 +242,22 @@ PostHog.capture_exception( ) ``` +If you evaluated feature flags for the request, pass the same snapshot to include matching flag properties on the exception event: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' }, + flags: flags +) +``` + ### Background job exceptions When `auto_instrument_active_job` is enabled, ActiveJob exceptions are automatically captured with job context: @@ -214,7 +278,7 @@ end #### Associating jobs with users -By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key: +By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key in hash arguments: Ruby @@ -225,7 +289,7 @@ PostHog AI ProcessOrderJob.perform_later(order.id, user_id: current_user.id) ``` -For more control, use the `posthog_distinct_id` class method: +For more control, use the `posthog_distinct_id` class method. The proc or block receives the same arguments as `perform`: Ruby @@ -233,13 +297,30 @@ PostHog AI ```ruby class SendWelcomeEmailJob < ApplicationJob - posthog_distinct_id ->(user, options) { user.id } + posthog_distinct_id ->(user, _options) { user.id } def perform(user, options = {}) UserMailer.welcome(user).deliver_now end end ``` +You can also use a block: + +Ruby + +PostHog AI + +```ruby +class ProcessOrderJob < ApplicationJob + posthog_distinct_id do |_order, notify_user_id| + notify_user_id + end + def perform(order, notify_user_id) + # Process the order... + end +end +``` + ### Rails 7.0+ error reporter PostHog integrates with Rails' built-in error reporting: @@ -256,11 +337,13 @@ end Rails.error.record(exception, context: { user_id: current_user.id }) ``` -PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. +PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. Other context keys are included as properties on the exception event. ### User context -PostHog Rails automatically captures user information from your controllers. If your user method has a different name, configure it: +PostHog Rails automatically captures authenticated user information from your controllers for exceptions. Authenticated Rails user context takes precedence over client-supplied tracing headers for exception identity. + +If your user method has a different name, configure it: Ruby @@ -272,11 +355,15 @@ PostHog::Rails.config.current_user_method = :logged_in_user #### User ID extraction -By default, PostHog Rails auto-detects the user's distinct ID by trying these methods: +By default, PostHog Rails auto-detects the user's distinct ID by trying these methods in order: 1. `posthog_distinct_id` – Define this on your User model for full control 2. `distinct_id` – Common analytics convention 3. `id` – Standard ActiveRecord primary key +4. `pk` – Primary key alias +5. `uuid` – For UUID-based primary keys + +It also checks hash-like users for `id`, `pk`, and `uuid` keys. You can configure a specific method: @@ -309,9 +396,16 @@ The following exceptions are not reported by default (common 4xx errors): - `AbstractController::ActionNotFound` - `ActionController::BadRequest` - `ActionController::InvalidAuthenticityToken` +- `ActionController::InvalidCrossOriginRequest` +- `ActionController::MethodNotAllowed` +- `ActionController::NotImplemented` +- `ActionController::ParameterMissing` - `ActionController::RoutingError` - `ActionController::UnknownFormat` +- `ActionController::UnknownHttpMethod` +- `ActionDispatch::Http::Parameters::ParseError` - `ActiveRecord::RecordNotFound` +- `ActiveRecord::RecordNotUnique` Add more with: @@ -325,7 +419,7 @@ PostHog::Rails.config.excluded_exceptions = ['MyException'] ## Feature flags -Use feature flags in your Rails app: +Evaluate flags once for the current user, then read values from the returned snapshot: Ruby @@ -334,7 +428,8 @@ PostHog AI ```ruby class PostsController < ApplicationController def show - if PostHog.is_feature_enabled('new-post-design', current_user.id) + flags = PostHog.evaluate_flags(current_user.id) + if flags.enabled?('new-post-design') render 'posts/show_new' else render 'posts/show' @@ -343,6 +438,35 @@ class PostsController < ApplicationController end ``` +For multivariate flags and experiments, use `get_flag`: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +variant = flags.get_flag('checkout-experiment') +if variant == 'test' + # Do something differently +end +``` + +When capturing an event after branching on a flag, pass the same `flags` snapshot so the event includes the exact flag values used by your code: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture({ + distinct_id: current_user.id, + event: 'checkout_started', + flags: flags.only_accessed +}) +``` + For local evaluation, ensure you've set `personal_api_key`: Ruby @@ -355,9 +479,11 @@ config.personal_api_key = Rails.application.credentials.posthog[:personal_api_ke See our [Ruby SDK docs](/docs/libraries/ruby.md#local-evaluation) for details on local evaluation with Puma and Unicorn servers. +> **Note:** `PostHog.is_feature_enabled`, `PostHog.get_feature_flag`, `PostHog.get_feature_flag_result`, `PostHog.get_feature_flag_payload`, and `PostHog.capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `PostHog.evaluate_flags` for new code. + ## Testing -In your test environment, disable PostHog or use test mode: +In your test environment, disable network calls with test mode: config/environments/test.rb @@ -365,7 +491,8 @@ PostHog AI ```ruby PostHog.init do |config| - config.test_mode = true # Events are queued but not sent + config.api_key = '' + config.test_mode = true end ``` @@ -389,23 +516,33 @@ end | Option | Type | Default | Description | | --- | --- | --- | --- | -| api_key | String | required | Your PostHog project token | -| host | String | https://us.i.posthog.com | PostHog instance URL | -| personal_api_key | String | nil | For feature flag evaluation | -| test_mode | Boolean | false | Don't send events (for testing) | -| on_error | Proc | nil | Error callback | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. | +| personal_api_key | String | nil | Personal API key for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error). | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | + +The `PostHog.init` block supports the options above. Less common core options like `batch_size`, `disable_singleton_warning`, `skip_ssl_verification`, and the experimental `flag_definition_cache_provider` can be passed as an options hash to `PostHog.init(...)`; see the [Ruby SDK docs](/docs/libraries/ruby.md#configuration) for details. ### Rails-specific options +Configure these via `PostHog::Rails.configure` or `PostHog::Rails.config`: + | Option | Type | Default | Description | | --- | --- | --- | --- | -| auto_capture_exceptions | Boolean | false | Automatically capture exceptions | -| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues | -| auto_instrument_active_job | Boolean | false | Instrument ActiveJob | -| capture_user_context | Boolean | true | Include user info | -| current_user_method | Symbol | :current_user | Controller method for user | -| user_id_method | Symbol | nil | Method to extract ID from user object | -| excluded_exceptions | Array | [] | Additional exceptions to ignore | +| auto_capture_exceptions | Boolean | false | Automatically capture exceptions. | +| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues. | +| auto_instrument_active_job | Boolean | false | Capture ActiveJob exceptions with job context. | +| excluded_exceptions | Array | [] | Additional exception class names to ignore. | +| use_tracing_headers | Boolean | true | Use X-PostHog-Distinct-Id and X-PostHog-Session-Id as request-scoped defaults. | +| capture_user_context | Boolean | true | Include authenticated user info in exceptions. | +| current_user_method | Symbol | :current_user | Controller method used to fetch the current user. | +| user_id_method | Symbol | nil | Method used to extract the distinct ID from the user object. Auto-detects when nil. | ## Troubleshooting @@ -423,7 +560,7 @@ end => true ``` -2. Check your excluded exceptions list +2. Check your excluded exceptions list. 3. Verify middleware is installed: @@ -437,9 +574,9 @@ end ### User context not working -1. Verify `current_user_method` matches your controller method -2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, or `id` -3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method` +1. Verify `current_user_method` matches your controller method. +2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, `id`, `pk`, or `uuid`. +3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method`. ### Feature flags not working diff --git a/skills/instrument-integration/references/ruby.md b/skills/instrument-integration/references/ruby.md index 8a70dac..ab491dd 100644 --- a/skills/instrument-integration/references/ruby.md +++ b/skills/instrument-integration/references/ruby.md @@ -4,6 +4,8 @@ The `posthog-ruby` library provides tracking functionality on the server-side fo 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 web app or other server-side application that needs performance. +> **Use a single client instance (singleton)** — Create the PostHog client once and reuse it throughout your application. Multiple client instances with the same API key can cause dropped events and inconsistent behavior. The SDK logs a warning if it detects multiple instances. + ## Installation Add this to your `Gemfile`: @@ -33,12 +35,98 @@ posthog = PostHog::Client.new({ You can find your project token and instance address in the [project settings](https://app.posthog.com/project/settings) page in PostHog. +## Configuration + +Initialize the client with your project token before making any calls: + +Ruby + +PostHog AI + +```ruby +require 'posthog' +posthog = PostHog::Client.new({ + api_key: '', + host: 'https://us.i.posthog.com', + on_error: Proc.new { |status, msg| print msg } +}) +``` + +Available client options: + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. Include the protocol, for example https://us.i.posthog.com or https://eu.i.posthog.com. | +| personal_api_key | String | nil | Personal API key. Required for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| batch_size | Integer | 100 | Maximum number of events to send in one async batch. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. Useful in forking environments like Sidekiq and Resque. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error) for API or serialization errors. | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | +| disable_singleton_warning | Boolean | false | Suppress warnings about multiple clients with the same API key. Use only when you intentionally need multiple clients. | +| skip_ssl_verification | Boolean | false | Disable SSL certificate verification. Intended only for local development or custom deployments. | +| flag_definition_cache_provider | Object | nil | Experimental provider for distributed feature flag definition caching. See [distributed flag definition caching](#distributed-flag-definition-caching). | + +### Filtering or modifying events before sending + +Use `before_send` to add, modify, or drop events immediately before the SDK queues or sends them: + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ + api_key: '', + before_send: Proc.new do |event| + event[:properties] ||= {} + event[:properties]['environment'] = ENV['RACK_ENV'] + # Return nil to drop the event + event[:properties]['internal_user'] == true ? nil : event + end +}) +``` + +### Flushing and shutting down + +For short-lived scripts, call `flush` before the process exits. Call `shutdown` when your application is stopping to flush pending events and stop background resources. + +Ruby + +PostHog AI + +```ruby +posthog.capture({ distinct_id: 'user_123', event: 'script_finished' }) +posthog.flush +posthog.shutdown +``` + ## Identifying users > **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). > > See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. +Identify a user and set their person properties with `identify`: + +Ruby + +PostHog AI + +```ruby +posthog.identify({ + distinct_id: 'distinct_id_of_your_user', + properties: { + email: 'john@doe.com', + pro_user: false + } +}) +``` + ## Capturing events You can send custom events using `capture`: @@ -93,6 +181,20 @@ posthog.capture({ }) ``` +`capture` accepts these fields: + +| Field | Type | Description | +| --- | --- | --- | +| distinct_id | String | The user ID. If omitted, framework integrations can provide request context; otherwise the SDK generates a UUID and marks the event as personless. | +| event | String | Event name. Required. | +| properties | Hash | Event properties. | +| groups | Hash | Group analytics mapping from group type to group key. | +| timestamp | Time | When the event occurred. Defaults to the current time. | +| message_id | String | Optional message ID. | +| uuid | String | Optional event UUID used for deduplication. Must be a valid UUID. | +| flags | PostHog::FeatureFlagEvaluations | Snapshot returned by evaluate_flags. Adds $feature/ and $active_feature_flags properties without another /flags request. | +| send_feature_flags | Boolean, Hash, or PostHog::SendFeatureFlagsOptions | Deprecated. Prefer passing flags: from evaluate_flags. | + ## Person profiles and properties The Ruby SDK captures identified events by default. These create [person profiles](/docs/data/persons.md). To set [person properties](/docs/data/user-properties.md) in these profiles, include them when capturing an event: @@ -102,14 +204,14 @@ Ruby PostHog AI ```ruby -posthog.capture( +posthog.capture({ distinct_id: 'distinct_id', event: 'event_name', properties: { '$set': { name: 'Max Hedgehog' }, '$set_once': { initial_url: '/blog' } } -) +}) ``` For more details on the difference between `$set` and `$set_once`, see our [person properties docs](/docs/data/user-properties.md#what-is-the-difference-between-set-and-set_once). @@ -121,13 +223,13 @@ Ruby PostHog AI ```ruby -posthog.capture( +posthog.capture({ distinct_id: 'distinct_id', event: 'event_name', properties: { '$process_person_profile': false } -) +}) ``` ## Alias @@ -141,10 +243,10 @@ Ruby PostHog AI ```ruby -posthog.alias( - distinct_id: "distinct_id", - alias: "alias_id" -) +posthog.alias({ + distinct_id: 'distinct_id', + alias: 'alias_id' +}) ``` We strongly recommend reading our docs on [alias](/docs/data/identify.md#alias-assigning-multiple-distinct-ids-to-the-same-user) to best understand how to correctly use this method. @@ -192,7 +294,7 @@ end `flags.get_flag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `nil` when the flag wasn't returned by the evaluation. -> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_payload()`, and `capture(send_feature_flags: true)` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. +> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_result()`, `posthog.get_feature_flag_payload()`, and `capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. ### Step 2: Include feature flag information when capturing events @@ -281,6 +383,36 @@ flags = posthog.evaluate_flags( ) ``` +### Evaluating locally only + +If you want to skip the remote `/flags` request and only use locally cached definitions, pass `only_evaluate_locally: true`: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + only_evaluate_locally: true, +) +``` + +### Disabling GeoIP for flag evaluation + +Pass `disable_geoip: true` to disable GeoIP lookup for remote flag evaluation: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + disable_geoip: true, +) +``` + ### Sending `$feature_flag_called` events Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluate_flags()`, the SDK sends this event when you call `flags.enabled?()` or `flags.get_flag()` for a flag. @@ -367,6 +499,18 @@ posthog = PostHog::Client.new({ }) ``` +### Legacy single-flag methods + +The following methods are still available during the migration period, but are deprecated. Prefer `evaluate_flags` for new code. + +| Method | Replacement | +| --- | --- | +| posthog.is_feature_enabled(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).enabled?(flag_key) | +| posthog.get_feature_flag(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).get_flag(flag_key) | +| posthog.get_feature_flag_payload(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).get_flag_payload(flag_key) | +| posthog.get_feature_flag_result(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...) and read get_flag / get_flag_payload | +| posthog.capture({ ..., send_feature_flags: true }) | posthog.capture({ ..., flags: flags }) | + ### Local Evaluation Evaluating feature flags requires making a request to PostHog for each flag. However, you can improve performance by evaluating flags locally. Instead of making a request for each flag, PostHog will periodically request and store feature flag definitions locally, enabling you to evaluate flags without making additional requests. @@ -377,26 +521,26 @@ For details on how to implement local evaluation, see our [local evaluation guid #### Evaluating feature flags locally in unicorn server -If you have `preload_app true` in your unicorn config, you can use the [`after_fork`](https://www.rubydoc.info/gems/unicorn/Unicorn%2FConfigurator:after_fork) hook (which is part of the unicorn's configuration) to enable the feature flag cache to receive the updates from posthog dashboard. +If you have `preload_app true` in your unicorn config, you can use the [`after_fork`](https://www.rubydoc.info/gems/unicorn/Unicorn%2FConfigurator:after_fork) hook (which is part of the unicorn's configuration) to enable the feature flag cache to receive the updates from PostHog. Ruby PostHog AI ```ruby -after_fork do |server, worker| - $posthog = PostHog::Client.new( +after_fork do |_server, _worker| + $posthog = PostHog::Client.new({ api_key: '', - personal_api_key: '' + personal_api_key: '', host: 'https://us.i.posthog.com', on_error: Proc.new { |status, msg| print msg } - ) + }) end ``` #### Evaluating feature flags locally in a Puma server -If you use Puma with multiple workers, you can use the `on_worker_boot` hook (which is part of the Puma's configuration) to enable the feature flag cache to receive the updates from PostHog. +If you use Puma with multiple workers, you can use the `on_worker_boot` hook (which is part of Puma's configuration) to enable the feature flag cache to receive updates from PostHog. Ruby @@ -404,15 +548,50 @@ PostHog AI ```ruby on_worker_boot do - $posthog = PostHog::Client.new( + $posthog = PostHog::Client.new({ api_key: '', - personal_api_key: '' + personal_api_key: '', host: 'https://us.i.posthog.com', on_error: Proc.new { |status, msg| print msg } - ) + }) end ``` +### Distributed flag definition caching + +`flag_definition_cache_provider` is an experimental API for sharing locally evaluated feature flag definitions across multiple workers or processes. The provider object must implement: + +- `flag_definitions` – returns cached definitions as a hash with `:flags`, `:group_type_mapping`, and `:cohorts`, or `nil` if empty. +- `should_fetch_flag_definitions?` – returns `true` if this process should fetch fresh definitions from PostHog. +- `on_flag_definitions_received(data)` – stores freshly fetched definitions. +- `shutdown` – releases locks or other resources. + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ + api_key: '', + personal_api_key: '', + flag_definition_cache_provider: my_cache_provider +}) +``` + +Because this API is experimental, it may change in future minor versions. + +### Remote config payloads + +Use `get_remote_config_payload` to fetch the decrypted remote config payload for a flag. This requires `personal_api_key`. + +Ruby + +PostHog AI + +```ruby +payload = posthog.get_remote_config_payload('flag-key') +``` + ## Experiments (A/B tests) Since [experiments](/docs/experiments/start-here.md) use feature flags, the code for running an experiment is very similar to the feature flags code: @@ -437,7 +616,7 @@ Group analytics allows you to associate an event with a group (e.g. teams, organ > **Note:** This is a paid feature and is not available on the open-source or free cloud plan. Learn more on the [pricing page](/pricing.md). -- Capture an event and associate it with a group +Capture an event and associate it with a group: Ruby @@ -450,34 +629,32 @@ posthog.capture({ properties: { movie_id: '123', category: 'romcom' - } + }, groups: { 'company': 'company_id_in_your_db' } }) ``` -- Update properties on a group +Update properties on a group: Ruby PostHog AI ```ruby -posthog.group_identify( - { - group_type: "company", - group_key: "company_id_in_your_db", - properties: { - name: "Awesome Inc." - } +posthog.group_identify({ + group_type: 'company', + group_key: 'company_id_in_your_db', + properties: { + name: 'Awesome Inc.' } -) +}) ``` The `name` is a special property which is used in the PostHog UI for the name of the group. If you don't specify a `name` property, the group ID will be used instead. -If the optional `distinct_id` is not provided in the group identify call, it defaults to `${groupType}_${groupKey}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior will result in each group appearing as a separate person in PostHog. To avoid this, it's often more practical to use a consistent `distinct_id`, such as `group_identifier`. +If the optional `distinct_id` is not provided in the group identify call, it defaults to `$#{group_type}_#{group_key}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior will result in each group appearing as a separate person in PostHog. To avoid this, it's often more practical to use a consistent `distinct_id`, such as `group_identifier`. ## Exception capture @@ -487,9 +664,7 @@ You can capture exceptions using the `posthog-ruby` library. This enables you to The [posthog-rails](/docs/libraries/ruby-on-rails.md) gem provides automatic exception capture, ActiveJob instrumentation, and user context out of the box. See our [Rails error tracking guide](/docs/error-tracking/installation/ruby-on-rails.md) for details. -For non-Rails Ruby applications, you can manually capture exceptions: - -To capture exceptions, use the `capture_exception` method: +For non-Rails Ruby applications, you can manually capture exceptions with `capture_exception`: Ruby @@ -498,12 +673,12 @@ PostHog AI ```ruby begin # Code that might raise an exception - raise StandardError, "Something went wrong" + raise StandardError, 'Something went wrong' rescue => e posthog.capture_exception( e, - distinct_id: 'user_distinct_id', - properties: { + 'user_distinct_id', + { custom_property: 'custom_value' } ) @@ -514,9 +689,10 @@ The `capture_exception` method accepts the following parameters: | Parameter | Type | Description | | --- | --- | --- | -| exception | Exception | The exception object to capture (required) | -| distinct_id | String | The distinct ID of the user (optional) | -| properties | Hash | Additional properties to attach to the exception event (optional) | +| exception | Exception, String, or exception-like object | The exception to capture. Required. | +| distinct_id | String | The distinct ID of the user. Optional; request context can provide a default, otherwise the SDK generates a UUID. | +| additional_properties | Hash | Additional properties to attach to the exception event. Optional. | +| flags | PostHog::FeatureFlagEvaluations | Optional keyword argument. Adds the same feature flag properties as capture({ flags: flags }). | You can also override the [fingerprint](/docs/error-tracking/fingerprints.md) to customize how exceptions are grouped into issues: @@ -527,8 +703,8 @@ PostHog AI ```ruby posthog.capture_exception( e, - distinct_id: 'user_distinct_id', - properties: { + 'user_distinct_id', + { '$exception_fingerprint': 'CustomExceptionGroup' } ) @@ -536,7 +712,41 @@ posthog.capture_exception( ## Debug mode -The Ruby SDK debug logs by default. The log level by default is set to `WARN`. You can change it to `DEBUG` if you want to debug the client by running `posthog.logger.level = Logger::DEBUG`, where `posthog` is your initialized `PostHog::Client` instance. +The Ruby SDK logs warnings by default. You can change the log level to `DEBUG` to debug the client: + +Ruby + +PostHog AI + +```ruby +posthog.logger.level = Logger::DEBUG +``` + +You can also replace the SDK logger globally: + +Ruby + +PostHog AI + +```ruby +PostHog::Logging.logger = Rails.logger +``` + +## Test helpers + +When `test_mode: true`, events remain queued. You can inspect and clear the queue in tests: + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ api_key: '', test_mode: true }) +posthog.capture({ distinct_id: 'user_123', event: 'test_event' }) +posthog.queued_messages +posthog.dequeue_last_message +posthog.clear +``` ## Thank you diff --git a/skills/instrument-llm-analytics/SKILL.md b/skills/instrument-llm-analytics/SKILL.md index 4b92755..29c4390 100644 --- a/skills/instrument-llm-analytics/SKILL.md +++ b/skills/instrument-llm-analytics/SKILL.md @@ -55,41 +55,41 @@ STEP 6: Set up environment variables. ## Reference files -- `references/openai.md` - Openai llm analytics installation - docs -- `references/azure-openai.md` - Azure openai llm analytics installation - docs -- `references/anthropic.md` - Anthropic llm analytics installation - docs -- `references/google.md` - Google llm analytics installation - docs -- `references/cohere.md` - Cohere llm analytics installation - docs -- `references/mistral.md` - Mistral llm analytics installation - docs -- `references/perplexity.md` - Perplexity llm analytics installation - docs -- `references/deepseek.md` - Deepseek llm analytics installation - docs -- `references/groq.md` - Groq llm analytics installation - docs -- `references/together-ai.md` - Together ai llm analytics installation - docs -- `references/fireworks-ai.md` - Fireworks ai llm analytics installation - docs -- `references/xai.md` - Xai llm analytics installation - docs -- `references/cerebras.md` - Cerebras llm analytics installation - docs -- `references/hugging-face.md` - Hugging face llm analytics installation - docs -- `references/ollama.md` - Ollama llm analytics installation - docs -- `references/openrouter.md` - Openrouter llm analytics installation - docs -- `references/langchain.md` - Langchain llm analytics installation - docs -- `references/llamaindex.md` - Llamaindex llm analytics installation - docs -- `references/crewai.md` - Crewai llm analytics installation - docs -- `references/autogen.md` - Autogen llm analytics installation - docs -- `references/dspy.md` - Dspy llm analytics installation - docs -- `references/langgraph.md` - Langgraph llm analytics installation - docs -- `references/pydantic-ai.md` - Pydantic ai llm analytics installation - docs -- `references/vercel-ai.md` - Vercel ai SDK llm analytics installation - docs -- `references/litellm.md` - Litellm llm analytics installation - docs -- `references/instructor.md` - Instructor llm analytics installation - docs -- `references/semantic-kernel.md` - Semantic kernel llm analytics installation - docs -- `references/mirascope.md` - Mirascope llm analytics installation - docs -- `references/mastra.md` - Mastra llm analytics installation - docs -- `references/smolagents.md` - Smolagents llm analytics installation - docs -- `references/openai-agents.md` - Openai agents SDK llm analytics installation - docs -- `references/portkey.md` - Portkey llm analytics installation - docs -- `references/helicone.md` - Helicone llm analytics installation - docs -- `references/manual-capture.md` - Manual capture llm analytics installation - docs -- `references/basics.md` - Llm analytics basics - docs +- `references/openai.md` - Openai observability installation - docs +- `references/azure-openai.md` - Azure openai observability installation - docs +- `references/anthropic.md` - Anthropic ai observability installation - docs +- `references/google.md` - Google ai observability installation - docs +- `references/cohere.md` - Cohere ai observability installation - docs +- `references/mistral.md` - Mistral ai observability installation - docs +- `references/perplexity.md` - Perplexity ai observability installation - docs +- `references/deepseek.md` - Deepseek ai observability installation - docs +- `references/groq.md` - Groq ai observability installation - docs +- `references/together-ai.md` - Together ai observability installation - docs +- `references/fireworks-ai.md` - Fireworks ai observability installation - docs +- `references/xai.md` - Xai observability installation - docs +- `references/cerebras.md` - Cerebras ai observability installation - docs +- `references/hugging-face.md` - Hugging face ai observability installation - docs +- `references/ollama.md` - Ollama ai observability installation - docs +- `references/openrouter.md` - Openrouter ai observability installation - docs +- `references/langchain.md` - Langchain ai observability installation - docs +- `references/llamaindex.md` - Llamaindex ai observability installation - docs +- `references/crewai.md` - Crewai observability installation - docs +- `references/autogen.md` - Autogen ai observability installation - docs +- `references/dspy.md` - Dspy ai observability installation - docs +- `references/langgraph.md` - Langgraph ai observability installation - docs +- `references/pydantic-ai.md` - Pydantic ai observability installation - docs +- `references/vercel-ai.md` - Vercel ai SDK observability installation - docs +- `references/litellm.md` - Litellm ai observability installation - docs +- `references/instructor.md` - Instructor ai observability installation - docs +- `references/semantic-kernel.md` - Semantic kernel ai observability installation - docs +- `references/mirascope.md` - Mirascope ai observability installation - docs +- `references/mastra.md` - Mastra ai observability installation - docs +- `references/smolagents.md` - Smolagents ai observability installation - docs +- `references/openai-agents.md` - Openai agents SDK observability installation - docs +- `references/portkey.md` - Portkey ai observability installation - docs +- `references/helicone.md` - Helicone ai observability installation - docs +- `references/manual-capture.md` - Manual capture ai observability installation - docs +- `references/basics.md` - Ai observability basics - docs - `references/traces.md` - Traces - docs - `references/calculating-costs.md` - Calculating llm costs - docs diff --git a/skills/instrument-llm-analytics/references/anthropic.md b/skills/instrument-llm-analytics/references/anthropic.md index f41024f..581ccac 100644 --- a/skills/instrument-llm-analytics/references/anthropic.md +++ b/skills/instrument-llm-analytics/references/anthropic.md @@ -1,4 +1,4 @@ -# Anthropic LLM analytics installation - Docs +# Anthropic AI Observability installation - Docs 1. 1 @@ -139,7 +139,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -147,7 +147,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -159,15 +159,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/autogen.md b/skills/instrument-llm-analytics/references/autogen.md index 5a2a148..84310e2 100644 --- a/skills/instrument-llm-analytics/references/autogen.md +++ b/skills/instrument-llm-analytics/references/autogen.md @@ -1,4 +1,4 @@ -# AutoGen LLM analytics installation - Docs +# AutoGen AI Observability installation - Docs 1. 1 @@ -85,7 +85,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -93,7 +93,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -105,15 +105,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/azure-openai.md b/skills/instrument-llm-analytics/references/azure-openai.md index d09ebc5..4db1f7e 100644 --- a/skills/instrument-llm-analytics/references/azure-openai.md +++ b/skills/instrument-llm-analytics/references/azure-openai.md @@ -1,4 +1,4 @@ -# Azure OpenAI LLM analytics installation - Docs +# Azure OpenAI observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/basics.md b/skills/instrument-llm-analytics/references/basics.md index 113af5f..12b0ea6 100644 --- a/skills/instrument-llm-analytics/references/basics.md +++ b/skills/instrument-llm-analytics/references/basics.md @@ -1,10 +1,10 @@ -# LLM Analytics basics - Docs +# AI Observability basics - Docs -This page covers how your LLM calls become analytics in PostHog and defines key concepts for LLM Analytics. +This page covers how your LLM calls become analytics in PostHog and defines key concepts for AI Observability. ## How LLM calls become events -PostHog's LLM Analytics works by wrapping your existing LLM provider's SDK to capture requests and responses. Your API calls still go directly to your provider, but the wrapper extracts metadata from each call and sends it to PostHog as an event. +PostHog's AI Observability works by wrapping your existing LLM provider's SDK to capture requests and responses. Your API calls still go directly to your provider, but the wrapper extracts metadata from each call and sends it to PostHog as an event. graph LR Call\["LLM call"\] --> Wrapper\["Wrapped SDK"\] Wrapper --> Provider\["LLM provider API"\] Wrapper --> Event\["Event"\] Event --> PostHog\["PostHog"\] @@ -23,7 +23,7 @@ Generations are represented using the event name `$ai_generation`. Each generati PostHog automatically calculates costs by matching your model and provider against pricing data. We use OpenRouter's pricing as our primary source, with fallback to manually maintained pricing for additional models. -You can also [set custom pricing](/docs/llm-analytics/calculating-costs.md) if you have negotiated rates or use unsupported models. +You can also [set custom pricing](/docs/ai-observability/calculating-costs.md) if you have negotiated rates or use unsupported models. ### Message roles @@ -47,11 +47,11 @@ Here's a breakdown of this hierarchy: | Term | Definition | Example | | --- | --- | --- | -| [Session](/docs/llm-analytics/sessions.md) | Groups multiple traces together | A user's conversation thread | -| [Trace](/docs/llm-analytics/traces.md) | Contains generations and spans for a single request | One chatbot message and response | -| [Span](/docs/llm-analytics/spans.md) | Tracks an operation within a trace | A retrieval step or function call | -| [Generation](/docs/llm-analytics/generations.md) | An LLM call, tracked as $ai_generation events | Sending a prompt to Claude | -| [Embedding](/docs/llm-analytics/embeddings.md) | Converts text into vectors | Vectorizing documents for RAG | +| [Session](/docs/ai-observability/sessions.md) | Groups multiple traces together | A user's conversation thread | +| [Trace](/docs/ai-observability/traces.md) | Contains generations and spans for a single request | One chatbot message and response | +| [Span](/docs/ai-observability/spans.md) | Tracks an operation within a trace | A retrieval step or function call | +| [Generation](/docs/ai-observability/generations.md) | An LLM call, tracked as $ai_generation events | Sending a prompt to Claude | +| [Embedding](/docs/ai-observability/embeddings.md) | Converts text into vectors | Vectorizing documents for RAG | ### Community questions diff --git a/skills/instrument-llm-analytics/references/calculating-costs.md b/skills/instrument-llm-analytics/references/calculating-costs.md index 92e35bf..0b24036 100644 --- a/skills/instrument-llm-analytics/references/calculating-costs.md +++ b/skills/instrument-llm-analytics/references/calculating-costs.md @@ -51,7 +51,7 @@ You can override PostHog's automatic cost calculation by providing custom pricin ### Option 1: Custom price per token -If you know your pricing per token, you can set the following [custom properties](/docs/llm-analytics/custom-properties.md) when calling your LLM: +If you know your pricing per token, you can set the following [custom properties](/docs/ai-observability/custom-properties.md) when calling your LLM: - `$ai_input_token_price` (required): Price per input/prompt token - `$ai_output_token_price` (required): Price per output/completion token @@ -120,7 +120,7 @@ Both `$ai_input_token_price` and `$ai_output_token_price` must be provided for c ### Option 2: Pre-calculated costs -If you're [manually capturing](/docs/llm-analytics/installation/manual-capture.md) LLM events and have already calculated the total costs yourself, you can send them directly: +If you're [manually capturing](/docs/ai-observability/installation/manual-capture.md) LLM events and have already calculated the total costs yourself, you can send them directly: - `$ai_input_cost_usd`: Total cost for input/prompt tokens in USD - `$ai_output_cost_usd`: Total cost for output/completion tokens in USD diff --git a/skills/instrument-llm-analytics/references/cerebras.md b/skills/instrument-llm-analytics/references/cerebras.md index 6bb8b05..ceed9cc 100644 --- a/skills/instrument-llm-analytics/references/cerebras.md +++ b/skills/instrument-llm-analytics/references/cerebras.md @@ -1,4 +1,4 @@ -# Cerebras LLM analytics installation - Docs +# Cerebras AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/cohere.md b/skills/instrument-llm-analytics/references/cohere.md index c498f1e..aa09ff4 100644 --- a/skills/instrument-llm-analytics/references/cohere.md +++ b/skills/instrument-llm-analytics/references/cohere.md @@ -1,4 +1,4 @@ -# Cohere LLM analytics installation - Docs +# Cohere AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/crewai.md b/skills/instrument-llm-analytics/references/crewai.md index ee4d05b..243d4b9 100644 --- a/skills/instrument-llm-analytics/references/crewai.md +++ b/skills/instrument-llm-analytics/references/crewai.md @@ -1,4 +1,4 @@ -# CrewAI LLM analytics installation - Docs +# CrewAI observability installation - Docs 1. 1 @@ -88,7 +88,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 5. ## Verify traces and generations @@ -96,7 +96,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -108,15 +108,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/deepseek.md b/skills/instrument-llm-analytics/references/deepseek.md index df0cf32..286b617 100644 --- a/skills/instrument-llm-analytics/references/deepseek.md +++ b/skills/instrument-llm-analytics/references/deepseek.md @@ -1,4 +1,4 @@ -# DeepSeek LLM analytics installation - Docs +# DeepSeek AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/dspy.md b/skills/instrument-llm-analytics/references/dspy.md index eb6c157..49578ea 100644 --- a/skills/instrument-llm-analytics/references/dspy.md +++ b/skills/instrument-llm-analytics/references/dspy.md @@ -1,4 +1,4 @@ -# DSPy LLM analytics installation - Docs +# DSPy AI Observability installation - Docs 1. 1 @@ -86,7 +86,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 5. ## Verify traces and generations @@ -94,7 +94,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -106,15 +106,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/fireworks-ai.md b/skills/instrument-llm-analytics/references/fireworks-ai.md index 203d933..c0ec1b2 100644 --- a/skills/instrument-llm-analytics/references/fireworks-ai.md +++ b/skills/instrument-llm-analytics/references/fireworks-ai.md @@ -1,4 +1,4 @@ -# Fireworks AI LLM analytics installation - Docs +# Fireworks AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/google.md b/skills/instrument-llm-analytics/references/google.md index 68f46db..97c14a6 100644 --- a/skills/instrument-llm-analytics/references/google.md +++ b/skills/instrument-llm-analytics/references/google.md @@ -1,4 +1,4 @@ -# Google LLM analytics installation - Docs +# Google AI Observability installation - Docs 1. 1 @@ -135,7 +135,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. 4 @@ -171,7 +171,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -183,15 +183,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/groq.md b/skills/instrument-llm-analytics/references/groq.md index bc76fda..39dc918 100644 --- a/skills/instrument-llm-analytics/references/groq.md +++ b/skills/instrument-llm-analytics/references/groq.md @@ -1,4 +1,4 @@ -# Groq LLM analytics installation - Docs +# Groq AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/helicone.md b/skills/instrument-llm-analytics/references/helicone.md index c160878..43dca5a 100644 --- a/skills/instrument-llm-analytics/references/helicone.md +++ b/skills/instrument-llm-analytics/references/helicone.md @@ -1,4 +1,4 @@ -# Helicone LLM analytics installation - Docs +# Helicone AI Observability installation - Docs 1. 1 @@ -145,7 +145,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -153,7 +153,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -165,15 +165,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/hugging-face.md b/skills/instrument-llm-analytics/references/hugging-face.md index 81ea9b7..9d41a0d 100644 --- a/skills/instrument-llm-analytics/references/hugging-face.md +++ b/skills/instrument-llm-analytics/references/hugging-face.md @@ -1,4 +1,4 @@ -# Hugging Face LLM analytics installation - Docs +# Hugging Face AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/instructor.md b/skills/instrument-llm-analytics/references/instructor.md index 58c8012..3f17f4b 100644 --- a/skills/instrument-llm-analytics/references/instructor.md +++ b/skills/instrument-llm-analytics/references/instructor.md @@ -1,4 +1,4 @@ -# Instructor LLM analytics installation - Docs +# Instructor AI Observability installation - Docs 1. 1 @@ -147,7 +147,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -155,7 +155,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -167,15 +167,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/langchain.md b/skills/instrument-llm-analytics/references/langchain.md index 6c4e9a9..4a8e764 100644 --- a/skills/instrument-llm-analytics/references/langchain.md +++ b/skills/instrument-llm-analytics/references/langchain.md @@ -1,4 +1,4 @@ -# LangChain LLM analytics installation - Docs +# LangChain AI Observability installation - Docs 1. 1 @@ -139,7 +139,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | It also automatically creates a trace hierarchy based on how LangChain components are nested. @@ -149,7 +149,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -161,15 +161,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/langgraph.md b/skills/instrument-llm-analytics/references/langgraph.md index e180987..8362326 100644 --- a/skills/instrument-llm-analytics/references/langgraph.md +++ b/skills/instrument-llm-analytics/references/langgraph.md @@ -1,4 +1,4 @@ -# LangGraph LLM analytics installation - Docs +# LangGraph AI Observability installation - Docs 1. 1 @@ -152,7 +152,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -160,7 +160,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -172,15 +172,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/litellm.md b/skills/instrument-llm-analytics/references/litellm.md index 17312cf..fe68b10 100644 --- a/skills/instrument-llm-analytics/references/litellm.md +++ b/skills/instrument-llm-analytics/references/litellm.md @@ -1,4 +1,4 @@ -# LiteLLM LLM analytics installation - Docs +# LiteLLM AI Observability installation - Docs 1. 1 @@ -137,7 +137,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 5. 5 @@ -182,7 +182,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -194,15 +194,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/llamaindex.md b/skills/instrument-llm-analytics/references/llamaindex.md index 249214f..d2a55dd 100644 --- a/skills/instrument-llm-analytics/references/llamaindex.md +++ b/skills/instrument-llm-analytics/references/llamaindex.md @@ -1,4 +1,4 @@ -# LlamaIndex LLM analytics installation - Docs +# LlamaIndex AI Observability installation - Docs 1. 1 @@ -83,7 +83,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -91,7 +91,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -103,15 +103,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/manual-capture.md b/skills/instrument-llm-analytics/references/manual-capture.md index 55a32f2..9bb377a 100644 --- a/skills/instrument-llm-analytics/references/manual-capture.md +++ b/skills/instrument-llm-analytics/references/manual-capture.md @@ -1,4 +1,4 @@ -# Manual capture LLM analytics installation - Docs +# Manual capture AI Observability installation - Docs 1. 1 @@ -397,7 +397,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -409,15 +409,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/mastra.md b/skills/instrument-llm-analytics/references/mastra.md index 82bed04..6b1cfef 100644 --- a/skills/instrument-llm-analytics/references/mastra.md +++ b/skills/instrument-llm-analytics/references/mastra.md @@ -1,4 +1,4 @@ -# Mastra LLM analytics installation - Docs +# Mastra AI Observability installation - Docs 1. 1 @@ -93,7 +93,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -101,7 +101,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -113,15 +113,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/mirascope.md b/skills/instrument-llm-analytics/references/mirascope.md index e2149e7..275c41f 100644 --- a/skills/instrument-llm-analytics/references/mirascope.md +++ b/skills/instrument-llm-analytics/references/mirascope.md @@ -1,4 +1,4 @@ -# Mirascope LLM analytics installation - Docs +# Mirascope AI Observability installation - Docs 1. 1 @@ -78,7 +78,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -86,7 +86,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -98,15 +98,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/mistral.md b/skills/instrument-llm-analytics/references/mistral.md index 835ae1f..457b033 100644 --- a/skills/instrument-llm-analytics/references/mistral.md +++ b/skills/instrument-llm-analytics/references/mistral.md @@ -1,4 +1,4 @@ -# Mistral LLM analytics installation - Docs +# Mistral AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/ollama.md b/skills/instrument-llm-analytics/references/ollama.md index 5e7d847..5159af6 100644 --- a/skills/instrument-llm-analytics/references/ollama.md +++ b/skills/instrument-llm-analytics/references/ollama.md @@ -1,4 +1,4 @@ -# Ollama LLM analytics installation - Docs +# Ollama AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/openai-agents.md b/skills/instrument-llm-analytics/references/openai-agents.md index b1bcdf8..168a877 100644 --- a/skills/instrument-llm-analytics/references/openai-agents.md +++ b/skills/instrument-llm-analytics/references/openai-agents.md @@ -1,4 +1,4 @@ -# OpenAI Agents SDK LLM analytics installation - Docs +# OpenAI Agents SDK observability installation - Docs 1. 1 @@ -26,7 +26,7 @@ **Proxy note** - These SDKs **do not** proxy your calls. They only fire off an async call to PostHog in the background to send the data. You can also use LLM analytics with other SDKs or our API, but you will need to capture the data in the right format. See the schema in the [manual capture section](/docs/llm-analytics/installation/manual-capture.md) for more details. + These SDKs **do not** proxy your calls. They only fire off an async call to PostHog in the background to send the data. You can also use AI observability with other SDKs or our API, but you will need to capture the data in the right format. See the schema in the [manual capture section](/docs/ai-observability/installation/manual-capture.md) for more details. 3. 3 @@ -85,7 +85,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 5. 5 @@ -127,7 +127,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -139,15 +139,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/openai.md b/skills/instrument-llm-analytics/references/openai.md index 19603ab..0f4b857 100644 --- a/skills/instrument-llm-analytics/references/openai.md +++ b/skills/instrument-llm-analytics/references/openai.md @@ -1,4 +1,4 @@ -# OpenAI LLM analytics installation - Docs +# OpenAI observability installation - Docs 1. 1 @@ -162,7 +162,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -174,15 +174,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/openrouter.md b/skills/instrument-llm-analytics/references/openrouter.md index 6dba88c..d0bfcfc 100644 --- a/skills/instrument-llm-analytics/references/openrouter.md +++ b/skills/instrument-llm-analytics/references/openrouter.md @@ -1,4 +1,4 @@ -# OpenRouter LLM analytics installation - Docs +# OpenRouter AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/perplexity.md b/skills/instrument-llm-analytics/references/perplexity.md index 8153209..6f6d298 100644 --- a/skills/instrument-llm-analytics/references/perplexity.md +++ b/skills/instrument-llm-analytics/references/perplexity.md @@ -1,4 +1,4 @@ -# Perplexity LLM analytics installation - Docs +# Perplexity AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/portkey.md b/skills/instrument-llm-analytics/references/portkey.md index 04d7a8e..9cf4930 100644 --- a/skills/instrument-llm-analytics/references/portkey.md +++ b/skills/instrument-llm-analytics/references/portkey.md @@ -1,4 +1,4 @@ -# Portkey LLM analytics installation - Docs +# Portkey AI Observability installation - Docs 1. 1 @@ -147,7 +147,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -155,7 +155,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -167,15 +167,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/pydantic-ai.md b/skills/instrument-llm-analytics/references/pydantic-ai.md index a4b8190..cfddd6a 100644 --- a/skills/instrument-llm-analytics/references/pydantic-ai.md +++ b/skills/instrument-llm-analytics/references/pydantic-ai.md @@ -1,4 +1,4 @@ -# Pydantic AI LLM analytics installation - Docs +# Pydantic AI Observability installation - Docs 1. 1 @@ -80,7 +80,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -88,7 +88,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -100,15 +100,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/semantic-kernel.md b/skills/instrument-llm-analytics/references/semantic-kernel.md index aef8382..0b167ac 100644 --- a/skills/instrument-llm-analytics/references/semantic-kernel.md +++ b/skills/instrument-llm-analytics/references/semantic-kernel.md @@ -1,4 +1,4 @@ -# Semantic Kernel LLM analytics installation - Docs +# Semantic Kernel AI Observability installation - Docs 1. 1 @@ -86,7 +86,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -94,7 +94,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -106,15 +106,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/smolagents.md b/skills/instrument-llm-analytics/references/smolagents.md index a32db3e..8f18273 100644 --- a/skills/instrument-llm-analytics/references/smolagents.md +++ b/skills/instrument-llm-analytics/references/smolagents.md @@ -1,4 +1,4 @@ -# smolagents LLM analytics installation - Docs +# smolagents AI Observability installation - Docs 1. 1 @@ -78,7 +78,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -86,7 +86,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -98,15 +98,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/together-ai.md b/skills/instrument-llm-analytics/references/together-ai.md index 156d31e..f937359 100644 --- a/skills/instrument-llm-analytics/references/together-ai.md +++ b/skills/instrument-llm-analytics/references/together-ai.md @@ -1,4 +1,4 @@ -# Together AI LLM analytics installation - Docs +# Together AI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/traces.md b/skills/instrument-llm-analytics/references/traces.md index b311f2a..4c47ff4 100644 --- a/skills/instrument-llm-analytics/references/traces.md +++ b/skills/instrument-llm-analytics/references/traces.md @@ -1,13 +1,13 @@ # Traces - Docs -Traces are a collection of [generations](/docs/llm-analytics/generations.md) and [spans](/docs/llm-analytics/spans.md) that capture a full interaction between a user and an LLM. The [traces tab](https://app.posthog.com/llm-analytics/traces) lists them along with the properties autocaptured by PostHog like the person, total cost, total latency, and more. +Traces are a collection of [generations](/docs/ai-observability/generations.md) and [spans](/docs/ai-observability/spans.md) that capture a full interaction between a user and an LLM. The [traces tab](https://app.posthog.com/llm-analytics/traces) lists them along with the properties autocaptured by PostHog like the person, total cost, total latency, and more. ## Sessions vs Traces -- **Trace** (`$ai_trace_id`): Groups related generations and spans together. Required for all LLM analytics events. +- **Trace** (`$ai_trace_id`): Groups related generations and spans together. Required for all AI Observability events. - **Session** (`$ai_session_id`): Optional property that groups multiple traces together based on your chosen grouping strategy. -See the [Sessions](/docs/llm-analytics/sessions.md) documentation for more details on how to use `$ai_session_id`. +See the [Sessions](/docs/ai-observability/sessions.md) documentation for more details on how to use `$ai_session_id`. ## Trace timeline @@ -27,15 +27,15 @@ When viewing a trace, you can control how conversation messages are displayed us ## Tool calls -Traces display any [tools](/docs/llm-analytics/tools.md) called by the generations within them, shown as tags in the traces list. This makes it easy to see which conversations involved tool use at a glance. +Traces display any [tools](/docs/ai-observability/tools.md) called by the generations within them, shown as tags in the traces list. This makes it easy to see which conversations involved tool use at a glance. ## Sentiment classification -PostHog can classify the sentiment of user messages in a trace as negative, neutral, or positive. Sentiment is computed on-demand using a local model when you view a trace — no data is sent to third-party services. Each trace gets an overall sentiment label and score, with a per-generation and per-message breakdown. See [Sentiment classification](/docs/llm-analytics/sentiment.md) for more details. +PostHog can classify the sentiment of user messages in a trace as negative, neutral, or positive. Sentiment is computed on-demand using a local model when you view a trace — no data is sent to third-party services. Each trace gets an overall sentiment label and score, with a per-generation and per-message breakdown. See [Sentiment classification](/docs/ai-observability/sentiment.md) for more details. ## Search traces with PostHog AI -[PostHog AI](/docs/posthog-ai.md) can search and analyze your LLM traces using natural language. When you're on an [LLM Analytics page](https://app.posthog.com/llm-analytics), PostHog AI automatically switches to its LLM analytics mode, giving it access to tools for searching traces by date range, model, cost, error status, and other properties. +[PostHog AI](/docs/posthog-ai.md) can search and analyze your LLM traces using natural language. When you're on an [AI Observability page](https://app.posthog.com/llm-analytics), PostHog AI automatically switches to its AI Observability mode, giving it access to tools for searching traces by date range, model, cost, error status, and other properties. Example prompts you can try: diff --git a/skills/instrument-llm-analytics/references/vercel-ai.md b/skills/instrument-llm-analytics/references/vercel-ai.md index 7b592b4..1b15d52 100644 --- a/skills/instrument-llm-analytics/references/vercel-ai.md +++ b/skills/instrument-llm-analytics/references/vercel-ai.md @@ -1,4 +1,4 @@ -# Vercel AI SDK LLM analytics installation - Docs +# Vercel AI SDK observability installation - Docs 1. 1 @@ -78,7 +78,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -86,7 +86,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -98,15 +98,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-llm-analytics/references/xai.md b/skills/instrument-llm-analytics/references/xai.md index 16774bd..d0ecc91 100644 --- a/skills/instrument-llm-analytics/references/xai.md +++ b/skills/instrument-llm-analytics/references/xai.md @@ -1,4 +1,4 @@ -# xAI LLM analytics installation - Docs +# xAI Observability installation - Docs 1. 1 @@ -143,7 +143,7 @@ | $ai_output_choices | List of response choices from the LLM | | $ai_output_tokens | The number of tokens in the output (often found in response.usage) | | $ai_total_cost_usd | The total cost in USD (input + output) | - | [[...]](/docs/llm-analytics/generations.md#event-properties) | See [full list](/docs/llm-analytics/generations.md#event-properties) of properties | + | [[...]](/docs/ai-observability/generations.md#event-properties) | See [full list](/docs/ai-observability/generations.md#event-properties) of properties | 4. ## Verify traces and generations @@ -151,7 +151,7 @@ *Confirm LLM events are being sent to PostHog* - Let's make sure LLM events are being captured and sent to PostHog. Under **LLM analytics**, you should see rows of data appear in the **Traces** and **Generations** tabs. + Let's make sure LLM events are being captured and sent to PostHog. Under **AI Observability**, you should see rows of data appear in the **Traces** and **Generations** tabs. ![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syne_ecd0801880.png)![LLM generations in PostHog](https://res.cloudinary.com/dmukukwp6/image/upload/SCR_20250807_syjm_5baab36590.png) @@ -163,15 +163,15 @@ Recommended - Now that you're capturing AI conversations, continue with the resources below to learn what else LLM Analytics enables within the PostHog platform. + Now that you're capturing AI conversations, continue with the resources below to learn what else AI Observability enables within the PostHog platform. | Resource | Description | | --- | --- | - | [Basics](/docs/llm-analytics/basics.md) | Learn the basics of how LLM calls become events in PostHog. | - | [Generations](/docs/llm-analytics/generations.md) | Read about the $ai_generation event and its properties. | - | [Traces](/docs/llm-analytics/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | - | [Spans](/docs/llm-analytics/spans.md) | Review spans and their role in representing individual operations. | - | [Anaylze LLM performance](/docs/llm-analytics/dashboard.md) | Learn how to create dashboards to analyze LLM performance. | + | [Basics](/docs/ai-observability/basics.md) | Learn the basics of how LLM calls become events in PostHog. | + | [Generations](/docs/ai-observability/generations.md) | Read about the $ai_generation event and its properties. | + | [Traces](/docs/ai-observability/traces.md) | Explore the trace hierarchy and how to use it to debug LLM calls. | + | [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. | ### Community questions diff --git a/skills/instrument-logs/references/search.md b/skills/instrument-logs/references/search.md index cda78b3..8f755d1 100644 --- a/skills/instrument-logs/references/search.md +++ b/skills/instrument-logs/references/search.md @@ -1,9 +1,10 @@ # Search logs - Docs -Filter logs from the filter bar at the top of the [logs page](https://us.posthog.com/logs). Pick a field, choose an operator, and enter a value. Add as many filters as you need — they're combined with AND. +Filter logs from the filter bar at the top of the [logs page](https://app.posthog.com/logs). Pick a field, choose an operator, and enter a value. Add as many filters as you need — they're combined with AND. -There are three kinds of fields you can filter on: +There are four kinds of fields you can filter on: +- **Logs** – top-level log properties: `severity_level`, `trace_id`, and `span_id` - **Message** – full-text search over the log body - **Resource attributes** – describe where the log came from, like `service.name`, `host.name`, or `k8s.container.name` - **Attributes** – custom key-value context attached to individual log events, like `user_id`, `endpoint`, or `status_code` @@ -20,6 +21,16 @@ To filter: For example, filter `service.name` equals `checkout-api` to scope to one service, then add `status_code` equals `500` to narrow to failed requests. +## Filter by severity, trace ID, and span ID + +The **Logs** group in the filter picker exposes three top-level fields. All three only support equals and not-equals operators. + +- **severity\_level** – filter by log severity using a dropdown. Available values: `trace`, `debug`, `info`, `warn`, `error`, `fatal`. +- **trace\_id** – filter logs by their OpenTelemetry trace correlation ID. Accepts hex or base64 format trace IDs +- **span\_id** – filter logs by their OpenTelemetry span ID. Accepts hex or base64, same as `trace_id`. + +For example, copy a `trace_id` from a trace URL and paste it into the filter to see every log emitted during that trace. + ## Full-text search on Message To search log bodies, pick the **Message** field from the filter bar. Message supports three operators, each with a negated variant for exclusion: diff --git a/skills/instrument-product-analytics/SKILL.md b/skills/instrument-product-analytics/SKILL.md index bdc82dd..083a2f0 100644 --- a/skills/instrument-product-analytics/SKILL.md +++ b/skills/instrument-product-analytics/SKILL.md @@ -12,7 +12,7 @@ metadata: Use this skill to add product analytics events (capture calls) that track meaningful user actions in new or changed code. Use it after implementing features or reviewing PRs to ensure key user behaviors are captured. If PostHog is not yet installed, this skill also covers initial SDK setup. Supports any framework or language. -Supported frameworks: Next.js, React Router, Nuxt, Vue, TanStack Start, SvelteKit, Astro, Angular, Django, Flask, FastAPI, Laravel, Ruby on Rails, Android, iOS, React Native, Expo, and more. +Supported frameworks: Next.js, React Router, Nuxt, Vue, TanStack Start, SvelteKit, Astro, Angular, Django, Flask, FastAPI, Laravel, PHP, Ruby on Rails, Android, iOS, React Native, Expo, and more. ## Instructions @@ -91,6 +91,7 @@ STEP 10: Verify and clean up. - `references/EXAMPLE-fastapi.md` - fastapi example project code - `references/EXAMPLE-python.md` - python example project code - `references/EXAMPLE-laravel.md` - laravel example project code +- `references/EXAMPLE-php.md` - php example project code - `references/EXAMPLE-ruby-on-rails.md` - ruby-on-rails example project code - `references/EXAMPLE-ruby.md` - ruby example project code - `references/EXAMPLE-android.md` - android example project code @@ -114,6 +115,7 @@ STEP 10: Verify and clean up. - `references/python.md` - Python - docs - `references/posthog-python.md` - PostHog python SDK - `references/laravel.md` - Laravel - docs +- `references/php.md` - Php - docs - `references/ruby-on-rails.md` - Ruby on rails - docs - `references/ruby.md` - Ruby - docs - `references/android.md` - Android - docs diff --git a/skills/instrument-product-analytics/references/EXAMPLE-php.md b/skills/instrument-product-analytics/references/EXAMPLE-php.md new file mode 100644 index 0000000..d530bd4 --- /dev/null +++ b/skills/instrument-product-analytics/references/EXAMPLE-php.md @@ -0,0 +1,527 @@ +# PostHog php Example Project + +Repository: https://github.com/PostHog/context-mill +Path: basics/php + +--- + +## README.md + +# PostHog PHP Example - CLI Todo App + +A simple command-line todo application built with plain PHP (no framework) demonstrating PostHog integration for CLIs, scripts, data pipelines, and non-web PHP applications. + +## Purpose + +This example serves as: +- **Verification** that the context-mill wizard works for plain PHP projects +- **Reference implementation** of PostHog best practices for non-framework PHP code +- **Working example** you can run and modify + +## Features Demonstrated + +- **SDK initialization** - Uses `PostHog::init(...)` once with environment-based configuration +- **Event tracking** - Captures user actions with `distinctId` and properties +- **User identification** - Associates properties with users via `PostHog::identify(...)` +- **Error tracking** - Enables automatic PHP error tracking and manually captures handled exceptions +- **Proper flushing** - Calls `PostHog::flush()` before CLI exit + +## Quick Start + +### 1. Install Dependencies + +```bash +composer install +``` + +### 2. Configure PostHog + +```bash +# Copy environment template +cp .env.example .env + +# Edit .env and add your PostHog API key +# POSTHOG_API_KEY=phc_your_api_key_here +# POSTHOG_HOST=https://us.i.posthog.com +``` + +### 3. Run the App + +```bash +# Add a todo +php todo.php add "Buy groceries" + +# List all todos +php todo.php list + +# Complete a todo +php todo.php complete 1 + +# Delete a todo +php todo.php delete 1 + +# Show statistics +php todo.php stats +``` + +## What Gets Tracked + +The app tracks these events in PostHog: + +| Event | Properties | Purpose | +|-------|-----------|---------| +| `todo_added` | `todo_id`, `todo_length`, `total_todos` | When user adds a new todo | +| `todos_viewed` | `total_todos`, `completed_todos` | When user lists todos | +| `todo_completed` | `todo_id`, `time_to_complete_hours` | When user completes a todo | +| `todo_deleted` | `todo_id`, `was_completed` | When user deletes a todo | +| `stats_viewed` | `total_todos`, `completed_todos`, `pending_todos` | When user views stats | +| `$exception` | exception details and command context | When handled errors occur | + +## Code Structure + +``` +basics/php/ +├── todo.php # Main CLI application +├── composer.json # PHP dependencies +├── .env.example # Environment variable template +├── .gitignore # Git ignore rules +└── README.md # This file +``` + +## Key Implementation Patterns + +### 1. Initialize Once + +```php +PostHog::init($apiKey, [ + 'host' => $host, + 'error_tracking' => [ + 'enabled' => true, + ], +]); +``` + +### 2. Event Tracking Pattern + +```php +PostHog::capture([ + 'distinctId' => 'user_123', + 'event' => 'event_name', + 'properties' => ['key' => 'value'], +]); +``` + +### 3. Identifying Users + +```php +PostHog::identify([ + 'distinctId' => 'user_123', + 'properties' => ['app_language' => 'php'], +]); +``` + +### 4. Exception Tracking + +```php +try { + riskyOperation(); +} catch (Throwable $e) { + PostHog::captureException($e, 'user_123', [ + 'command' => 'example_command', + ]); +} +``` + +### 5. Flush Before CLI Exit + +```php +PostHog::flush(); +``` + +## Running Without PostHog + +The app works fine without PostHog configured - it simply won't track analytics. You'll see a warning message but the app continues to function normally. + +## Next Steps + +- Modify `todo.php` to experiment with PostHog tracking +- Add new commands and track their usage +- Explore feature flags: `PostHog::isFeatureEnabled('flag-name', 'user_id')` +- Check your PostHog dashboard to see tracked events + +## Learn More + +- [PostHog PHP SDK Documentation](https://posthog.com/docs/libraries/php) +- [PostHog PHP Error Tracking](https://posthog.com/docs/error-tracking/installation/php) +- [PostHog Product Analytics PHP installation](https://posthog.com/docs/product-analytics/installation/php) + +--- + +## .env.example + +```example +# PostHog configuration +POSTHOG_API_KEY=phc_your_api_key_here +POSTHOG_HOST=https://us.i.posthog.com + +``` + +--- + +## todo.php + +```php + getenv('POSTHOG_HOST') ?: 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + 'context_provider' => static function (array $payload): array { + return [ + 'distinctId' => getUserId(), + 'properties' => [ + 'app' => 'php_todo_cli', + 'runtime' => PHP_VERSION, + '$exception_source' => $payload['source'] ?? null, + ], + ]; + }, + ], + ]); + + return true; +} + +function getUserId(): string +{ + $path = dataFilePath(); + if (file_exists($path)) { + $data = json_decode((string) file_get_contents($path), true); + if (is_array($data) && isset($data['user_id'])) { + return (string) $data['user_id']; + } + } + + return 'user_' . bin2hex(random_bytes(4)); +} + +function loadTodos(): array +{ + $path = dataFilePath(); + if (!file_exists($path)) { + return ['user_id' => getUserId(), 'todos' => []]; + } + + $data = json_decode((string) file_get_contents($path), true); + if (!is_array($data)) { + return ['user_id' => getUserId(), 'todos' => []]; + } + + $data['todos'] = $data['todos'] ?? []; + $data['user_id'] = $data['user_id'] ?? getUserId(); + return $data; +} + +function saveTodos(array $data): void +{ + file_put_contents(dataFilePath(), json_encode($data, JSON_PRETTY_PRINT) . PHP_EOL); +} + +function identifyUser(bool $posthogEnabled): void +{ + if (!$posthogEnabled) { + return; + } + + PostHog::identify([ + 'distinctId' => getUserId(), + 'properties' => [ + 'app_language' => 'php', + 'app_type' => 'cli', + ], + ]); +} + +function trackEvent(bool $posthogEnabled, string $eventName, array $properties = []): void +{ + if (!$posthogEnabled) { + return; + } + + PostHog::capture([ + 'distinctId' => getUserId(), + 'event' => $eventName, + 'properties' => $properties, + ]); +} + +function cmdAdd(string $text, bool $posthogEnabled): void +{ + $data = loadTodos(); + + $todo = [ + 'id' => count($data['todos']) + 1, + 'text' => $text, + 'completed' => false, + 'created_at' => date(DATE_ATOM), + ]; + + $data['todos'][] = $todo; + saveTodos($data); + + echo "Added todo #{$todo['id']}: {$todo['text']}\n"; + + trackEvent($posthogEnabled, 'todo_added', [ + 'todo_id' => $todo['id'], + 'todo_length' => strlen($todo['text']), + 'total_todos' => count($data['todos']), + ]); +} + +function cmdList(bool $posthogEnabled): void +{ + $data = loadTodos(); + + if (count($data['todos']) === 0) { + echo "No todos yet! Add one with: php todo.php add 'Your task'\n"; + return; + } + + echo "\nYour Todos (" . count($data['todos']) . " total):\n\n"; + + foreach ($data['todos'] as $todo) { + $status = $todo['completed'] ? 'X' : ' '; + echo " [{$status}] #{$todo['id']}: {$todo['text']}\n"; + } + + echo "\n"; + + trackEvent($posthogEnabled, 'todos_viewed', [ + 'total_todos' => count($data['todos']), + 'completed_todos' => count(array_filter($data['todos'], static fn (array $todo): bool => (bool) $todo['completed'])), + ]); +} + +function cmdComplete(int $id, bool $posthogEnabled): void +{ + $data = loadTodos(); + + foreach ($data['todos'] as &$todo) { + if ((int) $todo['id'] !== $id) { + continue; + } + + if ($todo['completed']) { + echo "Todo #{$id} is already completed\n"; + return; + } + + $todo['completed'] = true; + $todo['completed_at'] = date(DATE_ATOM); + saveTodos($data); + + echo "Completed todo #{$todo['id']}: {$todo['text']}\n"; + + $timeToComplete = (strtotime($todo['completed_at']) - strtotime($todo['created_at'])) / 3600; + trackEvent($posthogEnabled, 'todo_completed', [ + 'todo_id' => $todo['id'], + 'time_to_complete_hours' => $timeToComplete, + ]); + return; + } + + echo "ERROR: Todo #{$id} not found\n"; +} + +function cmdDelete(int $id, bool $posthogEnabled): void +{ + $data = loadTodos(); + + foreach ($data['todos'] as $index => $todo) { + if ((int) $todo['id'] !== $id) { + continue; + } + + unset($data['todos'][$index]); + $data['todos'] = array_values($data['todos']); + saveTodos($data); + + echo "Deleted todo #{$id}\n"; + + trackEvent($posthogEnabled, 'todo_deleted', [ + 'todo_id' => $todo['id'], + 'was_completed' => $todo['completed'], + ]); + return; + } + + echo "ERROR: Todo #{$id} not found\n"; +} + +function cmdStats(bool $posthogEnabled): void +{ + $data = loadTodos(); + + $total = count($data['todos']); + $completed = count(array_filter($data['todos'], static fn (array $todo): bool => (bool) $todo['completed'])); + $pending = $total - $completed; + $rate = $total > 0 ? number_format($completed / $total * 100, 1) : '0.0'; + + echo "\nStats:\n\n"; + echo " Total todos: {$total}\n"; + echo " Completed: {$completed}\n"; + echo " Pending: {$pending}\n"; + echo " Completion rate: {$rate}%\n\n"; + + trackEvent($posthogEnabled, 'stats_viewed', [ + 'total_todos' => $total, + 'completed_todos' => $completed, + 'pending_todos' => $pending, + ]); +} + +function printUsage(): void +{ + echo << Mark todo as completed + php todo.php delete Delete a todo + php todo.php stats Show statistics +USAGE; +} + +$posthogEnabled = false; + +try { + $posthogEnabled = initializePostHog(); + identifyUser($posthogEnabled); + + $command = $argv[1] ?? null; + if (!$command) { + printUsage(); + exit(0); + } + + switch ($command) { + case 'add': + $text = $argv[2] ?? null; + if (!$text) { + echo "ERROR: Please provide todo text\n"; + echo "Usage: php todo.php add \"Your task\"\n"; + exit(1); + } + cmdAdd($text, $posthogEnabled); + break; + + case 'list': + cmdList($posthogEnabled); + break; + + case 'complete': + $id = (int) ($argv[2] ?? 0); + if ($id <= 0) { + echo "ERROR: Please provide a valid todo ID\n"; + echo "Usage: php todo.php complete \n"; + exit(1); + } + cmdComplete($id, $posthogEnabled); + break; + + case 'delete': + $id = (int) ($argv[2] ?? 0); + if ($id <= 0) { + echo "ERROR: Please provide a valid todo ID\n"; + echo "Usage: php todo.php delete \n"; + exit(1); + } + cmdDelete($id, $posthogEnabled); + break; + + case 'stats': + cmdStats($posthogEnabled); + break; + + default: + echo "ERROR: Unknown command '{$command}'\n"; + printUsage(); + exit(1); + } +} catch (Throwable $e) { + echo "ERROR: {$e->getMessage()}\n"; + + if ($posthogEnabled) { + PostHog::captureException($e, getUserId(), [ + 'command' => $argv[1] ?? null, + 'app' => 'php_todo_cli', + ]); + } + + exit(1); +} finally { + if ($posthogEnabled) { + PostHog::flush(); + } +} + +``` + +--- + diff --git a/skills/instrument-product-analytics/references/django.md b/skills/instrument-product-analytics/references/django.md index dc8a1af..af5d8ba 100644 --- a/skills/instrument-product-analytics/references/django.md +++ b/skills/instrument-product-analytics/references/django.md @@ -1,6 +1,6 @@ # Django - Docs -PostHog makes it easy to get data about traffic and usage of your Django app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. +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. This guide walks you through integrating PostHog into your Django app using the [Python SDK](/docs/libraries/python.md). @@ -18,7 +18,9 @@ Or, to integrate manually, continue with the rest of this guide. To start, run `pip install posthog` to install PostHog’s Python SDK. -Then, set the PostHog API key and host in your `AppConfig` in your `your_app/apps.py` so that's it's available everywhere: +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + +Then, configure PostHog in your app config so it's initialized when Django starts: your\_app/apps.py @@ -28,15 +30,13 @@ PostHog AI from django.apps import AppConfig import posthog class YourAppConfig(AppConfig): - name = "your_app_name" + name = 'your_app_name' def ready(self): posthog.api_key = '' posthog.host = 'https://us.i.posthog.com' ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). - -Next, if you haven't done so already, make sure you add your `AppConfig` to your `settings.py` under `INSTALLED_APPS`: +Next, if you haven't done so already, add your `AppConfig` to `INSTALLED_APPS` in `settings.py`: settings.py @@ -44,12 +44,14 @@ PostHog AI ```python INSTALLED_APPS = [ - # other apps - 'your_app_name.apps.MyAppConfig', # Add your app config + # ... other apps + 'your_app_name.apps.YourAppConfig', ] ``` -Lastly, to access PostHog in any file, simply `import posthog` and call the method you'd like. For example, to capture an event: +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). + +To capture events from any file, import `posthog` and call the method you need. For example: Python @@ -57,12 +59,18 @@ PostHog AI ```python import posthog +from posthog import identify_context def some_request(request): with posthog.new_context(): - posthog.identify_context(request.user.id) + # Django includes request.user for anonymous visitors too. Only identify + # the context when the visitor is logged in. + if request.user.is_authenticated: + identify_context(str(request.user.pk)) posthog.capture('event_name') ``` +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. + ## Identifying users > **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). @@ -71,11 +79,11 @@ def some_request(request): ## Django contexts middleware -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 request headers and tags all events captured during the request with relevant metadata. +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 tags all events captured during that request with relevant metadata. ### Basic setup -Add the middleware to your Django settings: +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. Python @@ -89,14 +97,22 @@ MIDDLEWARE = [ ] ``` +The middleware uses the globally configured `posthog` client by default, so you don't need to create or pass it a separate client instance. + The middleware automatically extracts and uses: - **Session ID** from the `X-POSTHOG-SESSION-ID` header, if present -- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present +- **Distinct ID** from the `X-POSTHOG-DISTINCT-ID` header, if present, falling back to the authenticated Django user's `pk` (Django's primary-key alias, which works with custom user models) +- **User email** from the authenticated Django user's `email` as `email` - **Current URL** as `$current_url` - **Request method** as `$request_method` +- **Request path** as `$request_path` +- **Forwarded IP address** from `X-Forwarded-For` as `$ip` +- **User agent** from `User-Agent` as `$user_agent` + +The session and distinct ID headers are sanitized before use. Empty values are ignored, control characters are removed, values are trimmed, and values are capped at 1000 characters. -All events captured during the request (including exceptions) will include these properties and be associated with the extracted session and distinct ID. +All events captured during the request (including exceptions) include these properties and are associated with the extracted session and distinct ID. If you are using PostHog on your frontend, the JavaScript Web SDK will add the session and distinct ID headers automatically if you enable tracing headers. @@ -112,7 +128,9 @@ posthog.init('', { ### Exception capture -By default, the middleware captures exceptions and sends them to PostHog's error tracking. Disable this by setting: +By default, the middleware captures exceptions and sends them to PostHog's error tracking using the globally configured `posthog` client. This includes Django view exceptions that Django converts into error responses. + +Disable this by setting: Python @@ -137,7 +155,8 @@ def add_user_tags(request): # type: (HttpRequest) -> Dict[str, Any] tags = {} if hasattr(request, 'user') and request.user.is_authenticated: - tags['user_id'] = request.user.id + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) tags['email'] = request.user.email return tags POSTHOG_MW_EXTRA_TAGS = add_user_tags @@ -196,7 +215,8 @@ def add_request_context(request): tags = {} if hasattr(request, 'user') and request.user.is_authenticated: tags['user_type'] = 'authenticated' - tags['user_id'] = str(request.user.id) + # Use pk instead of id so this works with custom User primary keys. + tags['user_id'] = str(request.user.pk) else: tags['user_type'] = 'anonymous' # Add request info @@ -217,7 +237,9 @@ POSTHOG_MW_TAG_MAP = clean_tags POSTHOG_MW_CAPTURE_EXCEPTIONS = True ``` -All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers. +All events captured within the request context automatically include the configured tags and are associated with the session and user identified from the request headers or Django authentication. + +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. ## Next steps diff --git a/skills/instrument-product-analytics/references/flask.md b/skills/instrument-product-analytics/references/flask.md index f631b4b..e8ec7bf 100644 --- a/skills/instrument-product-analytics/references/flask.md +++ b/skills/instrument-product-analytics/references/flask.md @@ -1,6 +1,6 @@ # Flask - Docs -PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. +PostHog makes it easy to get data about traffic and usage of your Flask app. Integrating PostHog enables analytics, custom events capture, feature flags, error tracking, and more. This guide walks you through integrating PostHog into your Flask app using the [Python SDK](/docs/libraries/python.md). @@ -8,6 +8,8 @@ This guide walks you through integrating PostHog into your Flask app using the [ To start, run `pip install posthog` to install PostHog’s Python SDK. +> **Note:** Version `7.x` of the PostHog Python SDK requires Python 3.10 or higher. + Then, initialize PostHog where you'd like to use it. For example, here's how to capture an event in a simple route: app.py @@ -15,23 +17,23 @@ app.py PostHog AI ```python -package main -from flask import Flask, render_template, request, redirect, session, url_for +from flask import Flask from posthog import Posthog +app = Flask(__name__) posthog = Posthog( - '', - host='https://us.i.posthog.com' + '', + host='https://us.i.posthog.com', ) @app.route('/api/dashboard', methods=['POST']) def api_dashboard(): posthog.capture( - 'dashboard_api_called' + 'dashboard_api_called', distinct_id='distinct_id_of_your_user', ) return '', 204 ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). +You can find your project token and instance address in [your project settings](https://app.posthog.com/project/settings). ## Identifying users @@ -39,6 +41,35 @@ You can find your project token and instance address in [your project settings]( > > See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. +## Request contexts + +Use [contexts](/docs/libraries/python.md#contexts) to share identity, session IDs, and tags across multiple captures during a request: + +Python + +PostHog AI + +```python +from flask import request, session +from posthog import identify_context, set_context_session, tag +@app.route('/api/dashboard', methods=['POST']) +def api_dashboard(): + with posthog.new_context(): + distinct_id = request.headers.get('X-POSTHOG-DISTINCT-ID') or session.get('user_id') + if distinct_id: + identify_context(str(distinct_id)) + session_id = request.headers.get('X-POSTHOG-SESSION-ID') + if session_id: + set_context_session(session_id) + tag('$current_url', request.url) + tag('$request_method', request.method) + tag('$request_path', request.path) + posthog.capture('dashboard_api_called') + return '', 204 +``` + +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. + ## Error tracking Flask has built-in error handlers. This means PostHog’s default exception autocapture won’t work and we need to manually capture errors instead using `capture_exception()`: @@ -50,6 +81,7 @@ PostHog AI ```python from flask import Flask, jsonify from posthog import Posthog +app = Flask(__name__) posthog = Posthog('', host='https://us.i.posthog.com') @app.errorhandler(Exception) def handle_exception(e): diff --git a/skills/instrument-product-analytics/references/laravel.md b/skills/instrument-product-analytics/references/laravel.md index 5038330..022f900 100644 --- a/skills/instrument-product-analytics/references/laravel.md +++ b/skills/instrument-product-analytics/references/laravel.md @@ -1,14 +1,34 @@ # Laravel - Docs -PostHog makes it easy to get data about traffic and usage of your Laravel app. Integrating PostHog enables analytics, custom events capture, feature flags, and more. - -This guide walks you through integrating PostHog into your Laravel app using the [PHP SDK](/docs/libraries/php.md). +PostHog integrates with Laravel through the [PostHog PHP SDK](/docs/libraries/php.md). This page covers Laravel-specific setup. For SDK features such as event capture, identifying users, feature flags, group analytics, and configuration options, see the [PHP SDK docs](/docs/libraries/php.md). ## Installation -First, ensure [Composer](https://getcomposer.org/) is installed. Then run `composer require posthog/posthog-php` to install PostHog’s PHP SDK. +Install the PHP SDK as described in the [PHP installation guide](/docs/libraries/php.md#installation), then add your project token and host to `.env`: + +.env + +PostHog AI + +```bash +POSTHOG_API_KEY= +POSTHOG_HOST=https://us.i.posthog.com +``` + +Add PostHog to Laravel's services config: -Next, initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: +config/services.php + +PostHog AI + +```php +'posthog' => [ + 'api_key' => env('POSTHOG_API_KEY'), + 'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'), +], +``` + +Initialize PostHog in the `boot` method of `app/Providers/AppServiceProvider.php`: app/Providers/AppServiceProvider.php @@ -23,48 +43,103 @@ class AppServiceProvider extends ServiceProvider { public function boot(): void { + if (! config('services.posthog.api_key')) { + return; + } PostHog::init( - '', + config('services.posthog.api_key'), [ - 'host' => 'https://us.i.posthog.com' + 'host' => config('services.posthog.host'), ] ); } } ``` -You can find your project token and instance address in [your project settings](https://us.posthog.com/project/settings). +## Request context middleware -## Usage +Client SDKs such as [PostHog JS](/docs/libraries/js.md) can send tracing headers to your Laravel backend. The PHP SDK can read `X-PostHog-Distinct-Id` and `X-PostHog-Session-Id` headers and apply them to events captured during the request. Add middleware like this: -To access your PostHog client anywhere in your app, import `use PostHog\PostHog;` and call `PostHog::method_name`. For example, below is how to capture an event in a simple route: - -routes/web.php +app/Http/Middleware/PostHogRequestContext.php PostHog AI ```php 'distinct_id_of_your_user', - 'event' => 'route_called' - ]); - return view('welcome'); -}); +use Symfony\Component\HttpFoundation\Response; +final class PostHogRequestContext +{ + public function handle(Request $request, Closure $next): Response + { + if (! config('services.posthog.api_key')) { + return $next($request); + } + $context = PostHog::contextFromHeaders($request->headers->all()); + $context['properties'] = array_merge( + $context['properties'] ?? [], + array_filter([ + '$current_url' => $request->fullUrl(), + '$request_method' => $request->method(), + '$request_path' => $request->getPathInfo(), + '$user_agent' => $request->userAgent(), + '$ip' => $request->ip(), + ], static fn ($value): bool => $value !== null && $value !== '') + ); + return PostHog::withContext( + $context, + static fn (): Response => $next($request), + ['fresh' => true] + ); + } +} ``` -## Next steps +Register this middleware using your Laravel version's normal middleware registration. + +## Error tracking in Laravel + +The PHP SDK supports [error tracking](/docs/libraries/php.md#error-tracking), but Laravel handles most request exceptions before they become uncaught PHP exceptions. Capture Laravel-reported exceptions explicitly. + +In Laravel 11 and later, add a report callback in `bootstrap/app.php`: + +bootstrap/app.php + +PostHog AI + +```php +use Illuminate\Foundation\Configuration\Exceptions; +use PostHog\PostHog; +use Throwable; +->withExceptions(function (Exceptions $exceptions): void { + $exceptions->report(function (Throwable $e): void { + if (! config('services.posthog.api_key')) { + return; + } + PostHog::captureException( + $e, + auth()->id() !== null ? (string) auth()->id() : null, + [ + '$current_url' => request()->fullUrl(), + '$request_method' => request()->method(), + ] + ); + }); +}) +``` + +For older Laravel versions, call `PostHog::captureException()` from your exception handler's `report` method. -For any technical questions for how to integrate specific PostHog features into Laravel (such as analytics, feature flags, A/B testing, etc.), have a look at our [PHP SDK docs](/docs/libraries/php.md). +## Long-running processes -Alternatively, the following tutorials can help you get started: +In normal PHP request lifecycles, queued events flush when the client is destroyed. In long-running Laravel processes such as queue workers, Horizon, or Octane, call `PostHog::flush()` after capturing important events or at the end of a job/request. + +## Next steps -- [How to set up analytics in Laravel](/tutorials/laravel-analytics.md) -- [How to set up feature flags in Laravel](/tutorials/laravel-feature-flags.md) -- [How to set up A/B tests in Laravel](/tutorials/laravel-ab-tests.md) +See the [PHP SDK docs](/docs/libraries/php.md) for usage examples and the full API reference. ### Community questions diff --git a/skills/instrument-product-analytics/references/php.md b/skills/instrument-product-analytics/references/php.md new file mode 100644 index 0000000..1c2e1fe --- /dev/null +++ b/skills/instrument-product-analytics/references/php.md @@ -0,0 +1,629 @@ +# PHP - Docs + +This is an optional library you can install if you're working with PHP. It uses an internal queue to batch requests, flushes at the end of the request, and optionally does so in an async manner. + +## Installation + +Install the package with Composer: + +Terminal + +PostHog AI + +```bash +composer require posthog/posthog-php +``` + +In your app, set your project token before making any calls. + +PHP + +PostHog AI + +```php +PostHog\PostHog::init("", + ['host' => 'https://us.i.posthog.com'] +); +``` + +> **Note:** As a rule of thumb, we do not recommend having API keys or tokens in plaintext. Setting them as environment variables is best. The PHP SDK reads `POSTHOG_API_KEY` and `POSTHOG_HOST` when you omit the project token or host. + +You can find your project token and instance address in the [project settings](https://app.posthog.com/project/settings) page in PostHog. + +## Identifying users + +> **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). +> +> See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. + +## Capturing events + +You can send custom events using `capture`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => 'user_signed_up' +]); +``` + +> **Tip:** We recommend using a `[object] [verb]` format for your event names, where `[object]` is the entity that the behavior relates to, and `[verb]` is the behavior itself. For example, `project created`, `user signed up`, or `invite sent`. + +### Setting event properties + +Optionally, you can include additional information with the event by including a [properties](/docs/data/events.md#event-properties) object: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => 'user_signed_up', + 'properties' => [ + 'login_type' => 'email', + 'is_free_trial' => 'true' + ] +]); +``` + +### Sending page views + +If you're aiming for a backend-only implementation of PostHog and won't be capturing events from your frontend, you can send `pageviews` from your backend like so: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_the_user', + 'event' => '$pageview', + 'properties' => [ + '$current_url' => 'https://example.com' + ] +]); +``` + +## Person profiles and properties + +The PHP SDK captures identified events by default. These create [person profiles](/docs/data/persons.md). To set [person properties](/docs/data/user-properties.md), call `identify` with the user's distinct ID and properties: + +PHP + +PostHog AI + +```php +PostHog::identify([ + 'distinctId' => 'distinct_id', + 'properties' => [ + 'email' => 'max@example.com', + 'name' => 'Max Hedgehog', + ], +]); +``` + +You can also include person properties when capturing an event: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id', + 'event' => 'event_name', + 'properties' => [ + '$set' => [ + 'name' => 'Max Hedgehog' + ], + '$set_once' => [ + 'initial_url' => '/blog' + ] + ] +]); +``` + +For more details on the difference between `$set` and `$set_once`, see our [person properties docs](/docs/data/user-properties.md#what-is-the-difference-between-set-and-set_once). + +To capture [anonymous events](/docs/data/anonymous-vs-identified-events.md) without person profiles, set the event's `$process_person_profile` property to `false`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id', + 'event' => 'event_name', + 'properties' => [ + '$process_person_profile' => false + ] +]); +``` + +## Alias + +Sometimes, you want to assign multiple distinct IDs to a single user. This is helpful when your primary distinct ID is inaccessible. For example, if a distinct ID used on the frontend is not available in your backend. + +In this case, you can use `alias` to assign another distinct ID to the same user. + +PHP + +PostHog AI + +```php +PostHog::alias([ + 'distinctId' => 'distinct_id', + 'alias' => 'alias_id' +]); +``` + +We strongly recommend reading our docs on [alias](/docs/data/identify.md#alias-assigning-multiple-distinct-ids-to-the-same-user) to best understand how to correctly use this method. + +## Feature flags + +PostHog's [feature flags](/docs/feature-flags.md) enable you to safely deploy and roll back new features as well as target specific users and groups with them. + +There are two steps to implement feature flags in PHP: + +### Step 1: Evaluate flags once + +Call `PostHog::evaluateFlags()` once for the user, then read values from the returned snapshot. + +#### Boolean feature flags + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user + // Optional: fetch the payload + $matchedFlagPayload = $flags->getFlagPayload('flag-key'); +} +``` + +#### Multivariate feature flags + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +$enabledVariant = $flags->getFlag('flag-key'); +if ($enabledVariant === 'variant-key') { // replace 'variant-key' with the key of your variant + // Do something differently for this user + // Optional: fetch the payload + $matchedFlagPayload = $flags->getFlagPayload('flag-key'); +} +``` + +`$flags->getFlag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `null` when the flag wasn't returned by the evaluation. + +You can also call `$flags->getKeys()` to list the evaluated flag keys, or `$flags->getEventProperties()` to get the `$feature/` and `$active_feature_flags` properties that would be attached to a captured event. + +> **Note:** `PostHog::isFeatureEnabled()`, `PostHog::getFeatureFlag()`, `PostHog::getFeatureFlagPayload()`, and `capture(['send_feature_flags' => true])` still work during the migration period, but they're deprecated. Prefer `evaluateFlags()` for new code. + +### Step 2: Include feature flag information when capturing events + +If you want use your feature flag to breakdown or filter events in your [insights](/docs/product-analytics/insights.md), you'll need to include feature flag information in those events. This ensures that the feature flag value is attributed correctly to the event. + +> **Note:** This step is only required for events captured using our server-side SDKs or [API](/docs/api.md). + +There are two methods you can use to include feature flag information in your events: + +#### Method 1: Pass the evaluated flags snapshot to `capture()` + +Pass the same `flags` object that you used for branching. This attaches the exact flag values from that evaluation and doesn't make another `/flags` request. + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('distinct_id_of_your_user'); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user +} +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags, +]); +``` + +By default, this attaches every flag in the snapshot using `$feature/` properties and `$active_feature_flags`. + +To reduce event property bloat, pass a filtered snapshot: + +PHP + +PostHog AI + +```php +// Attach only flags accessed with isEnabled() or getFlag() before this call +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags->onlyAccessed(), +]); +// Attach only specific flags +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'flags' => $flags->only(['checkout-flow', 'new-dashboard']), +]); +``` + +`onlyAccessed()` is order-dependent. If you call it before accessing any flags with `isEnabled()` or `getFlag()`, no feature flag properties are attached. + +#### Method 2: Include the `$feature/feature_flag_name` property manually + +In the event properties, include `$feature/feature_flag_name: variant_key`: + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'distinct_id_of_your_user', + 'event' => 'event_name', + 'properties' => [ + // Replace feature-flag-key with your flag key and 'variant-key' with the key of your variant + '$feature/feature-flag-key' => 'variant-key', + ], +]); +``` + +### Evaluating only specific flags + +By default, `evaluateFlags()` evaluates every flag for the user. If you only need a few flags, pass `flagKeys` to request only those flags: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_your_user', + flagKeys: ['checkout-flow', 'new-dashboard'], +); +``` + +### Optional evaluation parameters + +`evaluateFlags()` also accepts optional parameters for local evaluation and GeoIP behavior: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_your_user', + groups: ['company' => 'company_id_in_your_db'], + personProperties: ['plan' => 'pro'], + groupProperties: ['company' => ['employees' => 11]], + onlyEvaluateLocally: false, // Defaults to false. Set to true to avoid a remote fallback. + disableGeoip: false, // Defaults to false. Set to true to disable GeoIP enrichment during remote evaluation. + flagKeys: ['checkout-flow', 'new-dashboard'], +); +``` + +### Sending `$feature_flag_called` events + +Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluateFlags()`, the SDK sends this event when you call `$flags->isEnabled()` or `$flags->getFlag()` for a flag. + +The SDK deduplicates these events per `(flag key, distinct_id)` in a local cache. If you reinitialize the PostHog client, the cache resets and `$feature_flag_called` events may be sent again. PostHog handles duplicates, so duplicate `$feature_flag_called` events don't affect your analytics. + +`$flags->getFlagPayload()` doesn't send `$feature_flag_called` events and doesn't count as an access for `onlyAccessed()`. + +### Advanced: Overriding server properties + +Sometimes, you may want to evaluate feature flags using [person properties](/docs/product-analytics/person-properties.md), [groups](/docs/product-analytics/group-analytics.md), or group properties that haven't been ingested yet, or were set incorrectly earlier. + +You can provide properties to evaluate the flag with by using the `person properties`, `groups`, and `group properties` arguments. PostHog will then use these values to evaluate the flag, instead of any properties currently stored on your PostHog server. + +For example: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags( + distinctId: 'distinct_id_of_the_user', + groups: [ + 'your_group_type' => 'your_group_id', + 'another_group_type' => 'your_group_id', + ], + personProperties: ['property_name' => 'value'], + groupProperties: [ + 'your_group_type' => ['group_property_name' => 'value'], + 'another_group_type' => ['group_property_name' => 'value'], + ], +); +if ($flags->isEnabled('flag-key')) { + // Do something differently for this user +} +``` + +### Overriding GeoIP properties + +By default, a user's GeoIP properties are set using the IP address they use to capture events on the frontend. You may want to override the these properties when evaluating feature flags. A common reason to do this is when you're not using PostHog on your frontend, so the user has no GeoIP properties. + +You can override GeoIP properties by including them in the `person_properties` parameter when evaluating feature flags. This is useful when you're evaluating flags on your backend and want to use the client's location instead of your server's location. + +The following GeoIP properties can be overridden: + +- `$geoip_country_code` +- `$geoip_country_name` +- `$geoip_city_name` +- `$geoip_city_confidence` +- `$geoip_continent_code` +- `$geoip_continent_name` +- `$geoip_latitude` +- `$geoip_longitude` +- `$geoip_postal_code` +- `$geoip_subdivision_1_code` +- `$geoip_subdivision_1_name` +- `$geoip_subdivision_2_code` +- `$geoip_subdivision_2_name` +- `$geoip_subdivision_3_code` +- `$geoip_subdivision_3_name` +- `$geoip_time_zone` + +Simply include any of these properties in the `person_properties` parameter alongside your other person properties when calling feature flags. + +### Request timeout + +You can configure the `feature_flag_request_timeout_ms` parameter when initializing your PostHog client to set a flag request timeout. This helps prevent your code from being blocked if PostHog's servers are too slow to respond. By default, this is set to 3 seconds. + +PHP + +PostHog AI + +```php +PostHog::init("", + [ + 'host' => 'https://us.i.posthog.com', + 'feature_flag_request_timeout_ms' => 3000, // Time in milliseconds. Defaults to 3000 (3 seconds). + ] +); +``` + +### Local Evaluation + +Evaluating feature flags requires making a request to PostHog for each flag. However, you can improve performance by evaluating flags locally. Instead of making a request for each flag, PostHog will periodically request and store feature flag definitions locally, enabling you to evaluate flags without making additional requests. + +It is best practice to use local evaluation flags when possible, since this enables you to resolve flags faster and with fewer API calls. + +To load feature flag definitions for local evaluation, initialize the SDK with your feature flags secure API key as `personalAPIKey`: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + ['host' => 'https://us.i.posthog.com'], + personalAPIKey: 'your feature flags secure API key' +); +``` + +For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). + +### Experiments (A/B tests) + +Since [experiments](/docs/experiments/start-here.md) use feature flags, the code for running an experiment is very similar to the feature flags code: + +PHP + +PostHog AI + +```php +$flags = PostHog::evaluateFlags('user_distinct_id'); +$variant = $flags->getFlag('experiment-feature-flag-key'); +if ($variant === 'variant-name') { + // Do something differently for this user +} +``` + +It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags.md). + +### Group analytics + +Group analytics allows you to associate an event with a group (e.g. teams, organizations, etc.). This feature requires version `2.1.0` or above of the PHP SDK. Read the [group analytics guide](/docs/product-analytics/group-analytics.md) for more information. + +> **Note:** This is a paid feature and is not available on the open-source or free cloud plan. Learn more on the [pricing page](/pricing.md). + +To create a group or update its properties, use `groupIdentify`: + +PHP + +PostHog AI + +```php +PostHog::groupIdentify([ + 'groupType' => 'company', + 'groupKey' => 'company_id_in_your_db', + 'properties' => [ + 'name' => 'Awesome Inc.', + 'employees' => 11, + ], + // Optional distinct ID to associate this event with an existing person. + // Requires posthog-php 4.4.0 or later. + 'distinctId' => 'user_distinct_id' +]); +``` + +`name` is a special property which is used in the PostHog UI for the name of the group. If you don't specify a `name` property, the group ID is used instead. + +If the optional `distinctId` parameter is not provided in the group identify call, it defaults to `${groupType}_${groupKey}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior results in each group appearing as a separate person in PostHog. To avoid this, use a consistent `distinctId`, such as `group_identifier`, or a real user distinct ID. + +Once a group is created, you can use the `capture` method and pass in the `groups` parameter to capture an event with group analytics. + +PHP + +PostHog AI + +```php +PostHog::capture([ + 'distinctId' => 'user_distinct_id', + 'event' => 'some_event', + 'groups' => ['company' => 'company_id_in_your_db'] +]); +``` + +## Request context + +Use request context to apply a distinct ID, session ID, and common properties to all captures inside a callback. This is useful when connecting frontend activity to backend events, session replay, and error tracking. + +PHP + +PostHog AI + +```php +PostHog::withContext([ + 'distinctId' => 'user_distinct_id', + 'sessionId' => 'session_id_from_frontend', + 'properties' => [ + '$current_url' => 'https://example.com/account', + ], +], function () { + PostHog::capture([ + 'event' => 'backend_event', + ]); +}); +``` + +You can extract PostHog context from frontend tracing headers with `contextFromHeaders()`: + +PHP + +PostHog AI + +```php +$context = PostHog::contextFromHeaders($_SERVER); +PostHog::withContext($context, function () { + PostHog::capture([ + 'event' => 'backend_event', + ]); +}); +``` + +Call `PostHog::getContext()` to read the currently active context. Pass `['fresh' => true]` as the third argument to `withContext()` if you don't want to inherit any existing context. + +## Error tracking + +The PHP SDK supports both manual exception capture and opt-in automatic error tracking. + +To automatically capture uncaught exceptions, PHP errors, and fatal shutdown errors, enable `error_tracking` when initializing the client: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'error_tracking' => [ + 'enabled' => true, + ], + ], +); +``` + +You can also call `PostHog::captureException()` directly for manual capture. When source files are readable at runtime, PostHog includes surrounding source lines for in-app stack frames automatically. + +For the full setup guide, including `context_provider`, excluded exceptions, and verification steps, see the [PHP error tracking installation docs](/docs/error-tracking/installation/php.md). + +## Config options + +When calling `PostHog::init`, there are various configuration options you can set apart from the host. Pass them into your client initialisation like so: + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'debug' => true, + 'ssl' => false, + // all options go here + ], +); +``` + +All possible options below: + +| Attribute | Description | +| --- | --- | +| hostType: StringDefault: us.i.posthog.com | URL of your PostHog instance. | +| sslType: BooleanDefault: true | Whether to use SSL for API requests or not. If host includes http:// or https://, the SDK infers this option unless you set it explicitly. | +| timeoutType: IntegerDefault: 10000 | Request timeout in milliseconds. | +| verify_batch_events_requestType: BooleanDefault: true | Whether to verify successful delivery of batch events (true, synchronous) or fire and forget (false, asynchronous) with the lib_curl consumer. | +| feature_flag_request_timeout_msType: IntegerDefault: 3000 | Request timeout for feature flags in milliseconds. | +| maximum_backoff_durationType: IntegerDefault: 10000 | Request retry backoff. Retries stop after this duration is hit. | +| consumerType: StringDefault: lib_curl | One of socket, file, lib_curl, and fork_curl. Determines what transport option to use for analytics capture. | +| debugType: BooleanDefault: false | Output debug logs or not. | +| max_queue_sizeType: IntegerDefault: 1000 | Maximum number of events to queue before rejecting new events. Applies to queued consumers. | +| batch_sizeType: IntegerDefault: 100 | Number of queued events to send in each batch. Applies to queued consumers. | +| compress_requestType: Boolean/StringDefault: false | Whether to gzip batch request payloads. | +| error_handlerType: CallableDefault: null | Callback invoked for SDK transport errors. | +| filenameType: StringDefault: sys_get_temp_dir() . '/posthog.log' | File path used when consumer is set to file. | +| error_trackingType: ArrayDefault: [] | Enables automatic error tracking. See the options below or the [PHP error tracking setup guide](/docs/error-tracking/installation/php.md). | + +### Error tracking options + +| Attribute | Description | +| --- | --- | +| enabledType: BooleanDefault: false | Enables automatic error tracking handlers. Manual captureException works regardless. | +| capture_errorsType: BooleanDefault: true | When enabled, captures PHP errors and fatal shutdown errors in addition to uncaught exceptions. | +| excluded_exceptionsType: Array of class stringsDefault: [] | Throwable classes to skip during automatic capture. | +| max_framesType: IntegerDefault: 20 | Maximum number of stack frames included in $exception_list. | +| context_providerType: Callable or nullDefault: null | Callback that returns distinctId and extra event properties for automatic captures. | + +## Debug mode + +PHP + +PostHog AI + +```php +PostHog::init( + '', + [ + 'host' => 'https://us.i.posthog.com', + 'debug' => true, + ], +); +``` + +## Thank you + +This library is largely based on the `analytics-php` package. + +### Community questions + +Ask a question + +### Was this page useful? + +HelpfulCould be better \ No newline at end of file diff --git a/skills/instrument-product-analytics/references/posthog-python.md b/skills/instrument-product-analytics/references/posthog-python.md index 50c8ae7..8c27cd2 100644 --- a/skills/instrument-product-analytics/references/posthog-python.md +++ b/skills/instrument-product-analytics/references/posthog-python.md @@ -1,6 +1,6 @@ # PostHog Python SDK -**SDK Version:** 7.14.2 +**SDK Version:** 7.15.4 Integrate PostHog into any python application. @@ -29,38 +29,38 @@ Initialize a new PostHog client instance. ### Parameters -- **`project_api_key?`** (`str`) - The project API key. -- **`host`** (`any`) - The host to use for the client. -- **`debug`** (`bool`) - Whether to enable debug mode. -- **`max_queue_size`** (`int`) -- **`send`** (`bool`) -- **`on_error`** (`any`) -- **`flush_at`** (`int`) -- **`flush_interval`** (`float`) -- **`gzip`** (`bool`) -- **`max_retries`** (`int`) -- **`sync_mode`** (`bool`) -- **`timeout`** (`int`) -- **`thread`** (`int`) -- **`poll_interval`** (`int`) -- **`personal_api_key`** (`any`) -- **`disabled`** (`bool`) -- **`disable_geoip`** (`bool`) -- **`historical_migration`** (`bool`) -- **`feature_flags_request_timeout_seconds`** (`int`) -- **`super_properties`** (`any`) -- **`enable_exception_autocapture`** (`bool`) -- **`log_captured_exceptions`** (`bool`) -- **`project_root`** (`any`) -- **`privacy_mode`** (`bool`) -- **`before_send`** (`any`) -- **`flag_fallback_cache_url`** (`any`) -- **`enable_local_evaluation`** (`bool`) -- **`flag_definition_cache_provider?`** (`FlagDefinitionCacheProvider`) -- **`capture_exception_code_variables`** (`bool`) -- **`code_variables_mask_patterns`** (`any`) -- **`code_variables_ignore_patterns`** (`any`) -- **`in_app_modules`** (`UnionType[list[str], any]`) +- **`project_api_key?`** (`str`) - PostHog project API key/token. +- **`host`** (`any`) - PostHog host. Defaults to the US ingestion endpoint when not set. App hosts such as ``https://us.posthog.com`` are mapped to the corresponding ingestion host. +- **`debug`** (`bool`) - Enable verbose SDK logging and re-raise errors from public API methods. +- **`max_queue_size`** (`int`) - Maximum number of events buffered before upload. +- **`send`** (`bool`) - If False, queueing succeeds but events are not sent. +- **`on_error`** (`any`) - Optional callback invoked by background consumers when an upload fails. +- **`flush_at`** (`int`) - Number of queued events that triggers a batch upload. +- **`flush_interval`** (`float`) - Maximum seconds a background consumer waits before flushing a partial batch. +- **`gzip`** (`bool`) - Whether to gzip event upload payloads. +- **`max_retries`** (`int`) - Number of upload retries for background consumers. +- **`sync_mode`** (`bool`) - If True, send each event synchronously instead of using background worker threads. +- **`timeout`** (`int`) - HTTP request timeout in seconds for event uploads. +- **`thread`** (`int`) - Number of background consumer threads. +- **`poll_interval`** (`int`) - Seconds between local feature flag definition refreshes. +- **`personal_api_key`** (`any`) - Personal API key used for local feature flag evaluation and remote config payloads. +- **`disabled`** (`bool`) - If True, disable captures and API requests. Useful in tests. +- **`disable_geoip`** (`bool`) - Whether to disable server-side GeoIP enrichment. Defaults to True. +- **`historical_migration`** (`bool`) - Mark events as historical migration imports. +- **`feature_flags_request_timeout_seconds`** (`int`) - Timeout in seconds for feature flag and remote config requests. +- **`super_properties`** (`any`) - Properties merged into every captured event. +- **`enable_exception_autocapture`** (`bool`) - Automatically capture uncaught exceptions. +- **`log_captured_exceptions`** (`bool`) - Also log exceptions captured by error tracking. +- **`project_root`** (`any`) - Root path used to determine in-app stack frames for captured exceptions. Defaults to the current working directory. +- **`privacy_mode`** (`bool`) - For AI observability, capture usage metadata without prompt inputs or outputs. +- **`before_send`** (`any`) - Optional callback that can modify or drop events before upload. Return ``None`` to drop an event. +- **`flag_fallback_cache_url`** (`any`) - Optional feature flag fallback cache URL, such as ``memory://local/?ttl=300&size=10000`` or a Redis URL. +- **`enable_local_evaluation`** (`bool`) - Whether to poll feature flag definitions for local evaluation when a personal API key is configured. +- **`flag_definition_cache_provider?`** (`FlagDefinitionCacheProvider`) - Optional external cache provider for sharing feature flag definitions across workers. +- **`capture_exception_code_variables`** (`bool`) - Capture local variable values on exception stack frames. +- **`code_variables_mask_patterns`** (`any`) - Variable-name patterns to mask when capturing code variables. +- **`code_variables_ignore_patterns`** (`any`) - Variable-name patterns to omit when capturing code variables. +- **`in_app_modules`** (`UnionType[list[str], any]`) - Module/package prefixes treated as in-app frames in captured exceptions. ### Returns @@ -341,6 +341,18 @@ if is_my_flag_enabled: --- +#### feature_flag_definitions() + +**Release Tag:** public + +Return feature flag definitions loaded for local evaluation. Returns: The currently loaded feature flag definitions, or ``None`` before local evaluation has loaded definitions. + +### Returns + +- `None` + +--- + #### get_all_flags() **Release Tag:** public @@ -575,6 +587,22 @@ decision = posthog.get_flags_decision('user123') --- +#### get_remote_config_payload() + +**Release Tag:** public + +Get the payload for a remote config feature flag. + +### Parameters + +- **`key?`** (`str`) - The remote config feature flag key. + +### Returns + +- `None` + +--- + #### load_feature_flags() **Release Tag:** public @@ -827,15 +855,8 @@ This will overwrite previous people property values. Generally operates similar ```python # Set person properties -from posthog import capture -capture( - 'distinct_id', - event='event_name', - properties={ - '$set': {'name': 'Max Hedgehog'}, - '$set_once': {'initial_url': '/blog'} - } -) +from posthog import set +set(distinct_id='distinct_id', properties={'name': 'Max Hedgehog'}) ``` --- @@ -862,15 +883,8 @@ This will not overwrite previous people property values, unlike `set`. Otherwise ```python # Set property once -from posthog import capture -capture( - 'distinct_id', - event='event_name', - properties={ - '$set': {'name': 'Max Hedgehog'}, - '$set_once': {'initial_url': '/blog'} - } -) +from posthog import set_once +set_once(distinct_id='distinct_id', properties={'initial_url': '/blog'}) ``` --- @@ -957,7 +971,7 @@ Capture exception is idempotent - if it is called twice with the same exception ### Parameters -- **`exception`** (`BaseException`) - The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` +- **`exception`** (`BaseException`) - The exception to capture. If not provided, the current exception is captured via `sys.exc_info()` **kwargs: Optional capture arguments including distinct_id, properties, timestamp, uuid, groups, flags, send_feature_flags, and disable_geoip. - **`kwargs?`** (`Unpack[OptionalCaptureArgs]`) ### Returns @@ -1032,7 +1046,7 @@ You can call `posthog.load_feature_flags()` before to make sure you're not doing - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags ### Returns @@ -1091,7 +1105,7 @@ Flags are key-value pairs where the key is the flag key and the value is the fla - **`group_properties`** (`any`) - Group properties - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags - **`flag_keys_to_evaluate`** (`any`) - Optional list of flag keys to evaluate (evaluates all if None) ### Returns @@ -1108,6 +1122,29 @@ get_all_flags('distinct_id_of_your_user') --- +#### get_all_flags_and_payloads() + +**Release Tag:** public + +Get all feature flag values and payloads for a user. + +### Parameters + +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. +- **`flag_keys_to_evaluate`** (`any`) - Optional list of flag keys to evaluate. Evaluates all flags when omitted. + +### Returns + +- `FlagsAndPayloads` + +--- + #### get_feature_flag() **Release Tag:** public @@ -1128,7 +1165,7 @@ Get feature flag variant for users. Used with experiments. - **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events - **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`device_id`** (`any`) +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags ### Returns @@ -1146,6 +1183,31 @@ if enabled_variant == 'variant-key': --- +#### get_feature_flag_payload() + +**Release Tag:** public + +Get the payload associated with a feature flag value. Deprecated for new code. Prefer ``evaluate_flags()`` and ``flags.get_flag_payload(key)`` so flag evaluation happens once per request. + +### Parameters + +- **`key?`** (`any`) - The feature flag key. +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`match_value`** (`any`) - Optional flag value to use when selecting a payload. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`send_feature_flag_events`** (`bool`) - Whether to send a $feature_flag_called event. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. + +### Returns + +- `Optional[str]` + +--- + #### load_feature_flags() **Release Tag:** public @@ -1230,19 +1292,19 @@ shutdown() **Release Tag:** public -Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: - enabled: Whether the flag is enabled - variant: The variant value if the flag has variants - payload: The payload associated with the flag (automatically deserialized from JSON) - key: The flag key - reason: Why the flag was enabled/disabled Example: ```python result = posthog.get_feature_flag_result('beta-feature', 'distinct_id') if result and result.enabled: # Use the variant and payload print(f"Variant: {result.variant}") print(f"Payload: {result.payload}") ``` +Get a FeatureFlagResult object which contains the flag result and payload. This method evaluates a feature flag and returns a FeatureFlagResult object containing: - enabled: Whether the flag is enabled - variant: The variant value if the flag has variants - payload: The payload associated with the flag (automatically deserialized from JSON) - key: The flag key - reason: Why the flag was enabled/disabled ### Parameters -- **`key?`** (`any`) -- **`distinct_id?`** (`any`) -- **`groups`** (`any`) -- **`person_properties`** (`any`) -- **`group_properties`** (`any`) -- **`only_evaluate_locally`** (`bool`) -- **`send_feature_flag_events`** (`bool`) -- **`disable_geoip`** (`any`) -- **`device_id`** (`any`) +- **`key?`** (`any`) - The feature flag key. +- **`distinct_id?`** (`any`) - The user's distinct ID. +- **`groups`** (`any`) - Mapping of group type to group key. +- **`person_properties`** (`any`) - Person properties to use for evaluation. +- **`group_properties`** (`any`) - Group properties keyed by group type. +- **`only_evaluate_locally`** (`bool`) - Whether to evaluate only locally. +- **`send_feature_flag_events`** (`bool`) - Whether to send a $feature_flag_called event. +- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. +- **`device_id`** (`any`) - Optional device ID override for experience-continuity flags. ### Returns @@ -1266,120 +1328,120 @@ Get the payload for a remote config feature flag. --- -#### set_capture_exception_code_variables_context() - -**Release Tag:** public +### Contexts methods -Set whether code variables are captured for the current context. +#### get_tags() -### Parameters +**Release Tag:** public -- **`enabled?`** (`bool`) +Get all tags from the current context. Returns: Dict of all tags in the current context ### Returns -- `None` +- `dict[str, Any]` --- -#### set_code_variables_ignore_patterns_context() +#### new_context() **Release Tag:** public -Variable names matching these patterns will be ignored completely when capturing code variables. +Create a new context scope that will be active for the duration of the with block. ### Parameters -- **`ignore_patterns?`** (`list`) +- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) +- **`capture_exceptions`** (`bool`) - Whether to capture exceptions raised within the context (default: True) +- **`client?`** (`Client`) - Optional Posthog client instance to use for this context (default: None) ### Returns - `None` +### Examples + +```python +from posthog import new_context, tag, capture +with new_context(): + tag("request_id", "123") + capture("event_name", properties={"property": "value"}) +``` + --- -#### set_code_variables_mask_patterns_context() +#### scoped() **Release Tag:** public -Variable names matching these patterns will be masked with *** when capturing code variables. +Decorator that creates a new context for the function. ### Parameters -- **`mask_patterns?`** (`list`) +- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) +- **`capture_exceptions`** (`bool`) - Whether to capture and track exceptions with posthog error tracking (default: True) ### Returns - `None` ---- +### Examples -### Contexts methods +```python +from posthog import scoped, tag, capture +@scoped() +def process_payment(payment_id): + tag("payment_id", payment_id) + capture("payment_started") +``` -#### get_tags() +--- + +#### set_capture_exception_code_variables_context() **Release Tag:** public -Get all tags from the current context. Returns: Dict of all tags in the current context +Override code-variable capture for exceptions in the current context. + +### Parameters + +- **`enabled?`** (`bool`) - Whether exceptions captured in this context should include local variable values from stack frames. ### Returns -- `dict[str, Any]` +- `None` --- -#### new_context() +#### set_code_variables_ignore_patterns_context() **Release Tag:** public -Create a new context scope that will be active for the duration of the with block. +Override code-variable ignore patterns for exceptions in the current context. ### Parameters -- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) -- **`capture_exceptions`** (`bool`) - Whether to capture exceptions raised within the context (default: True) -- **`client?`** (`Client`) - Optional Posthog client instance to use for this context (default: None) +- **`ignore_patterns?`** (`list`) - Variable-name patterns that should be omitted entirely when code variables are captured. ### Returns - `None` -### Examples - -```python -from posthog import new_context, tag, capture -with new_context(): - tag("request_id", "123") - capture("event_name", properties={"property": "value"}) -``` - --- -#### scoped() +#### set_code_variables_mask_patterns_context() **Release Tag:** public -Decorator that creates a new context for the function. +Override code-variable mask patterns for exceptions in the current context. ### Parameters -- **`fresh`** (`bool`) - Whether to start with a fresh context (default: False) -- **`capture_exceptions`** (`bool`) - Whether to capture and track exceptions with posthog error tracking (default: True) +- **`mask_patterns?`** (`list`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. ### Returns - `None` -### Examples - -```python -from posthog import scoped, tag, capture -@scoped() -def process_payment(payment_id): - tag("payment_id", payment_id) - capture("payment_started") -``` - --- #### set_context_device_id() @@ -1450,4 +1512,18 @@ from posthog import tag tag("user_id", "123") ``` +--- + +### Initialization methods + +#### setup() + +**Release Tag:** public + +Create or return the global PostHog client configured by module settings. Most applications should either instantiate ``Posthog`` directly or set ``posthog.api_key``/other module settings before calling top-level helpers. ``setup()`` is called automatically by global APIs such as ``capture()``. Returns: The global ``Client`` instance. Raises: ValueError: If ``api_key`` has not been configured. + +### Returns + +- `Client` + --- \ No newline at end of file diff --git a/skills/instrument-product-analytics/references/python.md b/skills/instrument-product-analytics/references/python.md index 166ab38..154b1cd 100644 --- a/skills/instrument-product-analytics/references/python.md +++ b/skills/instrument-product-analytics/references/python.md @@ -224,7 +224,7 @@ Python PostHog AI ```python -from posthog import new_context +from posthog import new_context, tag with new_context(fresh=True): tag("some-key", "value-2") # This event only has the property some-key="value-2" from the fresh context @@ -266,7 +266,7 @@ You can read more about identifying users in the [user identification documentat ### Contexts and sessions -Contexts can be associated with a session ID by calling `posthog.set_context_session`. Session IDs must be UUIDv7 strings. +Contexts can be associated with a session ID by calling `posthog.set_context_session`. When linking backend events to frontend sessions, use the session ID from the frontend SDK (PostHog session IDs are UUIDv7 strings). Python @@ -324,7 +324,7 @@ with new_context(capture_exceptions=False): ### Decorating functions -The SDK exposes a function decorator. It takes the same arguments as `new_context` and provides a handy way to mark a whole function as being in a new context. For example: +The SDK exposes a function decorator. It takes the same `fresh` and `capture_exceptions` arguments as `new_context` and provides a handy way to mark a whole function as being in a new context. For example: Python @@ -609,9 +609,9 @@ if variant == "variant-name": It's also possible to [run experiments without using feature flags](/docs/experiments/running-experiments-without-feature-flags.md). -## LLM analytics +## AI Observability -Our Python SDK includes a built-in LLM analytics feature. It enables you to capture LLM usage, performance, and more. Check out our [analytics docs](/docs/llm-analytics.md) for more details on setting it up. +Our Python SDK includes a built-in AI Observability feature. It enables you to capture LLM usage, performance, and more. Check out our [analytics docs](/docs/ai-observability.md) for more details on setting it up. ## Error tracking @@ -633,7 +633,7 @@ Python PostHog AI ```python -posthog.capture_exception(e, 'user_distinct_id', properties=additional_properties) +posthog.capture_exception(e, distinct_id='user_distinct_id', properties=additional_properties) ``` Contexts automatically capture exceptions thrown inside them, unless disable it by passing `capture_exceptions=False` to `new_context()`. diff --git a/skills/instrument-product-analytics/references/react-router-v6.md b/skills/instrument-product-analytics/references/react-router-v6.md index b651e1e..291000d 100644 --- a/skills/instrument-product-analytics/references/react-router-v6.md +++ b/skills/instrument-product-analytics/references/react-router-v6.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V6. If you're u Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V6. If you're u import posthog from 'posthog-js'; import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // Initialize PostHog - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const root = document.getElementById("root"); @@ -341,8 +341,8 @@ This guide walks you through setting up PostHog for React Router V6. If you're u PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-product-analytics/references/react-router-v7-data-mode.md b/skills/instrument-product-analytics/references/react-router-v7-data-mode.md index 17d61a0..fa07c5b 100644 --- a/skills/instrument-product-analytics/references/react-router-v7-data-mode.md +++ b/skills/instrument-product-analytics/references/react-router-v7-data-mode.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V7 in data mode Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V7 in data mode import Root, { RootErrorBoundary } from "./app/root"; import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const router = createBrowserRouter([...]); @@ -329,8 +329,8 @@ This guide walks you through setting up PostHog for React Router V7 in data mode PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md b/skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md index f88d210..e13d45a 100644 --- a/skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +++ b/skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md @@ -42,15 +42,15 @@ This guide walks you through setting up PostHog for React Router V7 in declarati Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -72,8 +72,8 @@ This guide walks you through setting up PostHog for React Router V7 in declarati import posthog from 'posthog-js'; import { PostHogErrorBoundary, PostHogProvider } from '@posthog/react' // Initialize PostHog - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', }); const root = document.getElementById("root"); @@ -341,8 +341,8 @@ This guide walks you through setting up PostHog for React Router V7 in declarati PostHog AI ```jsx - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); diff --git a/skills/instrument-product-analytics/references/react-router-v7-framework-mode.md b/skills/instrument-product-analytics/references/react-router-v7-framework-mode.md index 2d92274..a2ee8ea 100644 --- a/skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +++ b/skills/instrument-product-analytics/references/react-router-v7-framework-mode.md @@ -58,15 +58,15 @@ This guide walks you through setting up PostHog for React Router V7 in framework Required - Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, including `VITE_PUBLIC_` in their names ensures they are accessible in the frontend. + Add your environment variables to your `.env.local` file and to your hosting provider (e.g. Vercel, Netlify, AWS). You can find your project token and host in [your project settings](https://us.posthog.com/settings/project). If you're using Vite, prefixing variable names with `VITE_` ensures they are accessible in the frontend. .env.local PostHog AI ```shell - VITE_PUBLIC_POSTHOG_TOKEN= - VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com + VITE_POSTHOG_TOKEN= + VITE_POSTHOG_HOST=https://us.i.posthog.com ``` 3. 3 @@ -87,8 +87,8 @@ This guide walks you through setting up PostHog for React Router V7 in framework import { HydratedRouter } from "react-router/dom"; import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' - posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_TOKEN, { - api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST, + posthog.init(import.meta.env.VITE_POSTHOG_TOKEN, { + api_host: import.meta.env.VITE_POSTHOG_HOST, defaults: '2026-01-30', __add_tracing_headers: [ window.location.host, 'localhost' ], }); @@ -393,8 +393,8 @@ This guide walks you through setting up PostHog for React Router V7 in framework posthog?: PostHog; } export const posthogMiddleware: Route.MiddlewareFunction = async ({ request, context }, next) => { - const posthog = new PostHog(process.env.VITE_PUBLIC_POSTHOG_TOKEN!, { - host: process.env.VITE_PUBLIC_POSTHOG_HOST!, + const posthog = new PostHog(process.env.VITE_POSTHOG_TOKEN!, { + host: process.env.VITE_POSTHOG_HOST!, flushAt: 1, flushInterval: 0, }); diff --git a/skills/instrument-product-analytics/references/ruby-on-rails.md b/skills/instrument-product-analytics/references/ruby-on-rails.md index f4b7119..ad8cb5b 100644 --- a/skills/instrument-product-analytics/references/ruby-on-rails.md +++ b/skills/instrument-product-analytics/references/ruby-on-rails.md @@ -1,6 +1,6 @@ # Ruby on Rails - Docs -PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom events capture, feature flags, and automatic exception tracking. +PostHog makes it easy to get data about traffic and usage of your Ruby on Rails app. Integrating PostHog enables analytics, custom event capture, feature flags, and automatic exception tracking. This guide walks you through integrating PostHog into your Rails app using the [posthog-rails gem](https://github.com/PostHog/posthog-ruby/tree/main/posthog-rails). @@ -20,6 +20,7 @@ Or, to integrate manually, continue with the rest of this guide. - **ActiveJob instrumentation** – Tracks background job exceptions - **User context** – Automatically associates exceptions with the current user - **Smart filtering** – Excludes common Rails exceptions (404s, etc.) by default +- **Request context** – Adds request metadata and optional PostHog tracing header identity/session context to captured events - **Rails 7.0+ error reporter** – Integrates with Rails' built-in error reporting ## Installation @@ -67,35 +68,55 @@ This creates `config/initializers/posthog.rb` with sensible defaults and documen ## Configuration -The generated initializer includes all available options: +`PostHog.init` creates a single client instance used across your app. Avoid creating multiple `PostHog::Client` instances with the same API key, as this can cause dropped events and inconsistent behavior. + +The generated initializer includes the most common options: config/initializers/posthog.rb PostHog AI ```ruby +# Rails-specific configuration +PostHog::Rails.configure do |config| + config.auto_capture_exceptions = true # Enable automatic exception capture (default: false) + config.report_rescued_exceptions = true # Report exceptions Rails rescues (default: false) + config.auto_instrument_active_job = true # Instrument background jobs (default: false) + config.use_tracing_headers = true # Use PostHog tracing headers for identity/session context (default: true) + config.capture_user_context = true # Include authenticated user info in exceptions (default: true) + config.current_user_method = :current_user # Method to get current user (default: :current_user) + config.user_id_method = nil # Method to get ID from user object (default: auto-detect) + # Add additional exceptions to ignore + config.excluded_exceptions = ['MyCustomError'] +end # Core PostHog client initialization PostHog.init do |config| - # Required: Your PostHog API key + # Required: Your PostHog project API key config.api_key = '' # Optional: Your PostHog instance URL config.host = 'https://us.i.posthog.com' # Optional: Personal API key for feature flags config.personal_api_key = 'phx_xxxxxxxxx' + # Maximum number of events to queue before dropping (default: 10000) + config.max_queue_size = 10_000 + # Send events synchronously on the calling thread (default: false) + config.sync_mode = false + # Feature flags polling interval in seconds (default: 30) + config.feature_flags_polling_interval = 30 + # Feature flag request timeout in seconds (default: 3) + config.feature_flag_request_timeout_seconds = 3 # Error callback to detect misconfiguration config.on_error = proc { |status, msg| Rails.logger.error("PostHog error: #{msg}") } -end -# Rails-specific configuration -PostHog::Rails.configure do |config| - config.auto_capture_exceptions = true # Enable automatic exception capture - config.report_rescued_exceptions = true # Report exceptions Rails rescues - config.auto_instrument_active_job = true # Instrument background jobs - config.capture_user_context = true # Include user info in exceptions - config.current_user_method = :current_user # Method to get current user - # Add additional exceptions to ignore - config.excluded_exceptions = ['MyCustomError'] + # Before-send callback to modify or drop events + config.before_send = proc { |event| + event[:properties] ||= {} + event[:properties]['environment'] = Rails.env + event + } + # Disable network calls in test mode + config.test_mode = true if Rails.env.test? end ``` @@ -141,20 +162,45 @@ Ruby PostHog AI ```ruby -# Track an event -PostHog.capture( +PostHog.capture({ distinct_id: current_user.id, event: 'post_created', properties: { title: @post.title } -) -# Identify a user -PostHog.identify( +}) +``` + +Identify a user and set their person properties: + +Ruby + +PostHog AI + +```ruby +PostHog.identify({ distinct_id: current_user.id, properties: { email: current_user.email, plan: current_user.plan } -) +}) +``` + +The Rails integration delegates methods like `capture`, `identify`, `alias`, `group_identify`, `evaluate_flags`, `capture_exception`, `flush`, and `shutdown` to the initialized `PostHog::Client`. + +## Request context + +PostHog Rails automatically applies request-scoped context to events captured during web requests. Request metadata such as `$current_url`, `$request_method`, `$request_path`, `$user_agent`, and `$ip` is added to event properties. + +When `use_tracing_headers` is enabled, PostHog tracing headers (`X-PostHog-Distinct-Id` and `X-PostHog-Session-Id`) are also used as default `distinct_id` and `$session_id` values. Explicit `distinct_id` and properties passed to `PostHog.capture` always take precedence. + +Disable tracing header identity/session capture if you do not want client-supplied tracing headers used for server-side events. Request metadata is still captured: + +Ruby + +PostHog AI + +```ruby +PostHog::Rails.config.use_tracing_headers = false ``` ## Error tracking @@ -178,6 +224,8 @@ class PostsController < ApplicationController end ``` +`report_rescued_exceptions` controls whether exceptions Rails rescues (for example, exceptions rendered by Rails error pages) are captured. Enable it along with `auto_capture_exceptions` for complete error visibility, or leave it disabled to capture only unhandled exceptions. + ### Manual exception capture You can also manually capture exceptions: @@ -194,6 +242,22 @@ PostHog.capture_exception( ) ``` +If you evaluated feature flags for the request, pass the same snapshot to include matching flag properties on the exception event: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture_exception( + exception, + current_user.id, + { custom_property: 'value' }, + flags: flags +) +``` + ### Background job exceptions When `auto_instrument_active_job` is enabled, ActiveJob exceptions are automatically captured with job context: @@ -214,7 +278,7 @@ end #### Associating jobs with users -By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key: +By default, PostHog extracts a `distinct_id` from job arguments by looking for a `user_id` key in hash arguments: Ruby @@ -225,7 +289,7 @@ PostHog AI ProcessOrderJob.perform_later(order.id, user_id: current_user.id) ``` -For more control, use the `posthog_distinct_id` class method: +For more control, use the `posthog_distinct_id` class method. The proc or block receives the same arguments as `perform`: Ruby @@ -233,13 +297,30 @@ PostHog AI ```ruby class SendWelcomeEmailJob < ApplicationJob - posthog_distinct_id ->(user, options) { user.id } + posthog_distinct_id ->(user, _options) { user.id } def perform(user, options = {}) UserMailer.welcome(user).deliver_now end end ``` +You can also use a block: + +Ruby + +PostHog AI + +```ruby +class ProcessOrderJob < ApplicationJob + posthog_distinct_id do |_order, notify_user_id| + notify_user_id + end + def perform(order, notify_user_id) + # Process the order... + end +end +``` + ### Rails 7.0+ error reporter PostHog integrates with Rails' built-in error reporting: @@ -256,11 +337,13 @@ end Rails.error.record(exception, context: { user_id: current_user.id }) ``` -PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. +PostHog automatically extracts the user's distinct ID from `user_id` or `distinct_id` in the context hash. Other context keys are included as properties on the exception event. ### User context -PostHog Rails automatically captures user information from your controllers. If your user method has a different name, configure it: +PostHog Rails automatically captures authenticated user information from your controllers for exceptions. Authenticated Rails user context takes precedence over client-supplied tracing headers for exception identity. + +If your user method has a different name, configure it: Ruby @@ -272,11 +355,15 @@ PostHog::Rails.config.current_user_method = :logged_in_user #### User ID extraction -By default, PostHog Rails auto-detects the user's distinct ID by trying these methods: +By default, PostHog Rails auto-detects the user's distinct ID by trying these methods in order: 1. `posthog_distinct_id` – Define this on your User model for full control 2. `distinct_id` – Common analytics convention 3. `id` – Standard ActiveRecord primary key +4. `pk` – Primary key alias +5. `uuid` – For UUID-based primary keys + +It also checks hash-like users for `id`, `pk`, and `uuid` keys. You can configure a specific method: @@ -309,9 +396,16 @@ The following exceptions are not reported by default (common 4xx errors): - `AbstractController::ActionNotFound` - `ActionController::BadRequest` - `ActionController::InvalidAuthenticityToken` +- `ActionController::InvalidCrossOriginRequest` +- `ActionController::MethodNotAllowed` +- `ActionController::NotImplemented` +- `ActionController::ParameterMissing` - `ActionController::RoutingError` - `ActionController::UnknownFormat` +- `ActionController::UnknownHttpMethod` +- `ActionDispatch::Http::Parameters::ParseError` - `ActiveRecord::RecordNotFound` +- `ActiveRecord::RecordNotUnique` Add more with: @@ -325,7 +419,7 @@ PostHog::Rails.config.excluded_exceptions = ['MyException'] ## Feature flags -Use feature flags in your Rails app: +Evaluate flags once for the current user, then read values from the returned snapshot: Ruby @@ -334,7 +428,8 @@ PostHog AI ```ruby class PostsController < ApplicationController def show - if PostHog.is_feature_enabled('new-post-design', current_user.id) + flags = PostHog.evaluate_flags(current_user.id) + if flags.enabled?('new-post-design') render 'posts/show_new' else render 'posts/show' @@ -343,6 +438,35 @@ class PostsController < ApplicationController end ``` +For multivariate flags and experiments, use `get_flag`: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +variant = flags.get_flag('checkout-experiment') +if variant == 'test' + # Do something differently +end +``` + +When capturing an event after branching on a flag, pass the same `flags` snapshot so the event includes the exact flag values used by your code: + +Ruby + +PostHog AI + +```ruby +flags = PostHog.evaluate_flags(current_user.id) +PostHog.capture({ + distinct_id: current_user.id, + event: 'checkout_started', + flags: flags.only_accessed +}) +``` + For local evaluation, ensure you've set `personal_api_key`: Ruby @@ -355,9 +479,11 @@ config.personal_api_key = Rails.application.credentials.posthog[:personal_api_ke See our [Ruby SDK docs](/docs/libraries/ruby.md#local-evaluation) for details on local evaluation with Puma and Unicorn servers. +> **Note:** `PostHog.is_feature_enabled`, `PostHog.get_feature_flag`, `PostHog.get_feature_flag_result`, `PostHog.get_feature_flag_payload`, and `PostHog.capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `PostHog.evaluate_flags` for new code. + ## Testing -In your test environment, disable PostHog or use test mode: +In your test environment, disable network calls with test mode: config/environments/test.rb @@ -365,7 +491,8 @@ PostHog AI ```ruby PostHog.init do |config| - config.test_mode = true # Events are queued but not sent + config.api_key = '' + config.test_mode = true end ``` @@ -389,23 +516,33 @@ end | Option | Type | Default | Description | | --- | --- | --- | --- | -| api_key | String | required | Your PostHog project token | -| host | String | https://us.i.posthog.com | PostHog instance URL | -| personal_api_key | String | nil | For feature flag evaluation | -| test_mode | Boolean | false | Don't send events (for testing) | -| on_error | Proc | nil | Error callback | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. | +| personal_api_key | String | nil | Personal API key for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error). | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | + +The `PostHog.init` block supports the options above. Less common core options like `batch_size`, `disable_singleton_warning`, `skip_ssl_verification`, and the experimental `flag_definition_cache_provider` can be passed as an options hash to `PostHog.init(...)`; see the [Ruby SDK docs](/docs/libraries/ruby.md#configuration) for details. ### Rails-specific options +Configure these via `PostHog::Rails.configure` or `PostHog::Rails.config`: + | Option | Type | Default | Description | | --- | --- | --- | --- | -| auto_capture_exceptions | Boolean | false | Automatically capture exceptions | -| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues | -| auto_instrument_active_job | Boolean | false | Instrument ActiveJob | -| capture_user_context | Boolean | true | Include user info | -| current_user_method | Symbol | :current_user | Controller method for user | -| user_id_method | Symbol | nil | Method to extract ID from user object | -| excluded_exceptions | Array | [] | Additional exceptions to ignore | +| auto_capture_exceptions | Boolean | false | Automatically capture exceptions. | +| report_rescued_exceptions | Boolean | false | Report exceptions Rails rescues. | +| auto_instrument_active_job | Boolean | false | Capture ActiveJob exceptions with job context. | +| excluded_exceptions | Array | [] | Additional exception class names to ignore. | +| use_tracing_headers | Boolean | true | Use X-PostHog-Distinct-Id and X-PostHog-Session-Id as request-scoped defaults. | +| capture_user_context | Boolean | true | Include authenticated user info in exceptions. | +| current_user_method | Symbol | :current_user | Controller method used to fetch the current user. | +| user_id_method | Symbol | nil | Method used to extract the distinct ID from the user object. Auto-detects when nil. | ## Troubleshooting @@ -423,7 +560,7 @@ end => true ``` -2. Check your excluded exceptions list +2. Check your excluded exceptions list. 3. Verify middleware is installed: @@ -437,9 +574,9 @@ end ### User context not working -1. Verify `current_user_method` matches your controller method -2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, or `id` -3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method` +1. Verify `current_user_method` matches your controller method. +2. Check that the user object responds to `posthog_distinct_id`, `distinct_id`, `id`, `pk`, or `uuid`. +3. If using a custom identifier, set `PostHog::Rails.config.user_id_method = :your_method`. ### Feature flags not working diff --git a/skills/instrument-product-analytics/references/ruby.md b/skills/instrument-product-analytics/references/ruby.md index 8a70dac..ab491dd 100644 --- a/skills/instrument-product-analytics/references/ruby.md +++ b/skills/instrument-product-analytics/references/ruby.md @@ -4,6 +4,8 @@ The `posthog-ruby` library provides tracking functionality on the server-side fo 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 web app or other server-side application that needs performance. +> **Use a single client instance (singleton)** — Create the PostHog client once and reuse it throughout your application. Multiple client instances with the same API key can cause dropped events and inconsistent behavior. The SDK logs a warning if it detects multiple instances. + ## Installation Add this to your `Gemfile`: @@ -33,12 +35,98 @@ posthog = PostHog::Client.new({ You can find your project token and instance address in the [project settings](https://app.posthog.com/project/settings) page in PostHog. +## Configuration + +Initialize the client with your project token before making any calls: + +Ruby + +PostHog AI + +```ruby +require 'posthog' +posthog = PostHog::Client.new({ + api_key: '', + host: 'https://us.i.posthog.com', + on_error: Proc.new { |status, msg| print msg } +}) +``` + +Available client options: + +| Option | Type | Default | Description | +| --- | --- | --- | --- | +| api_key | String | required | Your PostHog project token. | +| host | String | https://us.i.posthog.com | Fully qualified PostHog API host. Include the protocol, for example https://us.i.posthog.com or https://eu.i.posthog.com. | +| personal_api_key | String | nil | Personal API key. Required for local feature flag evaluation and remote config payloads. | +| max_queue_size | Integer | 10000 | Maximum number of events to keep in the async queue before dropping new events. | +| batch_size | Integer | 100 | Maximum number of events to send in one async batch. | +| test_mode | Boolean | false | Keep events queued and do not send them. Useful for tests. | +| sync_mode | Boolean | false | Send events synchronously on the calling thread. Useful in forking environments like Sidekiq and Resque. | +| on_error | Proc | no-op | Callback called as on_error.call(status, error) for API or serialization errors. | +| feature_flags_polling_interval | Integer | 30 | Seconds between local feature flag definition polls. | +| feature_flag_request_timeout_seconds | Integer | 3 | Timeout, in seconds, for feature flag requests. | +| before_send | Proc | nil | Callback that receives the event hash before it is queued or sent. Return a modified event hash, or nil to drop the event. | +| disable_singleton_warning | Boolean | false | Suppress warnings about multiple clients with the same API key. Use only when you intentionally need multiple clients. | +| skip_ssl_verification | Boolean | false | Disable SSL certificate verification. Intended only for local development or custom deployments. | +| flag_definition_cache_provider | Object | nil | Experimental provider for distributed feature flag definition caching. See [distributed flag definition caching](#distributed-flag-definition-caching). | + +### Filtering or modifying events before sending + +Use `before_send` to add, modify, or drop events immediately before the SDK queues or sends them: + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ + api_key: '', + before_send: Proc.new do |event| + event[:properties] ||= {} + event[:properties]['environment'] = ENV['RACK_ENV'] + # Return nil to drop the event + event[:properties]['internal_user'] == true ? nil : event + end +}) +``` + +### Flushing and shutting down + +For short-lived scripts, call `flush` before the process exits. Call `shutdown` when your application is stopping to flush pending events and stop background resources. + +Ruby + +PostHog AI + +```ruby +posthog.capture({ distinct_id: 'user_123', event: 'script_finished' }) +posthog.flush +posthog.shutdown +``` + ## Identifying users > **Identifying users is required.** Backend events need a `distinct_id` that matches the ID your frontend uses when calling `posthog.identify()`. Without this, backend events are orphaned — they can't be linked to frontend event captures, [session replays](/docs/session-replay.md), [LLM traces](/docs/ai-engineering.md), or [error tracking](/docs/error-tracking.md). > > See our guide on [identifying users](/docs/getting-started/identify-users.md) for how to set this up. +Identify a user and set their person properties with `identify`: + +Ruby + +PostHog AI + +```ruby +posthog.identify({ + distinct_id: 'distinct_id_of_your_user', + properties: { + email: 'john@doe.com', + pro_user: false + } +}) +``` + ## Capturing events You can send custom events using `capture`: @@ -93,6 +181,20 @@ posthog.capture({ }) ``` +`capture` accepts these fields: + +| Field | Type | Description | +| --- | --- | --- | +| distinct_id | String | The user ID. If omitted, framework integrations can provide request context; otherwise the SDK generates a UUID and marks the event as personless. | +| event | String | Event name. Required. | +| properties | Hash | Event properties. | +| groups | Hash | Group analytics mapping from group type to group key. | +| timestamp | Time | When the event occurred. Defaults to the current time. | +| message_id | String | Optional message ID. | +| uuid | String | Optional event UUID used for deduplication. Must be a valid UUID. | +| flags | PostHog::FeatureFlagEvaluations | Snapshot returned by evaluate_flags. Adds $feature/ and $active_feature_flags properties without another /flags request. | +| send_feature_flags | Boolean, Hash, or PostHog::SendFeatureFlagsOptions | Deprecated. Prefer passing flags: from evaluate_flags. | + ## Person profiles and properties The Ruby SDK captures identified events by default. These create [person profiles](/docs/data/persons.md). To set [person properties](/docs/data/user-properties.md) in these profiles, include them when capturing an event: @@ -102,14 +204,14 @@ Ruby PostHog AI ```ruby -posthog.capture( +posthog.capture({ distinct_id: 'distinct_id', event: 'event_name', properties: { '$set': { name: 'Max Hedgehog' }, '$set_once': { initial_url: '/blog' } } -) +}) ``` For more details on the difference between `$set` and `$set_once`, see our [person properties docs](/docs/data/user-properties.md#what-is-the-difference-between-set-and-set_once). @@ -121,13 +223,13 @@ Ruby PostHog AI ```ruby -posthog.capture( +posthog.capture({ distinct_id: 'distinct_id', event: 'event_name', properties: { '$process_person_profile': false } -) +}) ``` ## Alias @@ -141,10 +243,10 @@ Ruby PostHog AI ```ruby -posthog.alias( - distinct_id: "distinct_id", - alias: "alias_id" -) +posthog.alias({ + distinct_id: 'distinct_id', + alias: 'alias_id' +}) ``` We strongly recommend reading our docs on [alias](/docs/data/identify.md#alias-assigning-multiple-distinct-ids-to-the-same-user) to best understand how to correctly use this method. @@ -192,7 +294,7 @@ end `flags.get_flag()` returns the variant string for multivariate flags, `true` for enabled boolean flags, `false` for disabled flags, and `nil` when the flag wasn't returned by the evaluation. -> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_payload()`, and `capture(send_feature_flags: true)` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. +> **Note:** `posthog.is_feature_enabled()`, `posthog.get_feature_flag()`, `posthog.get_feature_flag_result()`, `posthog.get_feature_flag_payload()`, and `capture({ ..., send_feature_flags: true })` still work during the migration period, but they're deprecated. Prefer `evaluate_flags()` for new code. ### Step 2: Include feature flag information when capturing events @@ -281,6 +383,36 @@ flags = posthog.evaluate_flags( ) ``` +### Evaluating locally only + +If you want to skip the remote `/flags` request and only use locally cached definitions, pass `only_evaluate_locally: true`: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + only_evaluate_locally: true, +) +``` + +### Disabling GeoIP for flag evaluation + +Pass `disable_geoip: true` to disable GeoIP lookup for remote flag evaluation: + +Ruby + +PostHog AI + +```ruby +flags = posthog.evaluate_flags( + 'distinct_id_of_your_user', + disable_geoip: true, +) +``` + ### Sending `$feature_flag_called` events Capturing `$feature_flag_called` events enables PostHog to know when a flag was accessed by a user and provide [analytics and insights](/docs/product-analytics/insights.md) on the flag. With `evaluate_flags()`, the SDK sends this event when you call `flags.enabled?()` or `flags.get_flag()` for a flag. @@ -367,6 +499,18 @@ posthog = PostHog::Client.new({ }) ``` +### Legacy single-flag methods + +The following methods are still available during the migration period, but are deprecated. Prefer `evaluate_flags` for new code. + +| Method | Replacement | +| --- | --- | +| posthog.is_feature_enabled(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).enabled?(flag_key) | +| posthog.get_feature_flag(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).get_flag(flag_key) | +| posthog.get_feature_flag_payload(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...).get_flag_payload(flag_key) | +| posthog.get_feature_flag_result(flag_key, distinct_id, ...) | posthog.evaluate_flags(distinct_id, ...) and read get_flag / get_flag_payload | +| posthog.capture({ ..., send_feature_flags: true }) | posthog.capture({ ..., flags: flags }) | + ### Local Evaluation Evaluating feature flags requires making a request to PostHog for each flag. However, you can improve performance by evaluating flags locally. Instead of making a request for each flag, PostHog will periodically request and store feature flag definitions locally, enabling you to evaluate flags without making additional requests. @@ -377,26 +521,26 @@ For details on how to implement local evaluation, see our [local evaluation guid #### Evaluating feature flags locally in unicorn server -If you have `preload_app true` in your unicorn config, you can use the [`after_fork`](https://www.rubydoc.info/gems/unicorn/Unicorn%2FConfigurator:after_fork) hook (which is part of the unicorn's configuration) to enable the feature flag cache to receive the updates from posthog dashboard. +If you have `preload_app true` in your unicorn config, you can use the [`after_fork`](https://www.rubydoc.info/gems/unicorn/Unicorn%2FConfigurator:after_fork) hook (which is part of the unicorn's configuration) to enable the feature flag cache to receive the updates from PostHog. Ruby PostHog AI ```ruby -after_fork do |server, worker| - $posthog = PostHog::Client.new( +after_fork do |_server, _worker| + $posthog = PostHog::Client.new({ api_key: '', - personal_api_key: '' + personal_api_key: '', host: 'https://us.i.posthog.com', on_error: Proc.new { |status, msg| print msg } - ) + }) end ``` #### Evaluating feature flags locally in a Puma server -If you use Puma with multiple workers, you can use the `on_worker_boot` hook (which is part of the Puma's configuration) to enable the feature flag cache to receive the updates from PostHog. +If you use Puma with multiple workers, you can use the `on_worker_boot` hook (which is part of Puma's configuration) to enable the feature flag cache to receive updates from PostHog. Ruby @@ -404,15 +548,50 @@ PostHog AI ```ruby on_worker_boot do - $posthog = PostHog::Client.new( + $posthog = PostHog::Client.new({ api_key: '', - personal_api_key: '' + personal_api_key: '', host: 'https://us.i.posthog.com', on_error: Proc.new { |status, msg| print msg } - ) + }) end ``` +### Distributed flag definition caching + +`flag_definition_cache_provider` is an experimental API for sharing locally evaluated feature flag definitions across multiple workers or processes. The provider object must implement: + +- `flag_definitions` – returns cached definitions as a hash with `:flags`, `:group_type_mapping`, and `:cohorts`, or `nil` if empty. +- `should_fetch_flag_definitions?` – returns `true` if this process should fetch fresh definitions from PostHog. +- `on_flag_definitions_received(data)` – stores freshly fetched definitions. +- `shutdown` – releases locks or other resources. + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ + api_key: '', + personal_api_key: '', + flag_definition_cache_provider: my_cache_provider +}) +``` + +Because this API is experimental, it may change in future minor versions. + +### Remote config payloads + +Use `get_remote_config_payload` to fetch the decrypted remote config payload for a flag. This requires `personal_api_key`. + +Ruby + +PostHog AI + +```ruby +payload = posthog.get_remote_config_payload('flag-key') +``` + ## Experiments (A/B tests) Since [experiments](/docs/experiments/start-here.md) use feature flags, the code for running an experiment is very similar to the feature flags code: @@ -437,7 +616,7 @@ Group analytics allows you to associate an event with a group (e.g. teams, organ > **Note:** This is a paid feature and is not available on the open-source or free cloud plan. Learn more on the [pricing page](/pricing.md). -- Capture an event and associate it with a group +Capture an event and associate it with a group: Ruby @@ -450,34 +629,32 @@ posthog.capture({ properties: { movie_id: '123', category: 'romcom' - } + }, groups: { 'company': 'company_id_in_your_db' } }) ``` -- Update properties on a group +Update properties on a group: Ruby PostHog AI ```ruby -posthog.group_identify( - { - group_type: "company", - group_key: "company_id_in_your_db", - properties: { - name: "Awesome Inc." - } +posthog.group_identify({ + group_type: 'company', + group_key: 'company_id_in_your_db', + properties: { + name: 'Awesome Inc.' } -) +}) ``` The `name` is a special property which is used in the PostHog UI for the name of the group. If you don't specify a `name` property, the group ID will be used instead. -If the optional `distinct_id` is not provided in the group identify call, it defaults to `${groupType}_${groupKey}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior will result in each group appearing as a separate person in PostHog. To avoid this, it's often more practical to use a consistent `distinct_id`, such as `group_identifier`. +If the optional `distinct_id` is not provided in the group identify call, it defaults to `$#{group_type}_#{group_key}` (e.g., `$company_company_id_in_your_db` in the example above). This default behavior will result in each group appearing as a separate person in PostHog. To avoid this, it's often more practical to use a consistent `distinct_id`, such as `group_identifier`. ## Exception capture @@ -487,9 +664,7 @@ You can capture exceptions using the `posthog-ruby` library. This enables you to The [posthog-rails](/docs/libraries/ruby-on-rails.md) gem provides automatic exception capture, ActiveJob instrumentation, and user context out of the box. See our [Rails error tracking guide](/docs/error-tracking/installation/ruby-on-rails.md) for details. -For non-Rails Ruby applications, you can manually capture exceptions: - -To capture exceptions, use the `capture_exception` method: +For non-Rails Ruby applications, you can manually capture exceptions with `capture_exception`: Ruby @@ -498,12 +673,12 @@ PostHog AI ```ruby begin # Code that might raise an exception - raise StandardError, "Something went wrong" + raise StandardError, 'Something went wrong' rescue => e posthog.capture_exception( e, - distinct_id: 'user_distinct_id', - properties: { + 'user_distinct_id', + { custom_property: 'custom_value' } ) @@ -514,9 +689,10 @@ The `capture_exception` method accepts the following parameters: | Parameter | Type | Description | | --- | --- | --- | -| exception | Exception | The exception object to capture (required) | -| distinct_id | String | The distinct ID of the user (optional) | -| properties | Hash | Additional properties to attach to the exception event (optional) | +| exception | Exception, String, or exception-like object | The exception to capture. Required. | +| distinct_id | String | The distinct ID of the user. Optional; request context can provide a default, otherwise the SDK generates a UUID. | +| additional_properties | Hash | Additional properties to attach to the exception event. Optional. | +| flags | PostHog::FeatureFlagEvaluations | Optional keyword argument. Adds the same feature flag properties as capture({ flags: flags }). | You can also override the [fingerprint](/docs/error-tracking/fingerprints.md) to customize how exceptions are grouped into issues: @@ -527,8 +703,8 @@ PostHog AI ```ruby posthog.capture_exception( e, - distinct_id: 'user_distinct_id', - properties: { + 'user_distinct_id', + { '$exception_fingerprint': 'CustomExceptionGroup' } ) @@ -536,7 +712,41 @@ posthog.capture_exception( ## Debug mode -The Ruby SDK debug logs by default. The log level by default is set to `WARN`. You can change it to `DEBUG` if you want to debug the client by running `posthog.logger.level = Logger::DEBUG`, where `posthog` is your initialized `PostHog::Client` instance. +The Ruby SDK logs warnings by default. You can change the log level to `DEBUG` to debug the client: + +Ruby + +PostHog AI + +```ruby +posthog.logger.level = Logger::DEBUG +``` + +You can also replace the SDK logger globally: + +Ruby + +PostHog AI + +```ruby +PostHog::Logging.logger = Rails.logger +``` + +## Test helpers + +When `test_mode: true`, events remain queued. You can inspect and clear the queue in tests: + +Ruby + +PostHog AI + +```ruby +posthog = PostHog::Client.new({ api_key: '', test_mode: true }) +posthog.capture({ distinct_id: 'user_123', event: 'test_event' }) +posthog.queued_messages +posthog.dequeue_last_message +posthog.clear +``` ## Thank you diff --git a/skills/querying-posthog-data/references/available-functions.md b/skills/querying-posthog-data/references/available-functions.md index 2d87f55..1ee494f 100644 --- a/skills/querying-posthog-data/references/available-functions.md +++ b/skills/querying-posthog-data/references/available-functions.md @@ -630,6 +630,8 @@ protocol quantile quantileExact quantiles +quantilesMerge +quantilesState queryString queryStringAndFragment radians diff --git a/skills/querying-posthog-data/references/example-error-tracking.md b/skills/querying-posthog-data/references/example-error-tracking.md index 85d6e94..05eb24e 100644 --- a/skills/querying-posthog-data/references/example-error-tracking.md +++ b/skills/querying-posthog-data/references/example-error-tracking.md @@ -10,13 +10,13 @@ SELECT count(DISTINCT uuid) AS occurrences, count(DISTINCT nullIf($session_id, '')) AS sessions, count(DISTINCT coalesce(nullIf(toString(person_id), '00000000-0000-0000-0000-000000000000'), distinct_id)) AS users, - sumForEach(arrayMap(bin -> if(and(greater(timestamp, bin), lessOrEquals(dateDiff('seconds', bin, timestamp), divide(dateDiff('seconds', toDateTime(toDateTime('2026-05-21 20:25:41.236619')), toDateTime(toDateTime('2026-05-22 20:25:41.237155'))), 20))), 1, 0), arrayMap(i -> dateAdd(toDateTime(toDateTime('2026-05-21 20:25:41.236619')), toIntervalSecond(multiply(i, divide(dateDiff('seconds', toDateTime(toDateTime('2026-05-21 20:25:41.236619')), toDateTime(toDateTime('2026-05-22 20:25:41.237155'))), 20)))), range(0, 20)))) AS volumeRange, + sumForEach(arrayMap(bin -> if(and(greater(timestamp, bin), lessOrEquals(dateDiff('seconds', bin, timestamp), divide(dateDiff('seconds', toDateTime(toDateTime('2026-05-26 21:03:56.953402')), toDateTime(toDateTime('2026-05-27 21:03:56.953927'))), 20))), 1, 0), arrayMap(i -> dateAdd(toDateTime(toDateTime('2026-05-26 21:03:56.953402')), toIntervalSecond(multiply(i, divide(dateDiff('seconds', toDateTime(toDateTime('2026-05-26 21:03:56.953402')), toDateTime(toDateTime('2026-05-27 21:03:56.953927'))), 20)))), range(0, 20)))) AS volumeRange, argMin(tuple(uuid, distinct_id, timestamp, properties), timestamp) AS first_event, argMax(properties.$lib, timestamp) AS library FROM events AS e WHERE - and(equals(event, '$exception'), isNotNull(e.issue_id), equals(properties.tag, 'max_ai'), greaterOrEquals(timestamp, toDateTime(toDateTime('2026-05-21 20:25:41.236619'))), lessOrEquals(timestamp, toDateTime(toDateTime('2026-05-22 20:25:41.237155'))), or(greater(position(lower(properties.$exception_types), lower('constant')), 0), greater(position(lower(properties.$exception_values), lower('constant')), 0), greater(position(lower(properties.$exception_sources), lower('constant')), 0), greater(position(lower(properties.$exception_functions), lower('constant')), 0), greater(position(lower(properties.email), lower('constant')), 0), greater(position(lower(person.properties.email), lower('constant')), 0))) + and(equals(event, '$exception'), isNotNull(e.issue_id), equals(properties.tag, 'max_ai'), greaterOrEquals(timestamp, toDateTime(toDateTime('2026-05-26 21:03:56.953402'))), lessOrEquals(timestamp, toDateTime(toDateTime('2026-05-27 21:03:56.953927'))), or(greater(position(lower(properties.$exception_types), lower('constant')), 0), greater(position(lower(properties.$exception_values), lower('constant')), 0), greater(position(lower(properties.$exception_sources), lower('constant')), 0), greater(position(lower(properties.$exception_functions), lower('constant')), 0), greater(position(lower(properties.email), lower('constant')), 0), greater(position(lower(person.properties.email), lower('constant')), 0))) GROUP BY id ORDER BY diff --git a/skills/querying-posthog-data/references/example-funnel-trends.md b/skills/querying-posthog-data/references/example-funnel-trends.md index 5ce79d3..a839d31 100644 --- a/skills/querying-posthog-data/references/example-funnel-trends.md +++ b/skills/querying-posthog-data/references/example-funnel-trends.md @@ -26,7 +26,7 @@ FROM FROM events AS e WHERE - and(and(greaterOrEquals(e.timestamp, toDateTime('2025-12-03 00:00:00.000000')), lessOrEquals(e.timestamp, toDateTime('2025-12-10 23:59:59.999999'))), and(notEquals(aggregation_target, ''), notEquals(aggregation_target, NULL)))) + and(and(greaterOrEquals(e.timestamp, toDateTime('2025-12-03 00:00:00.000000')), lessOrEquals(e.timestamp, toDateTime('2025-12-10 23:59:59.999999'))), and(notEquals(toString(aggregation_target), ''), notEquals(aggregation_target, NULL)))) GROUP BY aggregation_target) AS data RIGHT OUTER JOIN (SELECT diff --git a/skills/querying-posthog-data/references/example-logs.md b/skills/querying-posthog-data/references/example-logs.md index 670cb62..c2271a3 100644 --- a/skills/querying-posthog-data/references/example-logs.md +++ b/skills/querying-posthog-data/references/example-logs.md @@ -23,7 +23,7 @@ SELECT FROM logs WHERE - and(and(greaterOrEquals(toStartOfDay(time_bucket), toStartOfDay(assumeNotNull(toDateTime('2025-12-09 00:00:00')))), lessOrEquals(toStartOfDay(time_bucket), toStartOfDay(assumeNotNull(toDateTime('2025-12-10 00:00:00'))))), 1, greaterOrEquals(timestamp, toDateTime('2026-05-21 20:25:43.656852')), indexHint(like(lower(body), '%timeout%')), ilike(toString(body), '%timeout%'), in(severity_text, tuple('warn', 'error', 'fatal'))) + and(and(greaterOrEquals(toStartOfDay(time_bucket), toStartOfDay(assumeNotNull(toDateTime('2025-12-09 00:00:00')))), lessOrEquals(toStartOfDay(time_bucket), toStartOfDay(assumeNotNull(toDateTime('2025-12-10 00:00:00'))))), 1, greaterOrEquals(timestamp, toDateTime('2026-05-26 21:03:59.341134')), indexHint(like(lower(body), '%timeout%')), ilike(toString(body), '%timeout%'), in(severity_text, tuple('warn', 'error', 'fatal'))) ORDER BY timestamp DESC, uuid DESC diff --git a/skills/querying-posthog-data/references/example-session-replay.md b/skills/querying-posthog-data/references/example-session-replay.md index 7812b36..095a25e 100644 --- a/skills/querying-posthog-data/references/example-session-replay.md +++ b/skills/querying-posthog-data/references/example-session-replay.md @@ -19,17 +19,17 @@ SELECT sum(s.console_error_count) AS console_error_count, max(s.retention_period_days) AS retention_period_days, plus(dateTrunc('DAY', start_time), toIntervalDay(coalesce(retention_period_days, 30))) AS expiry_time, - date_diff('DAY', toDateTime('2026-05-22 20:25:44.656339'), expiry_time) AS recording_ttl, - greaterOrEquals(max(s._timestamp), toDateTime('2026-05-22 20:20:44.655475')) AS ongoing, + date_diff('DAY', toDateTime('2026-05-27 21:04:00.357593'), expiry_time) AS recording_ttl, + greaterOrEquals(max(s._timestamp), toDateTime('2026-05-27 20:59:00.356796')) AS ongoing, round(multiply(divide(plus(plus(plus(divide(sum(s.active_milliseconds), 1000), sum(s.click_count)), sum(s.keypress_count)), sum(s.console_error_count)), plus(plus(plus(plus(sum(s.mouse_activity_count), dateDiff('SECOND', start_time, end_time)), sum(s.console_error_count)), sum(s.console_log_count)), sum(s.console_warn_count))), 100), 2) AS activity_score FROM raw_session_replay_events AS s WHERE - and(greaterOrEquals(s.min_first_timestamp, toDateTime('2026-05-19 00:00:00.000000')), lessOrEquals(s.min_first_timestamp, toDateTime('2026-05-22 20:25:44.655652'))) + and(greaterOrEquals(s.min_first_timestamp, toDateTime('2026-05-24 00:00:00.000000')), lessOrEquals(s.min_first_timestamp, toDateTime('2026-05-27 21:04:00.356968'))) GROUP BY session_id HAVING - and(greaterOrEquals(expiry_time, toDateTime('2026-05-22 20:25:44.656197')), equals(max(s.is_deleted), 0), greater(active_seconds, 5.0)) + and(greaterOrEquals(expiry_time, toDateTime('2026-05-27 21:04:00.357478')), equals(max(s.is_deleted), 0), greater(active_seconds, 5.0)) ORDER BY start_time DESC, session_id DESC diff --git a/skills/querying-posthog-data/references/example-sessions.md b/skills/querying-posthog-data/references/example-sessions.md index a57eac7..7252939 100644 --- a/skills/querying-posthog-data/references/example-sessions.md +++ b/skills/querying-posthog-data/references/example-sessions.md @@ -13,7 +13,7 @@ SELECT FROM sessions WHERE - and(less($start_timestamp, toDateTime('2026-05-22 20:25:50.007785')), greater($start_timestamp, toDateTime('2026-05-21 20:25:45.008598'))) + and(less($start_timestamp, toDateTime('2026-05-27 21:04:05.708136')), greater($start_timestamp, toDateTime('2026-05-26 21:04:00.708886'))) ORDER BY $start_timestamp DESC LIMIT 50000