From 93a3d1360293a251090ed06fb090bdf74486f90d Mon Sep 17 00:00:00 2001 From: "releaser-ai-plugin[bot]" <273148615+releaser-ai-plugin[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 12:53:46 +0000 Subject: [PATCH] chore: sync skills (agent-skills-v0.226.0, context-mill@v1.23.6) --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- .cursor-plugin/plugin.json | 2 +- gemini-extension.json | 2 +- skills/.sync-manifest | 1 + .../SKILL.md | 97 ++++++ .../scripts/decode_recording_export.py | 281 +++++++++++++++++ skills/authoring-signals-scouts/SKILL.md | 6 +- .../references/lifecycle-and-testing.md | 6 +- skills/debugging-signals-pipeline/SKILL.md | 4 +- .../references/scout-data-model.md | 2 +- .../references/angular.md | 4 +- .../references/flutter.md | 2 +- .../references/nextjs.md | 6 +- .../references/nuxt-3-6.md | 2 +- .../references/react.md | 2 +- .../references/svelte.md | 2 +- .../references/web.md | 4 +- .../references/adding-feature-flag-code.md | 6 +- .../references/flutter.md | 2 +- .../references/next-js.md | 6 +- .../references/react.md | 2 +- .../references/web.md | 4 +- .../references/angular.md | 6 +- .../references/astro.md | 6 +- .../references/flutter.md | 2 +- .../instrument-integration/references/js.md | 12 +- .../references/next-js.md | 6 +- .../references/nuxt-js-3-6.md | 6 +- .../references/nuxt-js.md | 2 +- .../instrument-integration/references/php.md | 15 +- .../references/posthog-js.md | 2 +- .../references/posthog-python.md | 283 ++++++++++-------- .../references/react-native.md | 2 +- .../references/react-router-v6.md | 4 +- .../references/react-router-v7-data-mode.md | 4 +- .../react-router-v7-declarative-mode.md | 4 +- .../react-router-v7-framework-mode.md | 2 +- .../references/react.md | 6 +- .../references/svelte.md | 4 +- .../references/tanstack-start.md | 2 +- .../references/vue-js.md | 6 +- skills/instrument-logs/references/flutter.md | 2 +- .../references/angular.md | 6 +- .../references/astro.md | 6 +- .../references/flutter.md | 2 +- .../references/next-js.md | 6 +- .../references/nuxt-js-3-6.md | 6 +- .../references/nuxt-js.md | 2 +- .../references/php.md | 15 +- .../references/posthog-python.md | 283 ++++++++++-------- .../references/react-native.md | 2 +- .../references/react-router-v6.md | 4 +- .../references/react-router-v7-data-mode.md | 4 +- .../react-router-v7-declarative-mode.md | 4 +- .../react-router-v7-framework-mode.md | 2 +- .../references/svelte.md | 4 +- .../references/tanstack-start.md | 2 +- .../references/vue-js.md | 6 +- .../references/example-error-tracking.md | 8 +- .../references/example-logs.md | 2 +- .../references/example-session-replay.md | 8 +- .../references/example-sessions.md | 2 +- skills/signals-scout-general/SKILL.md | 62 ++-- .../references/discovery.md | 100 +++++++ 65 files changed, 962 insertions(+), 397 deletions(-) create mode 100644 skills/analysing-exported-session-recordings/SKILL.md create mode 100644 skills/analysing-exported-session-recordings/scripts/decode_recording_export.py create mode 100644 skills/signals-scout-general/references/discovery.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index e240265..895b7a6 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "posthog", "description": "Access PostHog analytics, feature flags, experiments, error tracking, and insights directly from your AI coding tool. Optionally capture Claude Code sessions to PostHog LLM Analytics.", - "version": "1.1.40", + "version": "1.1.41", "author": { "name": "PostHog", "email": "hey@posthog.com", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 11fb052..0bf371d 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.38", + "version": "1.0.39", "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 ec2371d..5ec3c7c 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "posthog", "displayName": "PostHog", - "version": "1.1.34", + "version": "1.1.35", "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 2ac1573..bd9d259 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "posthog", - "version": "1.0.36", + "version": "1.0.37", "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 1d01ff7..4b18ebf 100644 --- a/skills/.sync-manifest +++ b/skills/.sync-manifest @@ -1,3 +1,4 @@ +analysing-exported-session-recordings analyzing-experiment-session-replays assessing-heatmaps auditing-endpoints diff --git a/skills/analysing-exported-session-recordings/SKILL.md b/skills/analysing-exported-session-recordings/SKILL.md new file mode 100644 index 0000000..3652e7a --- /dev/null +++ b/skills/analysing-exported-session-recordings/SKILL.md @@ -0,0 +1,97 @@ +--- +name: analysing-exported-session-recordings +description: >- + Decode and analyse a downloaded session-recording export zip (the `data/` blocks + plus ClickHouse metadata) to understand what is making a recording large or slow: + size composition by DOM mutations vs full snapshots vs network bodies, biggest + payloads, content-type breakdown, churned tags/attributes. Use when asked "why is + this recording so big?", "what's in this export?", "break down replay size for + this session", "analyse the exported recording", or to validate whether a + size-reduction change (e.g. skipping binary network bodies) would actually help a + given session. Pairs with `exporting-session-recordings`, which produces the zip + this skill reads. +--- + +# Analysing exported session recordings + +An export bundles a recording's raw v2 storage blocks (under `data/`) plus its +ClickHouse metadata (`session-replay-events.json`, `events.json`). +Use this skill to crack those blocks open and measure what the recording is made of, +so size or performance conclusions rest on decoded data — not on raw bytes. + +Get the zip first via the `exporting-session-recordings` skill. + +## The one thing that will mislead you: the blocks are double-compressed + +A `data/` block is **not** readable JSON. It is two layers deep, and skipping either +layer makes the bytes look like binary garbage or "corruption" that isn't there: + +1. **Whole block: snappy-compressed.** The exporter fetches blocks with + `decompress=False` (`export_recording/activities.py`), so it writes the raw S3 + object. Each block is `snappy`-compressed and written at its byte offset, zero-padded + (so a `data/` file is mostly `\x00` with the real block at the end). Snappy keeps + literal text runs verbatim with binary copy-tokens between them, which is why a raw + block reads as "half JSON, half binary". +2. **Per field: gzip-compressed.** Once snappy-decompressed, a block is JSONL of + `["windowId", {event}]` rows. Events tagged `cv: "2024-10"` have their heavy DOM + fields (full-snapshot `data`; mutation `adds`/`attributes`/`texts`/`removes`) + individually gzip-compressed and stored as a binary-in-JSON string via fflate + `strFromU8(gzipSync(strToU8(json)), true)` — each string char is one gzip byte. + +**Do not measure or draw conclusions from the raw block bytes.** Reading them as UTF-8 +produces phantom `U+FFFD` runs and wildly wrong size splits (e.g. network bodies look +tiny because they are still snappy-compressed). Always decode both layers first, then +measure. The decoder script below does this; reach for it before hand-rolling anything. + +The exporter is lossless — it round-trips the raw S3 block (base64 through Redis, binary +write). Do **not** "fix" the exporter to decompress: export and import are a matched pair +that re-upload the raw blocks, so changing the export format breaks `import_recording`. +The decode belongs on the read side. + +## Decoding and the size report + +`scripts/decode_recording_export.py` does snappy-then-gzip and reports composition. +It needs a snappy codec (`pip install python-snappy`, or `cramjam`). + +```bash +# size + composition report (accepts the zip directly, or an already-extracted dir) +python scripts/decode_recording_export.py export-.zip + +# also emit fully-decoded events (DOM fields un-gzipped and inlined) for deeper digging +python scripts/decode_recording_export.py export-.zip --dump-jsonl decoded.jsonl +``` + +The report gives you: + +- **Decompressed DOM payload** split across full snapshots vs mutation + `adds`/`attributes`/`texts`/`removes` — `adds` and repeated full snapshots are the + usual DOM-side offenders. +- **Network bodies** by response content-type — these are stored **un-gzipped** in the + JSONL, so compare them to DOM on **decoded** size, never on raw bytes. +- **Top tag names and mutated attribute keys**, to see what the DOM churn actually is + (e.g. SVG icon trees, inline `style` animation churn). + +## Reading the numbers honestly + +- **Compare like with like.** DOM fields are gzip-then-snappy; network bodies are + plaintext-then-snappy. The report's decompressed sizes tell you what is _in_ the + recording (and what the player must hold), which is the right lens for "what should we + cut". For "what does it cost to store/ingest", remember network bodies compress far + better than already-gzipped DOM, so their stored share is smaller than their decoded + share. +- **A handful of blocks may fail to snappy-decompress** (empty/edge blocks). The script + logs and skips them; a few skips do not move the totals. +- **Blocks are sequential byte ranges and should not overlap** — if you write your own + pass, sanity-check for duplicate `(name, timestamp, kind, len)` bodies before trusting + a total. + +## Worked example (validated) + +A long single-page-app session decoded to ~70 MiB of DOM payload but **~253 MiB of +network bodies**, of which `binary/octet-stream` (136 MiB), `image/webp` (18.5 MiB) and +`image/svg+xml` (3.5 MiB) were binary assets captured as text. The lesson that earned +this skill: measuring those same bodies on the raw (still-snappy) bytes reported only +single-digit MiB and pointed at the wrong culprit. Decoded, the conclusion flips — +skipping binary network bodies (`feat(replay): skip binary/asset bodies in network +capture`, posthog-js #3912) is the dominant lever for a session like this, not a +rounding error. Decode before you conclude. diff --git a/skills/analysing-exported-session-recordings/scripts/decode_recording_export.py b/skills/analysing-exported-session-recordings/scripts/decode_recording_export.py new file mode 100644 index 0000000..e564c10 --- /dev/null +++ b/skills/analysing-exported-session-recordings/scripts/decode_recording_export.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python3 +"""Decode and analyse a session-recording export zip. + +An export (see the `exporting-session-recordings` skill) bundles the recording's +raw v2 storage blocks under `data/` plus ClickHouse metadata. The blocks are the +RAW S3 objects: each is snappy-compressed, written at its byte offset and +zero-padded (the exporter fetches with decompress=False). Inside, once +snappy-decompressed, each block is JSONL of `["windowId", {event}]` rows; events +tagged `cv: "2024-10"` have their heavy DOM fields individually gzip-compressed +and stored as binary-in-JSON strings (fflate `strFromU8(gzipSync(...), true)`). + +So fully decoding is two layers: snappy (whole block) then gzip (per field). + +Usage: + python decode_recording_export.py [--report] [--dump-jsonl OUT.jsonl] + +Requires a snappy codec: `python-snappy` (preferred) or `cramjam`. +""" + +from __future__ import annotations + +import argparse +import collections +import gzip +import json +import re +import sys +import zipfile +from pathlib import Path +from typing import Callable, Iterator + +EVENT_TYPES = {0: "DomContentLoaded", 1: "Load", 2: "FullSnapshot", 3: "Incremental", 4: "Meta", 5: "Custom", 6: "Plugin"} +INCREMENTAL_SOURCES = { + 0: "Mutation", + 1: "MouseMove", + 2: "MouseInteraction", + 3: "Scroll", + 4: "ViewportResize", + 5: "Input", + 6: "TouchMove", + 7: "MediaInteraction", + 8: "StyleSheetRule", + 9: "CanvasMutation", + 10: "Font", + 11: "Log", + 12: "Drag", + 13: "StyleDeclaration", + 14: "Selection", + 15: "AdoptedStyleSheet", +} +COMPRESSED_MUTATION_FIELDS = ("adds", "attributes", "texts", "removes") +TAG_RE = re.compile(rb'"tagName":"([^"]+)"') +ATTR_KEY_RE = re.compile(rb'"([a-zA-Z_:-]+)":') + + +def _load_snappy() -> Callable[[bytes], bytes]: + try: + import snappy # noqa: PLC0415 — optional codec, resolved at runtime + + return snappy.decompress + except ImportError: + pass + try: + import cramjam # noqa: PLC0415 — fallback codec, resolved at runtime + + return lambda b: bytes(cramjam.snappy.decompress(b)) + except ImportError as err: + raise SystemExit("Need a snappy codec. Install with `pip install python-snappy` (or `cramjam`).") from err + + +def _strip_null_padding(raw: bytes) -> bytes: + start = 0 + while start < len(raw) and raw[start] == 0: + start += 1 + end = len(raw) + while end > start and raw[end - 1] == 0: + end -= 1 + return raw[start:end] + + +def _block_to_text(name: str, raw: bytes, snappy_decompress: Callable[[bytes], bytes]) -> str | None: + block = _strip_null_padding(raw) + if not block: + return None + try: + return snappy_decompress(block).decode("utf-8", "replace") + except Exception as err: # noqa: BLE001 — a single bad block shouldn't abort the run + print(f" ! skipped block {name}: {err}", file=sys.stderr) + return None + + +def iter_block_text(source: Path, snappy_decompress: Callable[[bytes], bytes]) -> Iterator[str]: + """Yield the snappy-decompressed UTF-8 text of every data block, one block in memory at a time.""" + if source.is_dir(): + block_paths = sorted((source / "data").glob("*")) if (source / "data").is_dir() else sorted(source.glob("*")) + for path in block_paths: + if path.is_file(): + text = _block_to_text(path.name, path.read_bytes(), snappy_decompress) + if text is not None: + yield text + else: + # keep a single zip handle open for the whole iteration; read+decode one block at a time + with zipfile.ZipFile(source) as zf: + for name in zf.namelist(): + if name.startswith("data/") and not name.endswith("/"): + text = _block_to_text(name, zf.read(name), snappy_decompress) + if text is not None: + yield text + + +def iter_records(block_text: str) -> Iterator[dict]: + """Yield the event dict from each `["windowId", {event}]` JSONL row.""" + for line in block_text.split("\n"): + line = line.strip() + if not line: + continue + try: + row = json.loads(line) + except json.JSONDecodeError: + continue + if isinstance(row, list) and len(row) == 2 and isinstance(row[1], dict): + yield row[1] + + +def gunzip_field(field: str) -> bytes: + """Reverse fflate `strFromU8(gzipSync(...), true)`: each char is one gzip byte.""" + return gzip.decompress(bytes(ord(c) & 0xFF for c in field)) + + +class Report: + def __init__(self) -> None: + self.records = 0 + self.gz_ok = 0 + self.gz_fail = 0 + self.dom_bytes: collections.Counter[str] = collections.Counter() + self.dom_n: collections.Counter[str] = collections.Counter() + self.tags: collections.Counter[str] = collections.Counter() + self.attrs: collections.Counter[str] = collections.Counter() + self.net_body_bytes = 0 + self.net_bodies = 0 + self.net_bytes_by_content_type: collections.Counter[str] = collections.Counter() + + def add_dom(self, label: str, decompressed: bytes, collect_tags: bool, collect_attrs: bool) -> None: + self.dom_bytes[label] += len(decompressed) + self.dom_n[label] += 1 + if collect_tags: + for tag in TAG_RE.findall(decompressed): + self.tags[tag.decode("utf-8", "replace").lower()] += 1 + if collect_attrs: + for attr in ATTR_KEY_RE.findall(decompressed): + self.attrs[attr.decode()] += 1 + + +def analyse(source: Path) -> Report: + snappy_decompress = _load_snappy() + report = Report() + for block_text in iter_block_text(source, snappy_decompress): + for event in iter_records(block_text): + report.records += 1 + cv = event.get("cv") + data = event.get("data") + event_type = event.get("type") + + if cv == "2024-10" and event_type == 2 and isinstance(data, str): + _decode_into(report, "FullSnapshot", data, collect_tags=True, collect_attrs=False) + elif cv == "2024-10" and event_type == 3 and isinstance(data, dict): + for field in COMPRESSED_MUTATION_FIELDS: + value = data.get(field) + if isinstance(value, str): + _decode_into( + report, + f"mutation.{field}", + value, + collect_tags=(field == "adds"), + collect_attrs=(field == "attributes"), + ) + elif event_type == 6 and isinstance(data, dict): + _measure_network(report, data) + return report + + +def _decode_into(report: Report, label: str, field: str, collect_tags: bool, collect_attrs: bool) -> None: + try: + decompressed = gunzip_field(field) + except Exception: # noqa: BLE001 — count and move on; one field shouldn't abort + report.gz_fail += 1 + return + report.gz_ok += 1 + report.add_dom(label, decompressed, collect_tags, collect_attrs) + + +def _measure_network(report: Report, data: dict) -> None: + payload = data.get("payload") + requests = payload.get("requests") if isinstance(payload, dict) else None + for request in requests or []: + content_type = "unknown" + headers = request.get("responseHeaders") or {} + if isinstance(headers, dict): + for header, value in headers.items(): + if header.lower() == "content-type" and isinstance(value, str): + content_type = value.split(";")[0].strip() + for key in ("requestBody", "responseBody"): + body = request.get(key) + if isinstance(body, str): + report.net_body_bytes += len(body) + report.net_bodies += 1 + report.net_bytes_by_content_type[content_type] += len(body) + + +def print_report(report: Report) -> None: + dom_total = sum(report.dom_bytes.values()) + print(f"records parsed: {report.records:,} gzip fields ok={report.gz_ok:,} fail={report.gz_fail:,}\n") + print(f"=== decompressed DOM payload: {dom_total:,} bytes ({dom_total / 1024 / 1024:.1f} MiB) ===") + for label, by in report.dom_bytes.most_common(): + share = 100 * by / dom_total if dom_total else 0 + print(f" {label:20} n={report.dom_n[label]:7,} {by:14,} ({by / 1024 / 1024:7.1f} MiB, {share:4.1f}%)") + + net_total = report.net_body_bytes + print(f"\n=== network bodies: {net_total:,} bytes ({net_total / 1024 / 1024:.1f} MiB) across {report.net_bodies:,} bodies ===") + print(" (these are stored UN-gzipped in the JSONL, unlike DOM fields — compare decoded sizes, not raw bytes)") + for ct, by in report.net_bytes_by_content_type.most_common(10): + share = 100 * by / net_total if net_total else 0 + print(f" {by / 1024 / 1024:8.1f} MiB ({share:4.1f}%) {ct}") + + print("\n=== top tagNames (FullSnapshot + adds) ===") + for tag, n in report.tags.most_common(20): + print(f" {n:9,} {tag}") + + print("\n=== top mutated attribute keys ===") + for attr, n in report.attrs.most_common(20): + print(f" {n:9,} {attr}") + + +def dump_jsonl(source: Path, out_path: Path) -> None: + """Write fully-decoded events (DOM fields un-gzipped, inlined) to a JSONL file.""" + snappy_decompress = _load_snappy() + written = 0 + with out_path.open("w") as out: + for block_text in iter_block_text(source, snappy_decompress): + for event in iter_records(block_text): + cv = event.get("cv") + data = event.get("data") + if cv == "2024-10" and event.get("type") == 2 and isinstance(data, str): + try: + event["data"] = json.loads(gunzip_field(data)) + event.pop("cv", None) + except Exception: # noqa: BLE001 + pass + elif cv == "2024-10" and event.get("type") == 3 and isinstance(data, dict): + for field in COMPRESSED_MUTATION_FIELDS: + value = data.get(field) + if isinstance(value, str): + try: + data[field] = json.loads(gunzip_field(value)) + except Exception: # noqa: BLE001 + pass + event.pop("cv", None) + out.write(json.dumps(event, separators=(",", ":"))) + out.write("\n") + written += 1 + print(f"wrote {written:,} decoded events to {out_path}") + + +def main() -> None: + parser = argparse.ArgumentParser(description="Decode and analyse a session-recording export zip.") + parser.add_argument("source", type=Path, help="path to export-.zip or an extracted export directory") + parser.add_argument("--report", action="store_true", help="print the size/composition report (default)") + parser.add_argument("--dump-jsonl", type=Path, metavar="OUT", help="write fully-decoded events to a JSONL file") + args = parser.parse_args() + + if not args.source.exists(): + raise SystemExit(f"no such path: {args.source}") + + if args.dump_jsonl: + dump_jsonl(args.source, args.dump_jsonl) + if args.report or not args.dump_jsonl: + print_report(analyse(args.source)) + + +if __name__ == "__main__": + main() diff --git a/skills/authoring-signals-scouts/SKILL.md b/skills/authoring-signals-scouts/SKILL.md index 92a5ef3..ade3e47 100644 --- a/skills/authoring-signals-scouts/SKILL.md +++ b/skills/authoring-signals-scouts/SKILL.md @@ -126,11 +126,11 @@ skill with `posthog:signals-scout-config-create {"skill_name": "signals-scout-", "description": "...", "body": "...", "compatibility": "...", "metadata": {"owner_team": "", "scope": ""}} # Register its config immediately with the schedule you want (otherwise the coordinator -# auto-registers the default every-3-hours schedule on its next tick) +# auto-registers the default every-24-hours schedule on its next tick) posthog:signals-scout-config-create {"skill_name": "signals-scout-", "run_interval_minutes": 120} # Adapt an existing per-team scout — use the SMALLEST primitive (find/replace, not full-body) @@ -91,7 +91,7 @@ hogli unsync:skill -- --name signals-scout- Authoring a new canonical scout is just creating `signals-scout-/SKILL.md` and merging — the next tick discovers it, seeds it onto enrolled teams, and auto-registers an -enabled config on the default every-3-hours schedule. **If you change the fleet shape (add/rename a scout, change the +enabled config on the default every-24-hours schedule. **If you change the fleet shape (add/rename a scout, change the SKILL.md schema), update `products/signals/skills/AGENTS.md`.** On master, CI builds and publishes `dist/skills.zip` to the downstream distribution repos (the `ai-plugin` bundle and the standalone skills repo) automatically. diff --git a/skills/debugging-signals-pipeline/SKILL.md b/skills/debugging-signals-pipeline/SKILL.md index c33eddd..97b6fd3 100644 --- a/skills/debugging-signals-pipeline/SKILL.md +++ b/skills/debugging-signals-pipeline/SKILL.md @@ -223,8 +223,8 @@ grep CLICKHOUSE_DATABASE .env - Buffer workflow: `products/signals/backend/temporal/buffer.py` - Grouping workflow: `products/signals/backend/temporal/grouping_v2.py` - Report summary workflow: `products/signals/backend/temporal/summary.py` -- Docker sandbox implementation: `products/tasks/backend/services/docker_sandbox.py` +- Docker sandbox implementation: `products/tasks/backend/logic/services/docker_sandbox.py` - Sandbox Dockerfiles: `products/tasks/backend/sandbox/images/` -- Agent log polling: `products/tasks/backend/services/custom_prompt_internals.py` +- Agent log polling: `products/tasks/backend/logic/services/custom_prompt_internals.py` - Cleanup command: `products/signals/backend/management/commands/cleanup_signals.py` - Management command docs: `products/signals/backend/management/CLAUDE.md` diff --git a/skills/exploring-signals-scouts/references/scout-data-model.md b/skills/exploring-signals-scouts/references/scout-data-model.md index 5d8b9db..4c828f5 100644 --- a/skills/exploring-signals-scouts/references/scout-data-model.md +++ b/skills/exploring-signals-scouts/references/scout-data-model.md @@ -14,7 +14,7 @@ control surface, separate from its instruction body (the `LLMSkill`). | `skill_name` | The `signals-scout-*` skill this config controls. Fixed; one config per skill per team. | | `enabled` | `false` = paused. The coordinator skips disabled scouts entirely. | | `emit` | `false` = **dry-run**: the scout runs and reasons every tick but writes nothing to the inbox. | -| `run_interval_minutes` | Cadence, 10–43200. Default 60 (hourly). The coordinator dispatches when due. | +| `run_interval_minutes` | Cadence, 10–43200. Default 1440 (daily). The coordinator dispatches when due. | | `last_run_at` | When it last fired. `null` = never run. Drives the due-check. | A scout that is `enabled: true, emit: false` is alive and working — it just can't post findings. diff --git a/skills/instrument-error-tracking/references/angular.md b/skills/instrument-error-tracking/references/angular.md index a858ec0..b11c441 100644 --- a/skills/instrument-error-tracking/references/angular.md +++ b/skills/instrument-error-tracking/references/angular.md @@ -65,7 +65,7 @@ this.ngZone.runOutsideAngular(() => { posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2026-01-30', + defaults: '2026-05-30', }); }); } @@ -113,7 +113,7 @@ import posthog from 'posthog-js' posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2025-11-30' + defaults: '2026-05-30' }) bootstrapApplication(AppComponent, appConfig) .catch((err) => console.error(err)); diff --git a/skills/instrument-error-tracking/references/flutter.md b/skills/instrument-error-tracking/references/flutter.md index b2da929..a3e1a88 100644 --- a/skills/instrument-error-tracking/references/flutter.md +++ b/skills/instrument-error-tracking/references/flutter.md @@ -105,7 +105,7 @@ !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group identify setPersonProperties setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags resetGroups onFeatureFlags addFeatureFlagsHandler onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) diff --git a/skills/instrument-error-tracking/references/nextjs.md b/skills/instrument-error-tracking/references/nextjs.md index e3d4522..0cc466f 100644 --- a/skills/instrument-error-tracking/references/nextjs.md +++ b/skills/instrument-error-tracking/references/nextjs.md @@ -65,7 +65,7 @@ import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN!, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` @@ -87,7 +87,7 @@ useEffect(() => { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN as string, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }) }, []) return ( @@ -138,7 +138,7 @@ useEffect(() => { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN as string, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', loaded: (posthog) => { if (process.env.NODE_ENV === 'development') posthog.debug() } diff --git a/skills/instrument-error-tracking/references/nuxt-3-6.md b/skills/instrument-error-tracking/references/nuxt-3-6.md index 53a6d5f..84533f9 100644 --- a/skills/instrument-error-tracking/references/nuxt-3-6.md +++ b/skills/instrument-error-tracking/references/nuxt-3-6.md @@ -50,7 +50,7 @@ public: { posthogPublicKey: '', posthogHost: 'https://us.i.posthog.com', - posthogDefaults: '2026-01-30' + posthogDefaults: '2026-05-30' } } }) diff --git a/skills/instrument-error-tracking/references/react.md b/skills/instrument-error-tracking/references/react.md index b1f9fd8..5d21ace 100644 --- a/skills/instrument-error-tracking/references/react.md +++ b/skills/instrument-error-tracking/references/react.md @@ -65,7 +65,7 @@ import { PostHogProvider } from '@posthog/react' const options = { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', } as const createRoot(document.getElementById('root')).render( diff --git a/skills/instrument-error-tracking/references/svelte.md b/skills/instrument-error-tracking/references/svelte.md index cf1cb54..5470400 100644 --- a/skills/instrument-error-tracking/references/svelte.md +++ b/skills/instrument-error-tracking/references/svelte.md @@ -50,7 +50,7 @@ '', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' } ) } diff --git a/skills/instrument-error-tracking/references/web.md b/skills/instrument-error-tracking/references/web.md index 385be7f..3ea6362 100644 --- a/skills/instrument-error-tracking/references/web.md +++ b/skills/instrument-error-tracking/references/web.md @@ -21,7 +21,7 @@ !function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) ``` @@ -58,7 +58,7 @@ import posthog from 'posthog-js' posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` 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 1cf8b58..5c195bb 100644 --- a/skills/instrument-feature-flags/references/adding-feature-flag-code.md +++ b/skills/instrument-feature-flags/references/adding-feature-flag-code.md @@ -78,7 +78,7 @@ PostHog AI ```javascript posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', flag_keys: ['checkout-flow', 'new-dashboard'], }) ``` @@ -179,7 +179,7 @@ PostHog AI ```javascript posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' feature_flag_request_timeout_ms: 3000 // Time in milliseconds. Default is 3000 (3 seconds). }) ``` @@ -421,7 +421,7 @@ PostHog AI ```javascript posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' feature_flag_request_timeout_ms: 3000 // Time in milliseconds. Default is 3000 (3 seconds). } ) diff --git a/skills/instrument-feature-flags/references/flutter.md b/skills/instrument-feature-flags/references/flutter.md index c57d9a0..384c971 100644 --- a/skills/instrument-feature-flags/references/flutter.md +++ b/skills/instrument-feature-flags/references/flutter.md @@ -105,7 +105,7 @@ !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group identify setPersonProperties setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags resetGroups onFeatureFlags addFeatureFlagsHandler onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) diff --git a/skills/instrument-feature-flags/references/next-js.md b/skills/instrument-feature-flags/references/next-js.md index c84ce2a..6438326 100644 --- a/skills/instrument-feature-flags/references/next-js.md +++ b/skills/instrument-feature-flags/references/next-js.md @@ -82,7 +82,7 @@ PostHog AI import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -92,7 +92,7 @@ posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN!, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -131,7 +131,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-feature-flags/references/react.md b/skills/instrument-feature-flags/references/react.md index 1fcd3c2..76b0add 100644 --- a/skills/instrument-feature-flags/references/react.md +++ b/skills/instrument-feature-flags/references/react.md @@ -65,7 +65,7 @@ import { PostHogProvider } from '@posthog/react' const options = { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', } as const createRoot(document.getElementById('root')).render( diff --git a/skills/instrument-feature-flags/references/web.md b/skills/instrument-feature-flags/references/web.md index 3705800..e722665 100644 --- a/skills/instrument-feature-flags/references/web.md +++ b/skills/instrument-feature-flags/references/web.md @@ -21,7 +21,7 @@ !function(t,e){var o,n,p,r;e.__SV||(window.posthog && window.posthog.__loaded)||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) ``` @@ -58,7 +58,7 @@ import posthog from 'posthog-js' posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` diff --git a/skills/instrument-integration/references/angular.md b/skills/instrument-integration/references/angular.md index e58b2e3..8e05e53 100644 --- a/skills/instrument-integration/references/angular.md +++ b/skills/instrument-integration/references/angular.md @@ -67,7 +67,7 @@ export class PosthogService { this.ngZone.runOutsideAngular(() => { posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2026-01-30', + defaults: '2026-05-30', }); }); } @@ -117,7 +117,7 @@ import { environment } from "./environments/environment"; import posthog from 'posthog-js' posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2026-01-30' + defaults: '2026-05-30' }) bootstrapApplication(AppComponent, appConfig) .catch((err) => console.error(err)); @@ -151,7 +151,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/astro.md b/skills/instrument-integration/references/astro.md index 4b37196..0257d79 100644 --- a/skills/instrument-integration/references/astro.md +++ b/skills/instrument-integration/references/astro.md @@ -39,7 +39,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host:'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` @@ -64,7 +64,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', capture_pageview: 'history_change' }) } @@ -138,7 +138,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/flutter.md b/skills/instrument-integration/references/flutter.md index c7ade4e..7d3706f 100644 --- a/skills/instrument-integration/references/flutter.md +++ b/skills/instrument-integration/references/flutter.md @@ -193,7 +193,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host:'https://us.i.posthog.com', // 'https://us.i.posthog.com' or 'https://eu.i.posthog.com' - defaults: '2026-01-30', + defaults: '2026-05-30', }) diff --git a/skills/instrument-integration/references/js.md b/skills/instrument-integration/references/js.md index c123226..3273d0a 100644 --- a/skills/instrument-integration/references/js.md +++ b/skills/instrument-integration/references/js.md @@ -13,7 +13,7 @@ PostHog AI ```html ``` @@ -90,7 +90,7 @@ PostHog AI import posthog from 'posthog-js' posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` @@ -155,7 +155,7 @@ import "posthog-js/dist/tracing-headers" import "posthog-js/dist/web-vitals" import posthog from 'posthog-js/dist/module.no-external' // All other posthog commands are the same as usual -posthog.init('', { api_host: 'https://us.i.posthog.com', defaults: '2026-01-30' }) +posthog.init('', { api_host: 'https://us.i.posthog.com', defaults: '2026-05-30' }) ``` **Note:** You should ensure if using this option that you always import `posthog-js` from the same module, otherwise multiple bundles could get included. At this time `@posthog/react` does not work with any module import other than the default. @@ -176,7 +176,7 @@ import { } from 'posthog-js/dist/extension-bundles' posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', __extensionClasses: { ...SessionReplayExtensions, ...AnalyticsExtensions, @@ -215,13 +215,13 @@ PostHog AI ```javascript if (!window.location.host.includes('127.0.0.1') && !window.location.host.includes('localhost')) { - posthog.init('', { api_host: 'https://us.i.posthog.com', defaults: '2026-01-30' }) + posthog.init('', { api_host: 'https://us.i.posthog.com', defaults: '2026-05-30' }) } ``` What is the \`defaults\` option? -The `defaults` is a date, such as `2026-01-30`, for a configuration snapshot used as defaults to initialize PostHog. This default is overridden when you explicitly set a value for any of the options. +The `defaults` is a date, such as `2026-05-30`, for a configuration snapshot used as defaults to initialize PostHog. This default is overridden when you explicitly set a value for any of the options. ## Identifying users diff --git a/skills/instrument-integration/references/next-js.md b/skills/instrument-integration/references/next-js.md index c84ce2a..6438326 100644 --- a/skills/instrument-integration/references/next-js.md +++ b/skills/instrument-integration/references/next-js.md @@ -82,7 +82,7 @@ PostHog AI import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -92,7 +92,7 @@ posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN!, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -131,7 +131,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/nuxt-js-3-6.md b/skills/instrument-integration/references/nuxt-js-3-6.md index 06c35ed..56a93ed 100644 --- a/skills/instrument-integration/references/nuxt-js-3-6.md +++ b/skills/instrument-integration/references/nuxt-js-3-6.md @@ -57,7 +57,7 @@ export default defineNuxtConfig({ public: { posthogToken: process.env.NUXT_PUBLIC_POSTHOG_PROJECT_TOKEN || '', posthogHost: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', - posthogDefaults: '2026-01-30', + posthogDefaults: '2026-05-30', }, } }) @@ -134,7 +134,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` @@ -184,7 +184,7 @@ export default defineNuxtConfig({ public: { posthogToken: process.env.NUXT_PUBLIC_POSTHOG_PROJECT_TOKEN || '', posthogHost: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', - posthogDefaults: '2026-01-30', + posthogDefaults: '2026-05-30', } } }) diff --git a/skills/instrument-integration/references/nuxt-js.md b/skills/instrument-integration/references/nuxt-js.md index 50b176d..7844d45 100644 --- a/skills/instrument-integration/references/nuxt-js.md +++ b/skills/instrument-integration/references/nuxt-js.md @@ -168,7 +168,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/php.md b/skills/instrument-integration/references/php.md index 932bfab..72c9017 100644 --- a/skills/instrument-integration/references/php.md +++ b/skills/instrument-integration/references/php.md @@ -422,7 +422,7 @@ PostHog::init( ); ``` -For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). +For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). For distributed or stateless PHP applications, use `flag_definition_cache_provider` to share flag definitions across workers or requests. See [local evaluation in distributed environments](/docs/feature-flags/local-evaluation/distributed-environments?tab=PHP.md). ### Experiments (A/B tests) @@ -584,6 +584,7 @@ All possible options below: | 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. | +| flag_definition_cache_providerType: PostHog\\FlagDefinitionCacheProviderDefault: null | Provider for distributed local-evaluation flag definition caching. See [local evaluation in distributed environments](/docs/feature-flags/local-evaluation/distributed-environments?tab=PHP.md). | | 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, fork_curl, and noop. Determines what transport option to use for analytics capture. | | debugType: BooleanDefault: false | Output debug logs or not. | @@ -604,6 +605,18 @@ All possible options below: | 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. | +## Flushing and shutting down + +Call `PostHog::flush()` to send queued events without closing resources. When a script or long-running worker stops, call `PostHog::shutdown()` instead; it flushes queued events and releases resources held by providers such as `flag_definition_cache_provider`. + +PHP + +PostHog AI + +```php +PostHog::shutdown(); +``` + ## Debug mode PHP diff --git a/skills/instrument-integration/references/posthog-js.md b/skills/instrument-integration/references/posthog-js.md index 02a803b..29a30c8 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.391.6 +**SDK Version:** 1.392.0 Posthog-js allows you to automatically capture usage and send events to PostHog. diff --git a/skills/instrument-integration/references/posthog-python.md b/skills/instrument-integration/references/posthog-python.md index 6b829b5..89278d0 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.20.1 +**SDK Version:** 7.20.2 Integrate PostHog into any python application. @@ -61,6 +61,7 @@ Initialize a new PostHog client instance. - **`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. +- **`code_variables_mask_url_credentials`** (`any`) - Scrub credentials embedded in URLs/DSNs (e.g. ``user:pass@host``) from captured code variables, regardless of the surrounding variable name. Defaults to True. - **`in_app_modules`** (`UnionType[list[str], any]`) - Module/package prefixes treated as in-app frames in captured exceptions. - **`enable_exception_autocapture_rate_limiting`** (`bool`) - Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. - **`exception_autocapture_bucket_size`** (`int`) - Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). @@ -94,13 +95,13 @@ Create an alias between two distinct IDs. - **`previous_id?`** (`str`) - The previous distinct ID. - **`distinct_id?`** (`str`) - The new distinct ID to alias to. -- **`timestamp`** (`any`) - The timestamp of the event. -- **`uuid`** (`any`) - A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this event. +- **`timestamp`** (`datetime`) - The timestamp of the event. +- **`uuid?`** (`str`) - A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this event. ### Returns -- `None` +- `Optional[str]` ### Examples @@ -287,7 +288,7 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat ### Parameters - **`distinct_id`** (`Number`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. -- **`groups?`** (`dict[str, str]`) - Mapping of group type to group key. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. - **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If True, never fall back to remote evaluation — flags that can't be evaluated locally are simply omitted from the snapshot. @@ -321,19 +322,19 @@ Check if a feature flag is enabled for a user. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns -- `None` +- `Optional[bool]` ### Examples @@ -367,12 +368,12 @@ Get all feature flags for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -396,12 +397,12 @@ Get all feature flags and their payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -425,14 +426,14 @@ Get multivariate feature flag value for a user. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns @@ -459,20 +460,20 @@ Get the payload for a feature flag. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. - **`match_value`** (`bool`) - The specific flag value to get payload for. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Deprecated. Use get_feature_flag() instead if you need events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns -- `None` +- `Optional[object]` ### Examples @@ -495,11 +496,11 @@ Get feature flags and payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -523,11 +524,11 @@ Get feature flag payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -551,11 +552,11 @@ Get feature flag variants for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -574,10 +575,10 @@ Get feature flags decision. ### Parameters - **`distinct_id`** (`Number`) - The distinct ID of the user. -- **`groups?`** (`dict`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -660,14 +661,14 @@ Get a FeatureFlagResult object which contains the flag result and payload for a ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns @@ -861,15 +862,15 @@ To marry up whatever a user does before they sign up or log in with what they do ### Parameters -- **`previous_id?`** (`any`) - The unique ID of the user before -- **`distinct_id?`** (`any`) - The current unique id -- **`timestamp`** (`any`) - Optional timestamp for the event -- **`uuid`** (`any`) - Optional UUID for the event -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup +- **`previous_id?`** (`str`) - The unique ID of the user before +- **`distinct_id?`** (`str`) - The current unique id +- **`timestamp?`** (`datetime`) - Optional timestamp for the event +- **`uuid?`** (`str`) - Optional UUID for the event +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup ### Returns -- `None` +- `Optional[str]` ### Examples @@ -889,17 +890,17 @@ Set properties on a group. ### Parameters -- **`group_type?`** (`any`) - Type of your group -- **`group_key?`** (`any`) - Unique identifier of the group -- **`properties`** (`any`) - Properties to set on the group -- **`timestamp`** (`any`) - Optional timestamp for the event -- **`uuid`** (`any`) - Optional UUID for the event -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`distinct_id`** (`any`) - Optional distinct ID of the user performing the action +- **`group_type?`** (`str`) - Type of your group +- **`group_key?`** (`str`) - Unique identifier of the group +- **`properties?`** (`dict[str, Any]`) - Properties to set on the group +- **`timestamp?`** (`datetime`) - Optional timestamp for the event +- **`uuid?`** (`str`) - Optional UUID for the event +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`distinct_id`** (`Number`) - Optional distinct ID of the user performing the action ### Returns -- `None` +- `Optional[str]` ### Examples @@ -1105,14 +1106,14 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat ### Parameters -- **`distinct_id`** (`any`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. -- **`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. +- **`distinct_id`** (`Number`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. -- **`flag_keys`** (`any`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. -- **`device_id`** (`any`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`flag_keys?`** (`list[str]`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. +- **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns @@ -1142,19 +1143,19 @@ You can call `posthog.load_feature_flags()` before to make sure you're not doing ### Parameters -- **`key?`** (`any`) - The feature flag key -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties +- **`key?`** (`str`) - The feature flag key +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties - **`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`) - Optional device ID override for experience-continuity flags +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags ### Returns -- `None` +- `Optional[bool]` ### Examples @@ -1203,18 +1204,18 @@ Flags are key-value pairs where the key is the flag key and the value is the fla ### Parameters -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties - **`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 if None) +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags +- **`flag_keys_to_evaluate?`** (`list[str]`) - Optional list of flag keys to evaluate (evaluates all if None) ### Returns -- `Optional[dict[str, FeatureFlag]]` +- `Optional[dict[str, Union[bool, str]]]` ### Examples @@ -1234,14 +1235,14 @@ 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. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. +- **`flag_keys_to_evaluate?`** (`list[str]`) - Optional list of flag keys to evaluate. Evaluates all flags when omitted. ### Returns @@ -1261,19 +1262,19 @@ Get feature flag variant for users. Used with experiments. ### Parameters -- **`key?`** (`any`) - The feature flag key -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping from group type to group key -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties in format { group_type_name: { group_properties } } +- **`key?`** (`str`) - The feature flag key +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping from group type to group key +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties in format { group_type_name: { group_properties } } - **`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`) - Optional device ID override for experience-continuity flags +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags ### Returns -- `Optional[FeatureFlag]` +- `Union[bool, str, any]` ### Examples @@ -1295,20 +1296,20 @@ Get the payload associated with a feature flag value. Deprecated for new code. ### 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. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`match_value`** (`bool`) - Optional flag value to use when selecting a payload. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. ### Returns -- `Optional[str]` +- `Optional[object]` --- @@ -1404,19 +1405,19 @@ Get a FeatureFlagResult object which contains the flag result and payload. This ### Parameters -- **`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. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. ### Returns -- `None` +- `Optional[FeatureFlagResult]` --- @@ -1428,7 +1429,23 @@ Get the payload for a remote config feature flag. ### Parameters -- **`key?`** (`any`) - The key of the feature flag +- **`key?`** (`str`) - The key of the feature flag + +### Returns + +- `None` + +--- + +#### set_code_variables_mask_url_credentials_context() + +**Release Tag:** public + +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from captured code variables for the current context. + +### Parameters + +- **`enabled?`** (`bool`) ### Returns @@ -1528,7 +1545,7 @@ Override code-variable ignore patterns for exceptions in the current context. ### Parameters -- **`ignore_patterns?`** (`list`) - Variable-name patterns that should be omitted entirely when code variables are captured. +- **`ignore_patterns?`** (`list[str]`) - Variable-name patterns that should be omitted entirely when code variables are captured. ### Returns @@ -1544,7 +1561,7 @@ Override code-variable mask patterns for exceptions in the current context. ### Parameters -- **`mask_patterns?`** (`list`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. +- **`mask_patterns?`** (`list[str]`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. ### Returns diff --git a/skills/instrument-integration/references/react-native.md b/skills/instrument-integration/references/react-native.md index 9038fe8..bbda393 100644 --- a/skills/instrument-integration/references/react-native.md +++ b/skills/instrument-integration/references/react-native.md @@ -136,7 +136,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/react-router-v6.md b/skills/instrument-integration/references/react-router-v6.md index cf3a3d3..7d97f6e 100644 --- a/skills/instrument-integration/references/react-router-v6.md +++ b/skills/instrument-integration/references/react-router-v6.md @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V6. If you're u // Initialize PostHog posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const root = document.getElementById("root"); ReactDOM.createRoot(root).render( @@ -343,7 +343,7 @@ This guide walks you through setting up PostHog for React Router V6. If you're u ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 83cb29a..1d40658 100644 --- a/skills/instrument-integration/references/react-router-v7-data-mode.md +++ b/skills/instrument-integration/references/react-router-v7-data-mode.md @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V7 in data mode import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const router = createBrowserRouter([...]); createRoot(document.getElementById("root")!).render( @@ -331,7 +331,7 @@ This guide walks you through setting up PostHog for React Router V7 in data mode ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 857acb4..ee2ad36 100644 --- a/skills/instrument-integration/references/react-router-v7-declarative-mode.md +++ b/skills/instrument-integration/references/react-router-v7-declarative-mode.md @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V7 in declarati // Initialize PostHog posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const root = document.getElementById("root"); ReactDOM.createRoot(root).render( @@ -343,7 +343,7 @@ This guide walks you through setting up PostHog for React Router V7 in declarati ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 0901bfe..64412f4 100644 --- a/skills/instrument-integration/references/react-router-v7-framework-mode.md +++ b/skills/instrument-integration/references/react-router-v7-framework-mode.md @@ -89,7 +89,7 @@ This guide walks you through setting up PostHog for React Router V7 in framework import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, 'localhost' ], }); startTransition(() => { diff --git a/skills/instrument-integration/references/react.md b/skills/instrument-integration/references/react.md index e118a55..3d8182a 100644 --- a/skills/instrument-integration/references/react.md +++ b/skills/instrument-integration/references/react.md @@ -83,7 +83,7 @@ import posthog from 'posthog-js'; import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); createRoot(document.getElementById('root')).render( @@ -122,7 +122,7 @@ import posthog from 'posthog-js'; import { PostHogProvider} from '@posthog/react' posthog.init(process.env.REACT_APP_PUBLIC_POSTHOG_PROJECT_TOKEN, { api_host: process.env.REACT_APP_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', // Optional: send PostHog session/user context to your backend tracing_headers: ['api.example.com'], }); @@ -503,7 +503,7 @@ PostHog AI ```javascript posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' feature_flag_request_timeout_ms: 3000 // Time in milliseconds. Default is 3000 (3 seconds). } ) diff --git a/skills/instrument-integration/references/svelte.md b/skills/instrument-integration/references/svelte.md index 555219c..a03194d 100644 --- a/skills/instrument-integration/references/svelte.md +++ b/skills/instrument-integration/references/svelte.md @@ -57,7 +57,7 @@ export const load = async () => { if (browser) { posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) } return @@ -88,7 +88,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-integration/references/tanstack-start.md b/skills/instrument-integration/references/tanstack-start.md index 0504850..2819556 100644 --- a/skills/instrument-integration/references/tanstack-start.md +++ b/skills/instrument-integration/references/tanstack-start.md @@ -55,7 +55,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { apiKey="" options={{ api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', capture_exceptions: true }} > diff --git a/skills/instrument-integration/references/vue-js.md b/skills/instrument-integration/references/vue-js.md index ad8d832..e8e4412 100644 --- a/skills/instrument-integration/references/vue-js.md +++ b/skills/instrument-integration/references/vue-js.md @@ -65,7 +65,7 @@ import posthog from "posthog-js"; const app = createApp(App); posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN || '', { api_host: import.meta.env.VITE_POSTHOG_HOST || 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }); app.use(createPinia()) app.use(router) @@ -108,7 +108,7 @@ export default { install(Vue) { posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) Vue.prototype.$posthog = posthog } @@ -278,7 +278,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-logs/references/flutter.md b/skills/instrument-logs/references/flutter.md index 93e9afe..bbb2eb0 100644 --- a/skills/instrument-logs/references/flutter.md +++ b/skills/instrument-logs/references/flutter.md @@ -201,7 +201,7 @@ The PostHog Flutter SDK has built-in support for capturing structured Logs from !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host:'https://us.i.posthog.com', // 'https://us.i.posthog.com' or 'https://eu.i.posthog.com' - defaults: '2026-01-30', + defaults: '2026-05-30', }) diff --git a/skills/instrument-product-analytics/references/angular.md b/skills/instrument-product-analytics/references/angular.md index e58b2e3..8e05e53 100644 --- a/skills/instrument-product-analytics/references/angular.md +++ b/skills/instrument-product-analytics/references/angular.md @@ -67,7 +67,7 @@ export class PosthogService { this.ngZone.runOutsideAngular(() => { posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2026-01-30', + defaults: '2026-05-30', }); }); } @@ -117,7 +117,7 @@ import { environment } from "./environments/environment"; import posthog from 'posthog-js' posthog.init(environment.posthogKey, { api_host: environment.posthogHost, - defaults: '2026-01-30' + defaults: '2026-05-30' }) bootstrapApplication(AppComponent, appConfig) .catch((err) => console.error(err)); @@ -151,7 +151,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/astro.md b/skills/instrument-product-analytics/references/astro.md index 4b37196..0257d79 100644 --- a/skills/instrument-product-analytics/references/astro.md +++ b/skills/instrument-product-analytics/references/astro.md @@ -39,7 +39,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host:'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) ``` @@ -64,7 +64,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', capture_pageview: 'history_change' }) } @@ -138,7 +138,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/flutter.md b/skills/instrument-product-analytics/references/flutter.md index c7ade4e..7d3706f 100644 --- a/skills/instrument-product-analytics/references/flutter.md +++ b/skills/instrument-product-analytics/references/flutter.md @@ -193,7 +193,7 @@ PostHog AI !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(" "),n=0;n', { api_host:'https://us.i.posthog.com', // 'https://us.i.posthog.com' or 'https://eu.i.posthog.com' - defaults: '2026-01-30', + defaults: '2026-05-30', }) diff --git a/skills/instrument-product-analytics/references/next-js.md b/skills/instrument-product-analytics/references/next-js.md index c84ce2a..6438326 100644 --- a/skills/instrument-product-analytics/references/next-js.md +++ b/skills/instrument-product-analytics/references/next-js.md @@ -82,7 +82,7 @@ PostHog AI import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -92,7 +92,7 @@ posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, { import posthog from 'posthog-js' posthog.init(process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN!, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - defaults: '2026-01-30' + defaults: '2026-05-30' }); ``` @@ -131,7 +131,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/nuxt-js-3-6.md b/skills/instrument-product-analytics/references/nuxt-js-3-6.md index 06c35ed..56a93ed 100644 --- a/skills/instrument-product-analytics/references/nuxt-js-3-6.md +++ b/skills/instrument-product-analytics/references/nuxt-js-3-6.md @@ -57,7 +57,7 @@ export default defineNuxtConfig({ public: { posthogToken: process.env.NUXT_PUBLIC_POSTHOG_PROJECT_TOKEN || '', posthogHost: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', - posthogDefaults: '2026-01-30', + posthogDefaults: '2026-05-30', }, } }) @@ -134,7 +134,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` @@ -184,7 +184,7 @@ export default defineNuxtConfig({ public: { posthogToken: process.env.NUXT_PUBLIC_POSTHOG_PROJECT_TOKEN || '', posthogHost: process.env.NUXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', - posthogDefaults: '2026-01-30', + posthogDefaults: '2026-05-30', } } }) diff --git a/skills/instrument-product-analytics/references/nuxt-js.md b/skills/instrument-product-analytics/references/nuxt-js.md index 50b176d..7844d45 100644 --- a/skills/instrument-product-analytics/references/nuxt-js.md +++ b/skills/instrument-product-analytics/references/nuxt-js.md @@ -168,7 +168,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/php.md b/skills/instrument-product-analytics/references/php.md index 932bfab..72c9017 100644 --- a/skills/instrument-product-analytics/references/php.md +++ b/skills/instrument-product-analytics/references/php.md @@ -422,7 +422,7 @@ PostHog::init( ); ``` -For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). +For details on how to implement local evaluation, see our [local evaluation guide](/docs/feature-flags/local-evaluation.md). For distributed or stateless PHP applications, use `flag_definition_cache_provider` to share flag definitions across workers or requests. See [local evaluation in distributed environments](/docs/feature-flags/local-evaluation/distributed-environments?tab=PHP.md). ### Experiments (A/B tests) @@ -584,6 +584,7 @@ All possible options below: | 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. | +| flag_definition_cache_providerType: PostHog\\FlagDefinitionCacheProviderDefault: null | Provider for distributed local-evaluation flag definition caching. See [local evaluation in distributed environments](/docs/feature-flags/local-evaluation/distributed-environments?tab=PHP.md). | | 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, fork_curl, and noop. Determines what transport option to use for analytics capture. | | debugType: BooleanDefault: false | Output debug logs or not. | @@ -604,6 +605,18 @@ All possible options below: | 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. | +## Flushing and shutting down + +Call `PostHog::flush()` to send queued events without closing resources. When a script or long-running worker stops, call `PostHog::shutdown()` instead; it flushes queued events and releases resources held by providers such as `flag_definition_cache_provider`. + +PHP + +PostHog AI + +```php +PostHog::shutdown(); +``` + ## Debug mode PHP diff --git a/skills/instrument-product-analytics/references/posthog-python.md b/skills/instrument-product-analytics/references/posthog-python.md index 6b829b5..89278d0 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.20.1 +**SDK Version:** 7.20.2 Integrate PostHog into any python application. @@ -61,6 +61,7 @@ Initialize a new PostHog client instance. - **`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. +- **`code_variables_mask_url_credentials`** (`any`) - Scrub credentials embedded in URLs/DSNs (e.g. ``user:pass@host``) from captured code variables, regardless of the surrounding variable name. Defaults to True. - **`in_app_modules`** (`UnionType[list[str], any]`) - Module/package prefixes treated as in-app frames in captured exceptions. - **`enable_exception_autocapture_rate_limiting`** (`bool`) - Rate limit autocaptured exceptions client-side with a token bucket per exception type. Disabled by default. - **`exception_autocapture_bucket_size`** (`int`) - Maximum burst of autocaptured exceptions allowed per exception type (token bucket size, clamped to 0-100). @@ -94,13 +95,13 @@ Create an alias between two distinct IDs. - **`previous_id?`** (`str`) - The previous distinct ID. - **`distinct_id?`** (`str`) - The new distinct ID to alias to. -- **`timestamp`** (`any`) - The timestamp of the event. -- **`uuid`** (`any`) - A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this event. +- **`timestamp`** (`datetime`) - The timestamp of the event. +- **`uuid?`** (`str`) - A unique identifier for the event. If provided, it must be a valid UUID string or uuid.UUID instance; invalid values are ignored and replaced with a newly generated UUID. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this event. ### Returns -- `None` +- `Optional[str]` ### Examples @@ -287,7 +288,7 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat ### Parameters - **`distinct_id`** (`Number`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. -- **`groups?`** (`dict[str, str]`) - Mapping of group type to group key. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. - **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. - **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If True, never fall back to remote evaluation — flags that can't be evaluated locally are simply omitted from the snapshot. @@ -321,19 +322,19 @@ Check if a feature flag is enabled for a user. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns -- `None` +- `Optional[bool]` ### Examples @@ -367,12 +368,12 @@ Get all feature flags for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -396,12 +397,12 @@ Get all feature flags and their payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -425,14 +426,14 @@ Get multivariate feature flag value for a user. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns @@ -459,20 +460,20 @@ Get the payload for a feature flag. ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. - **`match_value`** (`bool`) - The specific flag value to get payload for. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Deprecated. Use get_feature_flag() instead if you need events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns -- `None` +- `Optional[object]` ### Examples @@ -495,11 +496,11 @@ Get feature flags and payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -523,11 +524,11 @@ Get feature flag payloads for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -551,11 +552,11 @@ Get feature flag variants for a user. ### Parameters -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -574,10 +575,10 @@ Get feature flags decision. ### Parameters - **`distinct_id`** (`Number`) - The distinct ID of the user. -- **`groups?`** (`dict`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`flag_keys_to_evaluate?`** (`list[str]`) - A list of specific flag keys to evaluate. If provided, only these flags will be evaluated, improving performance. - **`device_id?`** (`str`) - The device ID for this request. @@ -660,14 +661,14 @@ Get a FeatureFlagResult object which contains the flag result and payload for a ### Parameters -- **`key?`** (`any`) - The feature flag key. -- **`distinct_id?`** (`any`) - The distinct ID of the user. -- **`groups`** (`any`) - A dictionary of group information. -- **`person_properties`** (`any`) - A dictionary of person properties. -- **`group_properties`** (`any`) - A dictionary of group properties. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The distinct ID of the user. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - A dictionary of group information. +- **`person_properties?`** (`dict[str, Any]`) - A dictionary of person properties. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - A dictionary of group properties. - **`only_evaluate_locally`** (`bool`) - Whether to only evaluate locally. - **`send_feature_flag_events`** (`bool`) - Whether to send feature flag events. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP for this request. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP for this request. - **`device_id?`** (`str`) - The device ID for this request. ### Returns @@ -861,15 +862,15 @@ To marry up whatever a user does before they sign up or log in with what they do ### Parameters -- **`previous_id?`** (`any`) - The unique ID of the user before -- **`distinct_id?`** (`any`) - The current unique id -- **`timestamp`** (`any`) - Optional timestamp for the event -- **`uuid`** (`any`) - Optional UUID for the event -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup +- **`previous_id?`** (`str`) - The unique ID of the user before +- **`distinct_id?`** (`str`) - The current unique id +- **`timestamp?`** (`datetime`) - Optional timestamp for the event +- **`uuid?`** (`str`) - Optional UUID for the event +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup ### Returns -- `None` +- `Optional[str]` ### Examples @@ -889,17 +890,17 @@ Set properties on a group. ### Parameters -- **`group_type?`** (`any`) - Type of your group -- **`group_key?`** (`any`) - Unique identifier of the group -- **`properties`** (`any`) - Properties to set on the group -- **`timestamp`** (`any`) - Optional timestamp for the event -- **`uuid`** (`any`) - Optional UUID for the event -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup -- **`distinct_id`** (`any`) - Optional distinct ID of the user performing the action +- **`group_type?`** (`str`) - Type of your group +- **`group_key?`** (`str`) - Unique identifier of the group +- **`properties?`** (`dict[str, Any]`) - Properties to set on the group +- **`timestamp?`** (`datetime`) - Optional timestamp for the event +- **`uuid?`** (`str`) - Optional UUID for the event +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`distinct_id`** (`Number`) - Optional distinct ID of the user performing the action ### Returns -- `None` +- `Optional[str]` ### Examples @@ -1105,14 +1106,14 @@ Evaluate all feature flags for a user in a single call and return a :class:`Feat ### Parameters -- **`distinct_id`** (`any`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. -- **`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. +- **`distinct_id`** (`Number`) - The user's distinct ID. If ``None``, falls back to the context distinct_id. If still unresolvable, returns an empty snapshot. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - If ``True``, never fall back to remote evaluation. -- **`disable_geoip`** (`any`) - Whether to disable GeoIP lookup. -- **`flag_keys`** (`any`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. -- **`device_id`** (`any`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`flag_keys?`** (`list[str]`) - Optional list of flag keys. When provided, only these flags are evaluated — the underlying ``/flags`` request asks the server for just this subset, which makes the response smaller and the request cheaper. Use this when you only need a handful of flags out of many. +- **`device_id?`** (`str`) - Optional device ID override. If not provided, falls back to the context device_id (which may be set via tracing headers). Used by experience-continuity flags to match users across distinct_id changes. ### Returns @@ -1142,19 +1143,19 @@ You can call `posthog.load_feature_flags()` before to make sure you're not doing ### Parameters -- **`key?`** (`any`) - The feature flag key -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties +- **`key?`** (`str`) - The feature flag key +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties - **`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`) - Optional device ID override for experience-continuity flags +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags ### Returns -- `None` +- `Optional[bool]` ### Examples @@ -1203,18 +1204,18 @@ Flags are key-value pairs where the key is the flag key and the value is the fla ### Parameters -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties - **`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 if None) +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags +- **`flag_keys_to_evaluate?`** (`list[str]`) - Optional list of flag keys to evaluate (evaluates all if None) ### Returns -- `Optional[dict[str, FeatureFlag]]` +- `Optional[dict[str, Union[bool, str]]]` ### Examples @@ -1234,14 +1235,14 @@ 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. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. +- **`flag_keys_to_evaluate?`** (`list[str]`) - Optional list of flag keys to evaluate. Evaluates all flags when omitted. ### Returns @@ -1261,19 +1262,19 @@ Get feature flag variant for users. Used with experiments. ### Parameters -- **`key?`** (`any`) - The feature flag key -- **`distinct_id?`** (`any`) - The user's distinct ID -- **`groups`** (`any`) - Groups mapping from group type to group key -- **`person_properties`** (`any`) - Person properties -- **`group_properties`** (`any`) - Group properties in format { group_type_name: { group_properties } } +- **`key?`** (`str`) - The feature flag key +- **`distinct_id?`** (`Number`) - The user's distinct ID +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Groups mapping from group type to group key +- **`person_properties?`** (`dict[str, Any]`) - Person properties +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties in format { group_type_name: { group_properties } } - **`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`) - Optional device ID override for experience-continuity flags +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags ### Returns -- `Optional[FeatureFlag]` +- `Union[bool, str, any]` ### Examples @@ -1295,20 +1296,20 @@ Get the payload associated with a feature flag value. Deprecated for new code. ### 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. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`match_value`** (`bool`) - Optional flag value to use when selecting a payload. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. ### Returns -- `Optional[str]` +- `Optional[object]` --- @@ -1404,19 +1405,19 @@ Get a FeatureFlagResult object which contains the flag result and payload. This ### Parameters -- **`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. +- **`key?`** (`str`) - The feature flag key. +- **`distinct_id?`** (`Number`) - The user's distinct ID. +- **`groups?`** (`Mapping[str, Union[str, int]]`) - Mapping of group type to group key. +- **`person_properties?`** (`dict[str, Any]`) - Person properties to use for evaluation. +- **`group_properties?`** (`dict[str, dict[str, Any]]`) - Group properties keyed by group type. - **`only_evaluate_locally`** (`bool`) - 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. +- **`disable_geoip?`** (`bool`) - Whether to disable GeoIP lookup. +- **`device_id?`** (`str`) - Optional device ID override for experience-continuity flags. ### Returns -- `None` +- `Optional[FeatureFlagResult]` --- @@ -1428,7 +1429,23 @@ Get the payload for a remote config feature flag. ### Parameters -- **`key?`** (`any`) - The key of the feature flag +- **`key?`** (`str`) - The key of the feature flag + +### Returns + +- `None` + +--- + +#### set_code_variables_mask_url_credentials_context() + +**Release Tag:** public + +Whether to scrub credentials embedded in URLs/DSNs (e.g. user:pass@host) from captured code variables for the current context. + +### Parameters + +- **`enabled?`** (`bool`) ### Returns @@ -1528,7 +1545,7 @@ Override code-variable ignore patterns for exceptions in the current context. ### Parameters -- **`ignore_patterns?`** (`list`) - Variable-name patterns that should be omitted entirely when code variables are captured. +- **`ignore_patterns?`** (`list[str]`) - Variable-name patterns that should be omitted entirely when code variables are captured. ### Returns @@ -1544,7 +1561,7 @@ Override code-variable mask patterns for exceptions in the current context. ### Parameters -- **`mask_patterns?`** (`list`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. +- **`mask_patterns?`** (`list[str]`) - Variable-name patterns whose values should be replaced with ``***`` when code variables are captured. ### Returns diff --git a/skills/instrument-product-analytics/references/react-native.md b/skills/instrument-product-analytics/references/react-native.md index 9038fe8..bbda393 100644 --- a/skills/instrument-product-analytics/references/react-native.md +++ b/skills/instrument-product-analytics/references/react-native.md @@ -136,7 +136,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/react-router-v6.md b/skills/instrument-product-analytics/references/react-router-v6.md index cf3a3d3..7d97f6e 100644 --- a/skills/instrument-product-analytics/references/react-router-v6.md +++ b/skills/instrument-product-analytics/references/react-router-v6.md @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V6. If you're u // Initialize PostHog posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const root = document.getElementById("root"); ReactDOM.createRoot(root).render( @@ -343,7 +343,7 @@ This guide walks you through setting up PostHog for React Router V6. If you're u ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 83cb29a..1d40658 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 @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V7 in data mode import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const router = createBrowserRouter([...]); createRoot(document.getElementById("root")!).render( @@ -331,7 +331,7 @@ This guide walks you through setting up PostHog for React Router V7 in data mode ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 857acb4..ee2ad36 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 @@ -74,7 +74,7 @@ This guide walks you through setting up PostHog for React Router V7 in declarati // Initialize PostHog posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', }); const root = document.getElementById("root"); ReactDOM.createRoot(root).render( @@ -343,7 +343,7 @@ This guide walks you through setting up PostHog for React Router V7 in declarati ```jsx posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, '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 0901bfe..64412f4 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 @@ -89,7 +89,7 @@ This guide walks you through setting up PostHog for React Router V7 in framework import { PostHogProvider } from '@posthog/react' posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN, { api_host: import.meta.env.VITE_POSTHOG_HOST, - defaults: '2026-01-30', + defaults: '2026-05-30', tracing_headers: [ window.location.hostname, 'localhost' ], }); startTransition(() => { diff --git a/skills/instrument-product-analytics/references/svelte.md b/skills/instrument-product-analytics/references/svelte.md index 555219c..a03194d 100644 --- a/skills/instrument-product-analytics/references/svelte.md +++ b/skills/instrument-product-analytics/references/svelte.md @@ -57,7 +57,7 @@ export const load = async () => { if (browser) { posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }) } return @@ -88,7 +88,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/instrument-product-analytics/references/tanstack-start.md b/skills/instrument-product-analytics/references/tanstack-start.md index 0504850..2819556 100644 --- a/skills/instrument-product-analytics/references/tanstack-start.md +++ b/skills/instrument-product-analytics/references/tanstack-start.md @@ -55,7 +55,7 @@ function RootDocument({ children }: { children: React.ReactNode }) { apiKey="" options={{ api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', capture_exceptions: true }} > diff --git a/skills/instrument-product-analytics/references/vue-js.md b/skills/instrument-product-analytics/references/vue-js.md index ad8d832..e8e4412 100644 --- a/skills/instrument-product-analytics/references/vue-js.md +++ b/skills/instrument-product-analytics/references/vue-js.md @@ -65,7 +65,7 @@ import posthog from "posthog-js"; const app = createApp(App); posthog.init(import.meta.env.VITE_POSTHOG_PROJECT_TOKEN || '', { api_host: import.meta.env.VITE_POSTHOG_HOST || 'https://us.i.posthog.com', - defaults: '2026-01-30', + defaults: '2026-05-30', }); app.use(createPinia()) app.use(router) @@ -108,7 +108,7 @@ export default { install(Vue) { posthog.init('', { api_host: 'https://us.i.posthog.com', - defaults: '2026-01-30' + defaults: '2026-05-30' }) Vue.prototype.$posthog = posthog } @@ -278,7 +278,7 @@ This makes it possible to track users across their entire journey (e.g. from vis Add IPs to Firewall/WAF allowlists (recommended) -For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog’s requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. +For certain features like [heatmaps](/docs/toolbar/heatmaps.md), your Web Application Firewall (WAF) may be blocking PostHog's requests to your site. Add these IP addresses to your WAF allowlist or rules to let PostHog access your site. **EU**: `3.75.65.221`, `18.197.246.42`, `3.120.223.253` diff --git a/skills/querying-posthog-data/references/example-error-tracking.md b/skills/querying-posthog-data/references/example-error-tracking.md index def2749..bbef325 100644 --- a/skills/querying-posthog-data/references/example-error-tracking.md +++ b/skills/querying-posthog-data/references/example-error-tracking.md @@ -16,7 +16,6 @@ SELECT uniqMerge(ev.sessions_state) AS sessions, uniqMerge(ev.users_state) AS users, sumForEach(arrayMap(i -> if(equals(ev.bin_idx, i), ev.occ, _toUInt64(0)), range(0, 20))) AS volumeRange, - argMinMerge(ev.first_event_uuid_state) AS first_event_uuid, argMaxMerge(ev.library_state) AS library FROM (SELECT @@ -25,15 +24,14 @@ FROM argMaxState(properties.$exception_functions.-1, timestamp) AS function_state, argMaxState(properties.$exception_sources.-1, timestamp) AS source_state, argMaxState(properties.$lib, timestamp) AS library_state, - least(19, intDiv(dateDiff('seconds', toDateTime(toDateTime('2026-06-21 07:09:26.002999')), timestamp), greatest(1, intDiv(dateDiff('seconds', toDateTime(toDateTime('2026-06-21 07:09:26.002999')), toDateTime(toDateTime('2026-06-22 07:09:26.004646'))), 20)))) AS bin_idx, + least(19, intDiv(dateDiff('seconds', toDateTime(toDateTime('2026-06-22 04:06:57.168130')), timestamp), greatest(1, intDiv(dateDiff('seconds', toDateTime(toDateTime('2026-06-22 04:06:57.168130')), toDateTime(toDateTime('2026-06-23 04:06:57.169452'))), 20)))) AS bin_idx, count() AS occ, uniqState(nullIf(e.$session_id, '')) AS sessions_state, - uniqState(coalesce(nullIf(toString(e.person_id), '00000000-0000-0000-0000-000000000000'), e.distinct_id)) AS users_state, - argMinState(e.uuid, e.timestamp) AS first_event_uuid_state + uniqState(coalesce(nullIf(toString(e.person_id), '00000000-0000-0000-0000-000000000000'), e.distinct_id)) AS users_state FROM events AS e WHERE - and(equals(e.event, '$exception'), isNotNull(e.properties.$exception_fingerprint), true, greaterOrEquals(e.timestamp, toDateTime(toDateTime('2026-06-21 07:09:26.002999'))), lessOrEquals(e.timestamp, toDateTime(toDateTime('2026-06-22 07:09:26.004646'))), or(greater(position(lower(e.properties.$exception_types), lower('constant')), 0), greater(position(lower(e.properties.$exception_values), lower('constant')), 0), greater(position(lower(e.properties.$exception_sources), lower('constant')), 0), greater(position(lower(e.properties.$exception_functions), lower('constant')), 0), greater(position(lower(e.properties.email), lower('constant')), 0), greater(position(lower(e.person.properties.email), lower('constant')), 0)), equals(properties.tag, 'max_ai')) + and(equals(e.event, '$exception'), isNotNull(e.properties.$exception_fingerprint), true, greaterOrEquals(e.timestamp, toDateTime(toDateTime('2026-06-22 04:06:57.168130'))), lessOrEquals(e.timestamp, toDateTime(toDateTime('2026-06-23 04:06:57.169452'))), or(greater(position(lower(e.properties.$exception_types), lower('constant')), 0), greater(position(lower(e.properties.$exception_values), lower('constant')), 0), greater(position(lower(e.properties.$exception_sources), lower('constant')), 0), greater(position(lower(e.properties.$exception_functions), lower('constant')), 0), greater(position(lower(e.properties.email), lower('constant')), 0), greater(position(lower(e.person.properties.email), lower('constant')), 0)), equals(properties.tag, 'max_ai')) GROUP BY fp_hash, bin_idx) AS ev diff --git a/skills/querying-posthog-data/references/example-logs.md b/skills/querying-posthog-data/references/example-logs.md index c2df0eb..8fbe49f 100644 --- a/skills/querying-posthog-data/references/example-logs.md +++ b/skills/querying-posthog-data/references/example-logs.md @@ -31,7 +31,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-06-21 07:09:28.635157')), 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-06-22 04:06:59.298833')), 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 cc173ce..2c4adfd 100644 --- a/skills/querying-posthog-data/references/example-session-replay.md +++ b/skills/querying-posthog-data/references/example-session-replay.md @@ -19,18 +19,18 @@ 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-06-22 07:09:29.610005'), expiry_time) AS recording_ttl, - greaterOrEquals(max(s._timestamp), toDateTime('2026-06-22 07:04:29.609141')) AS ongoing, + date_diff('DAY', toDateTime('2026-06-23 04:07:00.084762'), expiry_time) AS recording_ttl, + greaterOrEquals(max(s._timestamp), toDateTime('2026-06-23 04:02:00.084113')) 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, coalesce(max(s.surfacing_score), 0.36) AS surfacing_score FROM raw_session_replay_events AS s WHERE - and(greaterOrEquals(s.min_first_timestamp, toDateTime('2026-06-19 00:00:00.000000')), lessOrEquals(s.min_first_timestamp, toDateTime('2026-06-22 07:09:29.609325'))) + and(greaterOrEquals(s.min_first_timestamp, toDateTime('2026-06-20 00:00:00.000000')), lessOrEquals(s.min_first_timestamp, toDateTime('2026-06-23 04:07:00.084253'))) GROUP BY session_id HAVING - and(greaterOrEquals(expiry_time, toDateTime('2026-06-22 07:09:29.609896')), equals(max(s.is_deleted), 0), greater(active_seconds, 5.0)) + and(greaterOrEquals(expiry_time, toDateTime('2026-06-23 04:07:00.084667')), 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 da3efd6..43c859b 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-06-22 07:09:36.043071')), greater($start_timestamp, toDateTime('2026-06-21 07:09:31.043785'))) + and(less($start_timestamp, toDateTime('2026-06-23 04:07:06.272075')), greater($start_timestamp, toDateTime('2026-06-22 04:07:01.272742'))) ORDER BY $start_timestamp DESC LIMIT 50000 diff --git a/skills/signals-scout-general/SKILL.md b/skills/signals-scout-general/SKILL.md index b74c9d4..b63d894 100644 --- a/skills/signals-scout-general/SKILL.md +++ b/skills/signals-scout-general/SKILL.md @@ -5,7 +5,7 @@ description: > team's project and emits findings into the Signals inbox. Sibling signals-scout-* specialists each watch a single product surface in depth; this scout looks for cross-product correlations and explores the surfaces no specialist covers. Each - scout runs on its own schedule (default every 3 hours), so general fires independently + scout runs on its own schedule (default every 24 hours), so general fires independently of the specialists over time. compatibility: > Runs as the PostHog Signals scout in a Claude sandbox with PostHog MCP scopes: signal_scout:read + signal_scout_internal:write (for @@ -24,31 +24,59 @@ a real outcome — re-emitting a known issue is worse than emitting nothing. ## Orient -Three cheap reads cold-start a run: +Cheap reads cold-start a run: - `signals-scout-project-profile-get` — deterministic snapshot of products in use, recent activity, integrations, top events with reach + burst metrics, inbox - report counts. -- `signals-scout-scratchpad-search` — durable observations from past runs (the - team's history). Search with `text=` (ILIKE on key + content). + report counts. A fast hint, not the whole truth: it leans toward configured + entities (dashboards, flags, experiments, pipelines…) and lags products that + shipped recently, so treat it as a starting point, not a complete map. +- `signals-scout-scratchpad-search` — durable observations from past runs. Read + `pattern:general:coverage-map` first (see "Map the project") — it's your running + inventory of which products actually have live data on this team. Search with + `text=` (ILIKE on key + content). - `signals-scout-runs-list` — recent summaries from this scout and siblings. Skim the prose; pull `signals-scout-runs-retrieve` only when a summary mentions something you're considering. +## Map the project + +The profile and `top_events` only see so much — they're blind to whole products +(session replay, logs, tracing, revenue, the _state_ of error tracking) whose data +the profile doesn't enumerate, and they lag products that shipped recently. Don't +trust them to be complete. Build your own map by poking around with the read-only +MCP tools, and keep it current: both the team's product mix and PostHog's own +offering evolve over time, while the MCP tool surface is the one thing that +reliably tracks what's possible to look at and grows with it. + +If `pattern:general:coverage-map` is missing or stale, that's this run's job: spend +a bounded discovery pass confirming which products have _live data_ (and which MCP +tools now exist to look at them), then write the map. `references/discovery.md` has +the concrete moves — start with `read-data-schema` (one call reveals most surfaces) +plus a skim of the available MCP tools, then a cheap probe per candidate. Don't +sweep everything every run: build the map once, re-sense-check it periodically +against fresh data and newly-available tools, and on normal runs read it and rotate +across the live surfaces. + +If `signals-scout-runs-list` shows no sibling specialists running, you are the only +scout on this project — the map should cover every live product, not just the gaps +between specialists. + ## Explore -Pick what looks interesting and follow it. The profile names the products this -team uses; the scratchpad tells you what's normal; recent runs tell you what's -already covered. Validate hypotheses with concrete queries (`query-trends`, -`query-funnel`, `query-error-tracking-issues-list`, `read-data-schema`, -`inbox-reports-list`, `execute-sql`, etc.) before emitting. - -If a sibling specialist already covers a surface in depth, leave the deep dive to it -on a future tick — the `skill_name`s on recent runs in `signals-scout-runs-list` show -the live roster (specialists exist for most product surfaces: error tracking, logs, AI -observability, experiments, feature flags, session replay, web analytics, surveys, and -more). Spend your time on **cross-product correlations** or on **surfaces no -specialist covers**. +Pick what looks interesting and follow it. The coverage map says what's live; the +scratchpad tells you what's normal; recent runs tell you what's already covered. +Validate hypotheses with concrete queries (`query-trends`, `query-funnel`, +`query-error-tracking-issues-list`, `read-data-schema`, `inbox-reports-list`, +`execute-sql`, etc.) before emitting. + +When sibling specialists are running, leave a surface they cover in depth to them on +a future tick — the `skill_name`s on recent runs in `signals-scout-runs-list` show +the live roster (specialists exist for most product surfaces: error tracking, logs, +AI observability, experiments, feature flags, session replay, web analytics, surveys, +and more) — and spend your time on **cross-product correlations** or **surfaces no +specialist covers**. When no specialists are running, the whole coverage map is your +beat: work across it instead of narrowing to one corner. ## Decide diff --git a/skills/signals-scout-general/references/discovery.md b/skills/signals-scout-general/references/discovery.md new file mode 100644 index 0000000..e1814e1 --- /dev/null +++ b/skills/signals-scout-general/references/discovery.md @@ -0,0 +1,100 @@ +# Discovery: mapping what a project actually uses + +The profile and `top_events` are a starting point, not the whole picture. They +enumerate configured entities and the busiest events, but whole products are +invisible to them — session replay, logs, tracing/APM, revenue, and the _state_ of +error tracking all live in data the profile doesn't carry — and the profile lags +products that shipped recently. On a project with no specialist scouts, you're the +only thing watching those surfaces, so confirm what's live yourself. + +Two things evolve under you: the **team's** product mix (they adopt new products, +turn others off) and **PostHog's** own offering (new products ship with new MCP +tools). The reliable substrate through both is the **MCP tool surface** — it tracks +what's possible to look at and grows over time. Lean on it: a tool family that +wasn't there last time is a strong hint of a product worth folding into the map. + +## One cheap pass, then a durable map you keep current + +Discovery is amortized, not repeated every run: + +- **No `pattern:general:coverage-map` yet (early runs):** spend this run building + it. Run the breadth pass below, then write the map. +- **Map exists and is recent:** skip discovery. Read it, pick a live surface, and + investigate — rotating across surfaces over successive runs. +- **Map is stale (~weekly, or the project clearly changed):** re-sense-check it. + Re-run the breadth pass, skim the MCP tools for capabilities new since last time, + and update the parts that drifted. Don't assume last week's map is still complete + — products appear on both sides. + +Stay bounded — discovery is orientation, not investigation. A handful of cheap reads +is enough; you have future runs to go deep. + +## Breadth pass: event taxonomy + tool surface + +Two cheap reads do most of the work. + +**1. The event taxonomy.** `read-data-schema` (events) returns the event names this +team captures — and the names alone reveal which products are live: + +| Signal in the event taxonomy | Product that's live | +| ------------------------------------------ | -------------------------------- | +| `$exception` | Error tracking | +| `$ai_generation` / `$ai_span` / `$ai_*` | LLM analytics (AI observability) | +| `$pageview` / `$pageleave` / `$web_vitals` | Web analytics | +| `$snapshot` / session activity | Session replay | +| `$feature_flag_called` | Feature flags | +| `$csp_violation` | CSP reporting | +| high-volume custom events | Product analytics | + +**2. The MCP tool surface.** Skim the available tools (the MCP's own `search` / +`tools` discovery). New `query-*` or product tool families that weren't there before +are how you notice PostHog shipped a product you don't yet have a lens for — pick it +up and probe whether this team uses it. + +Pair both with the profile's configured-entity sections (dashboards, flags, +experiments, surveys, pipelines, warehouse sources, cohorts): together they tell you +what's "configured," what's "emitting," and what's "now possible to query." + +## Confirm the surfaces the taxonomy can't show + +A few products don't announce themselves cleanly in the event list — probe them +directly when the breadth pass hints they might be present, one cheap read each: + +- **Error tracking** — `query-error-tracking-issues-list` (issue count + recent + activity; `$exception` volume alone doesn't tell you issue state). +- **Session replay** — `query-session-recordings-list` (are sessions recording, and + how recently?). +- **Logs** — `query-logs` (any volume, by service / severity). +- **Tracing / APM** — `query-apm-spans` (OTel spans present?). +- **LLM analytics** — `query-llm-traces-list` (live traces, not just `$ai_*` counts). +- **Revenue** — revenue events in the taxonomy, or warehouse Stripe sources in the + profile. +- **Data warehouse** — the profile's `external_data_sources`; deeper structure via + `read-data-warehouse-schema`. + +When you hit a surface no tool seems to cover, that's worth a `mcp-gap:` scratchpad +note (see [conventions.md](conventions.md)) — a capability the fleet may want later. + +## Write the coverage map + +Persist what you found as a single durable entry, overwriting it in place +(`pattern:general:coverage-map`). Make it future-run actionable: each live product +with a rough volume / last-seen and a one-line "what's worth watching here," an +explicit list of products that are _absent_ so future runs don't re-probe them, and +the date you last sense-checked it. Example shape: + +```text +key: pattern:general:coverage-map +content: "2026-06-22 discovery (team has NO specialist scouts — general owns all). + LIVE: error_tracking (~12k $exception/day, 40 issues, watch new-issue + bursts); web_analytics ($pageview ~80k/day, 3 channels); session_replay + (recording, ~1.5k/day); feature_flags (22 active). ABSENT (skip until a + refresh): llm_analytics (no $ai_*), apm (no spans), revenue (no Stripe + source), surveys, csp. Last full sense-check 2026-06-22; re-check ~weekly + or on a visible project change / new MCP tool family." +``` + +Future runs read this first, skip the absent products, and rotate attention across +the live ones — that's what turns a once-a-day generalist into something that covers +the whole project over a week instead of re-checking one corner, and keeps up as +both the team and PostHog change.