skills/assessing-heatmaps/SKILL.md
Assesses what a page's heatmap is telling you and recommends concrete changes. Pulls click / rageclick / scroll-depth data for a URL, names the hot elements by cross-referencing autocapture events on the same page, and can create a saved heatmap the user opens in PostHog, then summarizes the behavior and proposes improvements. TRIGGER when: user asks what a heatmap shows, why people aren't clicking something, where users rage-click, how far they scroll, what to change on a page based on heatmap/click data, or to 'analyze/assess/review the heatmap' for a URL. DO NOT TRIGGER when: the user only wants to create a saved heatmap screenshot with no analysis (use heatmaps-saved-create directly), or is asking about session replay in general (use investigating-replay).
npx skillsauth add posthog/ai-plugin assessing-heatmapsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A heatmap answers "where do people interact with this page?" — clicks, rage clicks, mouse movement, and how
far down they scroll. The data is pure geometry: pointer_relative_x (0..1 across the viewport), pointer_y
(absolute pixels down the page), and a count per spot. It does not know what was clicked. Turning
"lots of clicks at (0.5, 220)" into "lots of clicks on the Pricing nav link" is the whole job, and it comes
from cross-referencing autocapture on the same URL.
You can't see the page — there is no screenshot in your context. A good assessment fuses two sources and leans on autocapture to supply the layout/identity you can't see:
heatmaps-list).When the user wants to see the heatmap, create a saved heatmap (Step 4) — that renders the page with the data overlaid for them to open in PostHog. You reason from the data; they look at the picture.
You need an exact url_exact (one page) or a url_pattern (regex, to aggregate across query strings). Confirm
the URL with the user if ambiguous. Default to the last 7 days; widen to 30 if volume is low. Heatmap data is
retained for 90 days.
Call heatmaps-list once per signal you care about (or query the heatmaps table directly via SQL — see the
querying-posthog-data skill, models-heatmaps):
type: "click" — the primary "what draws attention" map.type: "rageclick" — repeated frustrated clicks. The single strongest "something is broken or
misleading" signal. Any meaningful rageclick cluster deserves a callout.type: "scrolldepth" — how far people get. Use it to find the fold and spot CTAs that sit below where most
people ever scroll.Use aggregation: "unique_visitors" when you care about how many people (not how many clicks); total_count
exaggerates a few heavy clickers.
fold summaryFor the click types, heatmaps-list returns a fold object alongside results:
pct_below_fold — share of non-fixed interactions that landed below the user's initial viewport (they
had to scroll to reach them). This is one of the highest-value findings: content people actively click that
sits below the fold is a prime candidate to move up.below_fold_count / total_count — the raw counts behind the percentage (fixed-position elements are
excluded, since they're always on screen).median_viewport_height — the typical fold line in CSS pixels, to recommend against.Report it concretely, e.g. "the fold is ~600px for most visitors, yet 35% of clicks land below it, so users
scroll before interacting — that content is a candidate for the first screen." Segment by device with
viewport_width_min/viewport_width_max (desktop and mobile have very different folds) and read fold per
band rather than blending them.
Need a distribution rather than a single percentage (e.g. clicks bucketed by how far below the fold)? Drop to
SQL on the raw heatmaps table, which has y and viewport_height in the same scaled units — see the
querying-posthog-data skill, models-heatmaps.
For each notable cluster, find what's actually there. Query autocapture on the same URL — either via the
exploring-autocapture-events skill or directly:
SELECT properties.$el_text AS text, count() AS clicks
FROM events
WHERE event = '$autocapture'
AND properties.$current_url = 'https://example.com/pricing'
AND timestamp >= now() - INTERVAL 7 DAY
GROUP BY text
ORDER BY clicks DESC
LIMIT 25
elements_chain gives the selector/DOM path when you need to disambiguate two elements with the same text.
Match autocapture's top elements to the heatmap's hot coordinates: clicks concentrated on something that is
not a link or button (plain text, an image, a disabled control) is a classic "users expect this to be
clickable" finding.
You can't see the page, but the user can. When a visual would help them follow your findings, create a saved heatmap so they can open the rendered page with the data overlaid in PostHog:
heatmaps-saved-create with the page url (type defaults to screenshot). This enqueues a headless
render — it is asynchronous. Pass widths matching the viewport band you analyzed in Step 2.heatmaps-saved-get (by the returned short_id) until status is completed, then tell the user
it's ready to view in PostHog.This is for the human's benefit — your own reasoning still comes from the Step 2 data and the Step 3 autocapture identity, not from the picture.
For a surprising cluster, heatmaps-events returns the individual sessions behind specific points. Hand the
session IDs to the investigating-replay skill to watch what people actually did.
Produce a short, concrete report:
| Signal | Likely meaning | Typical recommendation | | ---------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------- | | Rage clicks on an element | Broken, slow, or looks-clickable-but-isn't | Fix the handler, add feedback, or make it actually interactive | | Many clicks on non-link text/image | Users expect it to be clickable | Make it a link/button, or remove the affordance | | Primary CTA gets few clicks | Buried, low-contrast, or out-competed | Raise it, increase contrast, reduce nearby noise | | Scroll cliff before key content | Content/CTA is below where people stop | Move it up or add a reason to scroll | | High % of clicks below the fold | Engaged content sits below the initial viewport — users scroll before interacting | Move the most-clicked elements onto the first screen | | Hot clicks on nav, cold body | Page isn't delivering; people bail to nav | Re-evaluate the page's core content |
Team.heatmaps_opt_in). If heatmaps-list returns nothing for a page that
clearly gets traffic, capture may be off or the URL is wrong — check both before concluding "no
engagement".pointer_y and
relative x, so use the API/tool values directly rather than the raw table columns.heatmaps-saved-create, poll heatmaps-saved-get until
status is completed before telling the user it's viewable. Only screenshot-type heatmaps render an
image; iframe and recording types do not.viewport_width_min/viewport_width_max rather than blending them.tools
Focused Signals scout for PostHog projects with web traffic. Watches the acquisition and site-health layer the web analytics product reports on: per-channel session volume diverging from the site's own rhythm (an acquisition source silently collapsing or surging), attribution breakage (paid/campaign traffic reclassifying into Direct or Unknown when tagging breaks), landing pages that break (bounce-rate steps, 404 spikes, entry-path cliffs), and page-performance regressions (web vitals p75 steps). Emits findings only when they clear the confidence bar; otherwise writes durable memory and closes out empty. Self-contained peer in the signals-scout-* fleet.
tools
Focused Signals scout for PostHog projects using session replay. Watches two promises the replay product makes: that sessions are actually being recorded (capture integrity — recording volume vanishing while site traffic doesn't), and that the friction evidence inside recordings gets seen (rage-click / dead-click clusters concentrating on a page or element, error-after-interaction cohorts, recurring replay vision themes nobody aggregates). Emits findings only when they clear the confidence bar; otherwise writes durable memory and closes out empty. Self-contained peer in the signals-scout-* fleet.
tools
Focused Signals scout for PostHog setup health. Reads the project's active health issues — the deterministic findings of PostHog's own health checks (no live events, outdated SDKs, missing reverse proxy, absent web vitals, ingestion warnings, failing data-warehouse models, and more) — and decides which are genuinely worth surfacing. Unlike a one-signal-per-issue push, it bundles kind-clusters into a single finding, weights by real blast radius (cross-referencing actual event volume and reach), and prioritizes issues an agent can resolve via the MCP. Emits only above the confidence bar; otherwise writes durable memory and closes out empty. Self-contained peer in the signals-scout-* fleet — no dependencies on other skills.
tools
Focused Signals scout for PostHog projects using feature flags. Watches the flag roster and the `$feature_flag_called` evaluation stream for contradictions between a flag's configured state and its real traffic: evaluation cliffs on healthy flags, ghost flags (code calling keys that no longer exist), response-distribution shifts with no corresponding flag edit, and flag debt (stale, fully-rolled-out, or dead flags still burning evaluations). Emits findings only when they clear the confidence bar; otherwise writes durable memory and closes out empty. Self-contained peer in the signals-scout-* fleet — no dependencies on other skills.