Error Tracking · Error…
Feature Flags · Feature…
Omnibus
200 chapters · 643 min
Omnibus
Chapter 29 of 200
Guides exploration of $autocapture events captured by posthog-js to understand user interactions, find CSS selectors (especially data-attr attributes), evaluate selector…
4 minutes · 856 words · 12 sections
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.
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 (opens in a new tab)) |
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.
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.
Run a count query before doing anything else. If the count is zero, autocapture may be disabled. There are two ways this happens:
autocapture_opt_out in PostHog project settingsinit() call can pass autocapture: falseTell 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 DAYStart broad using the materialized columns. The goal is to understand what users are clicking before narrowing down.
Useful explorations:
elements_chain_elements)elements_chain_texts)elements_chain_href)elements_chain values for a specific page (filtered by properties.$current_url)See example queries (opens in a new tab) for all patterns.
Once the user identifies an interaction they care about, find a CSS selector that identifies it.
Priority order for selector attributes (best first):
data-attr or other data-* attributes — highest specificity, stable across deploys, developer-intended anchors.
Search with match(elements_chain, 'data-attr=') or extractAll.attr_id) — also highly stable, queryable via elements_chain_ids.When a data-attr value is found, construct a selector like [data-attr="value"] or button[data-attr="value"].
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.
If the selector alone is not unique enough, layer on additional filters:
elements_chain_textsproperties.$current_urlelements_chain_hrefRe-run the uniqueness check after each refinement. Only include filters that are needed — fewer filters means more resilience to minor DOM changes.
When the user wants a funnel, trend, or other insight, the filter shape is different from HogQL.
Each step in a FunnelsQuery / TrendsQuery is an EventsNode (or ActionsNode) with event: "$autocapture" and a properties array.
Two distinct property type values matter — they are not interchangeable:
type: "element" — keys: selector, tag_name, text, href. Matched against the parsed elements_chain. Operator support is split:
selector and tag_name only support exact and is_not — anything else raises NotImplementedError in the query compiler (posthog/hogql/property.py).text and href accept the full string operator set (exact, is_not, icontains, not_icontains, regex, not_regex, is_set, is_not_set).type: "event" — keys: any of the canonical autocapture properties ($event_type, $el_text, $current_url) or anything else on the event. Standard event-property operators (exact, icontains, regex, etc.).Example funnel from clicking one button to clicking another:
{
"kind": "FunnelsQuery",
"series": [
{
"kind": "EventsNode",
"event": "$autocapture",
"properties": [
{
"type": "element",
"key": "selector",
Two things easy to get wrong:
value is an array even when matching a single selector[data-attr="..."] wrapper — it is a CSS selector, not a bare attribute valueDecision rule: prefer an action (ActionsNode referencing an existing action — see Step 8) when the interaction will be referenced more than once; inline type: "element" / type: "event" filters when it’s a one-off insight; raw HogQL (Step 7) when joining across events or doing custom aggregations.
The discovered selector can be used directly in HogQL without creating an action.
Trends — count matching clicks over time:
SELECT
toStartOfDay(timestamp) as day,
count() as clicks
FROM events
WHERE event = '$autocapture'
AND timestamp > now() - INTERVAL 14 DAY
AND elements_chain =~ '(^|;)button.*?data-attr="checkout"'
GROUP BY day
ORDER BYFunnel — pageview to click conversion:
SELECT
person_id,
first_pageview,
first_click_after
FROM (
SELECT
p.person_id,
p.pageview_time as first_pageview,
min(c.click_time) as first_click_after
FROM (
For recurring analysis, prefer creating an action (next step) or using posthog:query-trends / posthog:query-funnel with the action.
Actions are the durable version of ad-hoc selector queries.
Once the criteria uniquely identify the interaction, create an action using posthog:action-create.
Construct the step with only the filters needed for uniqueness:
{
"name": "Clicked checkout button",
"steps": [
{
"event": "$autocapture",
"selector": "button[data-attr='checkout']",
"text": "Complete Purchase",
"text_matching": "exact",
"url": "/checkout",
"url_matching": "contains"
}
Available step fields for $autocapture:
selector — CSS selector (e.g. button[data-attr='checkout'])tag_name — HTML tag name (e.g. button, a, input)text / text_matching — element text (exact, contains, or regex)href / href_matching — link href (exact, contains, or regex)url / url_matching — page URL (exact, contains, or regex)After creation, verify with matchesAction():
SELECT count() as matching_events
FROM events
WHERE matchesAction('Clicked checkout button')
AND timestamp > now() - INTERVAL 7 DAY$autocapture is high volumeLIMIT generously when sampling elements_chain — the strings can be longelements_chain =~ operator matches CSS selectors as regex internally;
prefer materialized columns when possible for performanceInstall this repository
npx skills add PostHog/skills/plugin marketplace add PostHog/skillsSkills install per repository, not per chapter — the CLI has no documented per-skill form, so we do not print one.
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.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 9 August 2026.SKILL.md, not by matching a directory convention. 5 distinct layouts observed: skills/omnibus/*/SKILL.md, skills/posthog/all/skills/*/SKILL.md, skills/posthog/error-tracking/skills/*/SKILL.md, skills/posthog/feature-flags/skills/*/SKILL.md, skills/posthog/integration/skills/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by PostHog, declaring 5 plugins. It is read for editorial metadata only — never as the skill index, which is always the repository tree./PostHog/skills.md, and each chapter at its own .md URL.2 files · 7 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of chapter 29.
Documentation the agent loads on demand, rather than up front.