/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,
Claude Code
$ npx -y skills add PostHog/ai-plugin --skill exploring-autocapture-events --agent claude-code
Codex
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a codex -y
Cursor
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a cursor -y
Gemini CLI
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a gemini-cli -y
GitHub Copilot
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a github-copilot -y
OpenCode
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a opencode -y
Windsurf
$ npx skills add PostHog/ai-plugin --skill exploring-autocapture-events -a windsurf -y
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
Official PostHog plugin for AI clients. Access PostHog products directly from your AI coding tool.
Other skills on ai-plugin.
More skills from other plugins.
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
ask-matt
Ask which skill or flow fits your situation. A router over the skills in this repo.
Questions about exploring-autocapture-events.
- Which coding agents can use exploring-autocapture-events?
- exploring-autocapture-events installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

