Skip to content
Back to skills

Posthog

ASecurity

Query PostHog product analytics via REST API — event analytics, HogQL SQL queries, feature flags, experiments, session recordings, insights, persons, cohorts. Use when the user wants to answer an analytics question, toggle/inspect a flag, or pull event data programmatically without opening the PostHog UI or installing the PostHog MCP.

  • 9 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added May 26, 2026
toolsgobashsqldebuggingapi

Works with

  • claude code
  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add mnlt/teleport --skill posthog --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Posthog?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Posthog
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mnlt-posthog/badge)](https://www.skillsdirectory.com/skills/mnlt-posthog)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: posthog
description: Query PostHog product analytics via REST API — event analytics, HogQL SQL queries, feature flags, experiments, session recordings, insights, persons, cohorts. Use when the user wants to answer an analytics question, toggle/inspect a flag, or pull event data programmatically without opening the PostHog UI or installing the PostHog MCP.
license: MIT (skill wrapper; PostHog API terms apply)
---

# PostHog

Operates PostHog via REST API — event analytics, **HogQL queries**, feature flags, experiments, session recording metadata, insights, persons. Supports US cloud, EU cloud, and self-hosted. No MCP server required.

## Usage

- **Use for:** HogQL queries ("how many `$pageview` last 7d?"), flag inspect/toggle, last-N events for a user, experiment results.
- **Skip for:** Debugging client-side tracking, raw event ingestion (use an SDK), concept questions, raw replay JSON export (UI-only).

## Credentials check

```bash
[ -n "${POSTHOG_PERSONAL_API_KEY:-$POSTHOG_API_KEY}" ] && echo "POSTHOG_API_KEY: PRESENT" || echo "POSTHOG_API_KEY: MISSING"
```

**Never** echo the variable directly.

If MISSING, **respond to the user with EXACTLY this message (do NOT paraphrase, do NOT suggest manual JSON edits):**

> I need your posthog credential. Run this in another terminal — it'll open the signup page, validate format, and save it safely with masked input:
>
> ```
> teleport-setup add-key posthog
> ```
>
> Then restart Claude Code (`/exit`, then `claude`) and ask me again.

**Do NOT suggest editing `~/.claude/settings.local.json` manually.** The `teleport-setup add-key` command handles it with backup, validation, and masked input. Stop execution until the user has run the command and restarted.

## API

- Base URL varies: US `https://us.posthog.com`, EU `https://eu.posthog.com`, self-hosted `https://{your-host}`. Default to US; switch on explicit user confirmation or 401.
- Auth: `Authorization: Bearer $POSTHOG_PERSONAL_API_KEY` (key format `phx_*`).
- Most endpoints are **project-scoped**: `/api/projects/{project_id}/...`. Get ids via `GET /api/projects/`. Newer `/api/environments/{id}/...` routes coexist; prefer `projects`. <!-- unverified: /projects/ vs /environments/ deprecation timeline -->
- Personal API keys carry **scopes** (`query:read`, `feature_flag:read/write`, `insight:read/write`, `event:read`, `person:read/write`, `experiment:read/write`, etc.). Wrong scope = silent 403 or filtered result. <!-- unverified: canonical scope list -->
- Rate limits (team-wide): Query 2400/hr · Analytics 240/min + 1200/hr · Events 60/min + 300/hr · Flag local-eval 600/min · CRUD 480/min + 4800/hr.

## Endpoints

| Endpoint (under `/api/projects/{project_id}`) | Purpose                                                 |
| --------------------------------------------- | ------------------------------------------------------- |
| `POST /query/`                                | Run HogQL (primary)                                     |
| `GET /events/`                                | Raw events (**deprecated**; use `/query/`)              |
| `/feature_flags/`                             | List / create / update / soft-delete flag definitions   |
| `/insights/` / `/dashboards/`                 | Saved charts and dashboards                             |
| `/persons/` / `/cohorts/`                     | Users and audience definitions                          |
| `/session_recordings/`                        | Recording **metadata** only (raw replay is UI-only)     |
| `/experiments/` / `/actions/`                 | Experiments CRUD; named event patterns (legacy)         |

## Primary workflow — HogQL query

HogQL is PostHog's SQL dialect (**Clickhouse-flavored, not PostgreSQL**). Almost every analytics question is one POST away.

```bash
curl -sL -X POST -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" -H "Content-Type: application/json" \
  "https://us.posthog.com/api/projects/$PROJECT_ID/query/" \
  -d '{"query":{"kind":"HogQLQuery","query":"SELECT event, count() AS c FROM events WHERE timestamp > now() - INTERVAL 7 DAY GROUP BY event ORDER BY c DESC LIMIT 20"}}'
```

Response: `results` (row tuples), `columns`, `types`, `hasMore` (cap hit), plus `is_cached`/`timings`/`cache_key` when cached.

## Secondary workflows

**Evaluate a flag for a user (server-side)** — uses the **project token** `phc_*` (not the personal key), on the `/flags/` endpoint (successor to legacy `/decide/`). <!-- unverified: /flags/ vs /decide/ current state -->

```bash
curl -sL -X POST -H "Content-Type: application/json" \
  "https://us.posthog.com/flags/?v=2" \
  -d '{"api_key":"phc_PROJECT_TOKEN","distinct_id":"alice@example.com"}'
```

**List insights / manage flags / fetch recording metadata:**

```bash
curl -sL -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  "https://us.posthog.com/api/projects/$PROJECT_ID/insights/?limit=20" | jq '[.results[] | {id, name, short_id}]'

curl -sL -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  "https://us.posthog.com/api/projects/$PROJECT_ID/feature_flags/" | jq '[.results[] | {id, key, active}]'
```

## Gotchas

- **Scope mismatch = silent 403 or filtered result.** Personal API keys carry scopes — one you didn't tick shows up as 403 without a clear error. First suspect when a key "works elsewhere but not here".
- **US vs EU host mismatch.** A key minted on US returns 401 against `eu.posthog.com` (and vice versa). Confirm the cloud before debugging anything else.
- **HogQL is Clickhouse-flavored, not PostgreSQL.** Date functions (`now()`, `INTERVAL 7 DAY`, `toDate()`, `toStartOfDay()`), string ops, and aggregates differ from Postgres. On "unknown function", check HogQL docs — don't assume Postgres.
- **Project ID vs team ID vs environment ID.** All three are numeric, appear in URLs, easy to conflate. Prefer `/api/projects/{id}/...`; pick one form and stick with it in a session.
- **Events are eventually consistent** — a just-ingested event may not appear in queries for ~30–60s. Wait before assuming capture failed. <!-- unverified: exact ingestion lag SLA -->
- **`/flags/` evaluation vs flag management.** `/flags/` (and legacy `/decide/`) use the **project token** `phc_*` to *evaluate* per-user. `/api/projects/{id}/feature_flags/` uses the **personal API key** `phx_*` to manage definitions. Different endpoints, different auth. <!-- unverified: /decide/ deprecation state -->
- **`POSTHOG_API_KEY` (`phc_*`) vs `POSTHOG_PERSONAL_API_KEY` (`phx_*`).** `phc_*` = public project token for SDK *ingestion* (write-only, safe in browsers). `phx_*` = personal key for private read/admin. Never ship `phx_*` to a browser.
- **`/api/events/` is deprecated.** Without `after` it returns only last 24h, offset caps at 50 000. Use `POST /query/` over the `events` table instead.

## Attribution

`Used skill: PostHog (from teleport catalog).`

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.