/exploring-autocapture-events
Guides exploration of $autocapture events captured by posthog-js to understand user interactions, find CSS selectors (especially data-attr attributes), evaluate selector uniqueness, query matching clicks ad-hoc, and create actions. Use when the user asks about autocapture data,
$ npx -y skills add posthog/posthog --skill exploring-autocapture-events --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/exploring-autocapture-events
Context preview
The summary Claude sees to decide when to auto-load this skill.
Guides exploration of $autocapture events captured by posthog-js to understand user interactions, find CSS selectors (especially data-attr attributes), evaluate selector uniqueness, query matching clicks ad-hoc, and create actions. Use when the user asks about autocapture data,
SKILL.md
exploring-autocapture-events.SKILL.mdname: exploring-autocapture-events
description: >
Guides exploration of $autocapture events captured by posthog-js to understand user interactions,
find CSS selectors (especially data-attr attributes), evaluate selector uniqueness, query matching
clicks ad-hoc, and create actions. Use when the user asks about autocapture data, wants to find
what users are clicking, needs to build actions from click events, asks about elements_chain,
wants to build a trend or funnel filtered by clicks or other autocapture interactions, asks which
properties autocapture sends, or asks how to filter $autocapture events. Only applies to projects
using posthog-js autocapture.
Exploring autocapture events
if users opt in then posthog-js automatically captures clicks, form submissions, and page changes as `$autocapture` events. Each event records the clicked DOM element and its ancestors in the `elements_chain` column.
`$autocapture` is intentionally excluded from the `posthog:read-data-schema` taxonomy because it is only useful with autocapture-specific filters (selector, tag, text, href). This skill fills that gap.
Materialized columns
The `events` table provides fast access to common element fields without parsing the full chain string.
| Column | Type | Description | | ------------------------- | ------------- | ------------------------------------------------------------------------------------------------------ | | `elements_chain` | String | Full semicolon-separated element chain (see [format reference](./references/elements-chain-format.md)) | | `elements_chain_href` | String | Last href value from the chain | | `elements_chain_texts` | Array(String) | All text values from elements | | `elements_chain_ids` | Array(String) | All id attribute values | | `elements_chain_elements` | Array(String) | Useful tag names: a, button, input, select, textarea, label |
Use materialized columns for exploration queries whenever possible — they avoid regex parsing.
Canonical autocapture properties
Every `$autocapture` event from posthog-js ships with a fixed set of properties. Do not query the schema to "look them up" — they are these:
| Property | Examples | Notes | | ----------------- | --------------------------------- | ----------------------------------------------------------- | | `$event_type` | `click`, `submit`, `change` | the kind of interaction | | `$el_text` | `Sign up`, `Submit` | text of the clicked element | | `$current_url` | `https://app.example.com/pricing` | page the interaction happened on | | `$elements_chain` | semicolon-separated chain | parsed via the `elements_chain*` materialized columns above |
Standard event properties (`$browser`, `$os`, `$device_type`, etc.) are also present.
Workflow
1. Confirm autocapture data exists
Run a count query before doing anything else. If the count is zero, autocapture may be disabled. There are two ways this happens:
- **Project settings** — the team can set `autocapture_opt_out` in PostHog project settings
- **SDK config** — the posthog-js `init()` call can pass `autocapture: false`
Tell the user if no data is found so they can check both settings.
SELECT count() as cnt
FROM events
WHERE event = '$autocapture'
AND timestamp > now() - INTERVAL 7 DAY
2. Explore what users are interacting with
Start broad using the materialized columns. The goal is to understand what users are clicking before narrowing down.
Useful explorations:
- Top clicked tag names (via `elements_chain_elements`)
- Top clicked text values (via `elements_chain_texts`)
- Top clicked hrefs (via `elements_chain_href`)
- Raw `elements_chain` values for a specific page (filtered by `properties.$current_url`)
See [example queries](./references/example-queries.md) for all patterns.
3. Find candidate selectors
Once the user identifies an interaction they care about, find a CSS selector that identifies it.
Priority order for selector attributes (best first):
1. **`data-attr` or other `data-*` attributes** — highest specificity, stable across deploys, developer-intended anchors. Search with `match(elements_chain, 'data-attr=')` or `extractAll`. 2. **Element ID** (`attr_id`) — also highly stable, queryable via `elements_chain_ids`. 3. **Tag + class combination** — moderately stable but classes change with CSS refactors. 4. **Text content** — fragile (changes with copy edits, i18n) but sometimes the only option. 5. **Tag name alone** — too broad on its own, useful as a qualifier.
When a `data-attr` value is found, construct a selector like `[data-attr="value"]` or `button[data-attr="value"]`.
4. Evaluate selector uniqueness
A selector is only useful if it matches the intended interaction and not unrelated events.
Run a uniqueness check using `elements_chain =~` with the regex pattern for the selector. Then sample matching events to inspect what the selector actually captures. Compare the count against total autocapture volume to understand selectivity.
A good selector matches a single logical interaction. If it matches too many distinct elements, refine it in the next step.
5. Refine with additional filters
If the selector alone is not unique enough, layer on additional filters:
- **Text filter** — match by element text content using `elements_chain_texts`
- **URL filter
Read more
name: exploring-autocapture-events description: > Guides exploration of $autocapture events captured by posthog-js to understand user interactions, find CSS selectors (especially data-attr attributes), evaluate selector uniqueness, query matching clicks ad-hoc, and create actions. Use when the user asks about autocapture data, wants to find what users are clicking, needs to build actions from click events, asks about elements_chain, wants to build a trend or funnel filtered by clicks or other autocapture interactions, asks which properties autocapture sends, or asks how to filter $autocapture events. Only applies to projects using posthog-js autocapture.
Exploring autocapture events
if users opt in then posthog-js automatically captures clicks, form submissions, and page changes as `$autocapture` events. Each event records the clicked DOM element and its ancestors in the `elements_chain` column.
`$autocapture` is intentionally excluded from the `posthog:read-data-schema` taxonomy because it is only useful with autocapture-specific filters (selector, tag, text, href). This skill fills that gap.
Materialized columns
The `events` table provides fast access to common element fields without parsing the full chain string.
| Column | Type | Description | | ------------------------- | ------------- | ------------------------------------------------------------------------------------------------------ | | `elements_chain` | String | Full semicolon-separated element chain (see [format reference](./references/elements-chain-format.md)) | | `elements_chain_href` | String | Last href value from the chain | | `elements_chain_texts` | Array(String) | All text values from elements | | `elements_chain_ids` | Array(String) | All id attribute values | | `elements_chain_elements` | Array(String) | Useful tag names: a, button, input, select, textarea, label |
Use materialized columns for exploration queries whenever possible — they avoid regex parsing.
Canonical autocapture properties
Every `$autocapture` event from posthog-js ships with a fixed set of properties. Do not query the schema to "look them up" — they are these:
| Property | Examples | Notes | | ----------------- | --------------------------------- | ----------------------------------------------------------- | | `$event_type` | `click`, `submit`, `change` | the kind of interaction | | `$el_text` | `Sign up`, `Submit` | text of the clicked element | | `$current_url` | `https://app.example.com/pricing` | page the interaction happened on | | `$elements_chain` | semicolon-separated chain | parsed via the `elements_chain*` materialized columns above |
Standard event properties (`$browser`, `$os`, `$device_type`, etc.) are also present.
Workflow
1. Confirm autocapture data exists
Run a count query before doing anything else. If the count is zero, autocapture may be disabled. There are two ways this happens:
- **Project settings** — the team can set `autocapture_opt_out` in PostHog project settings
- **SDK config** — the posthog-js `init()` call can pass `autocapture: false`
Tell the user if no data is found so they can check both settings.
SELECT count() as cnt FROM events WHERE event = '$autocapture' AND timestamp > now() - INTERVAL 7 DAY
2. Explore what users are interacting with
Start broad using the materialized columns. The goal is to understand what users are clicking before narrowing down.
Useful explorations:
- Top clicked tag names (via `elements_chain_elements`)
- Top clicked text values (via `elements_chain_texts`)
- Top clicked hrefs (via `elements_chain_href`)
- Raw `elements_chain` values for a specific page (filtered by `properties.$current_url`)
See [example queries](./references/example-queries.md) for all patterns.
3. Find candidate selectors
Once the user identifies an interaction they care about, find a CSS selector that identifies it.
Priority order for selector attributes (best first):
1. **`data-attr` or other `data-*` attributes** — highest specificity, stable across deploys, developer-intended anchors. Search with `match(elements_chain, 'data-attr=')` or `extractAll`. 2. **Element ID** (`attr_id`) — also highly stable, queryable via `elements_chain_ids`. 3. **Tag + class combination** — moderately stable but classes change with CSS refactors. 4. **Text content** — fragile (changes with copy edits, i18n) but sometimes the only option. 5. **Tag name alone** — too broad on its own, useful as a qualifier.
When a `data-attr` value is found, construct a selector like `[data-attr="value"]` or `button[data-attr="value"]`.
4. Evaluate selector uniqueness
A selector is only useful if it matches the intended interaction and not unrelated events.
Run a uniqueness check using `elements_chain =~` with the regex pattern for the selector. Then sample matching events to inspect what the selector actually captures. Compare the count against total autocapture volume to understand selectivity.
A good selector matches a single logical interaction. If it matches too many distinct elements, refine it in the next step.
5. Refine with additional filters
If the selector alone is not unique enough, layer on additional filters:
- **Text filter** — match by element text content using `elements_chain_texts`
- **URL filter
:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.
Repo: posthog/posthog
Other skills on posthog.
- /analyzing-expensive-users
Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.
Open skill - /creating-online-evaluations
Author continuously-running online evaluations in PostHog AI observability, grounded in real failure modes you've identified. Use when the user wants evaluations that automatically score new generations or whole traces going forward — "create an eval to catch X", "continuously
Open skill - /exploring-ai-failures
Find where an AI/LLM application is failing in production and surface the failure patterns, working from real traces. Use when someone wants to understand what's going wrong with an AI feature, find and categorize failure modes, triage errors, or investigate quality issues
Open skill - /exploring-llm-clusters
Investigate AI observability clusters — understand usage patterns in AI/LLM traffic, compare cluster behavior, compute cost/latency metrics, and drill into individual traces within clusters.
Open skill - /exploring-llm-costs
Investigate LLM spend in PostHog — total cost over time, cost by model, provider, user, trace, or custom dimension, token and cache-hit economics, and cost regressions. Use when the user asks "how much are we spending on LLMs?", "which model / user / feature is most expensive?",
Open skill - /exploring-llm-evaluations
Investigate AI observability evaluations — `hog` (deterministic code-based), `llm_judge` (LLM-prompt-based), and `sentiment` (user-message sentiment). Find existing evaluations, inspect their configuration, run them against specific generations, query individual results, and
Open skill

