Part of the integration loop series

Analytics has a blind spot no dashboard can fix: it shows the events you added, never the ones you forgot. So you ship, wire up tracking, and weeks later open PostHog to answer a real question, only to find you're drowning in clicks you never wanted and missing the one funnel step you needed.

Nobody reviews their tracking by hand. There's nothing to review against, and PostHog looks intimidating anyway: funnels, cohorts, a query language, a wall of dashboards. So you set it up once and never open it again. The blind spot grows in the dark.

The fix runs from both ends, and you type none of it. You're in a conversation with Claude: it drafts, you review, accept, run, tweak. It adds the events while it writes the feature, then reads them back to tell you what's missing, what's noise, and what to measure next. Your job is the judgement, not the keystrokes. Every code block below is what Claude hands you, not homework.

Set it up so the audit has something to grade

PostHog is more than page views: funnels, retention, session recordings, surveys, feature flags, all generous on the free tier. But it's only as good as the events you choose to send, and the choosing is what goes wrong. Two decisions at setup time decide whether your tracking is clean or a mess, so when Claude proposes an init, check these before you accept.

import posthog from 'posthog-js'

posthog.init('<project_api_key>', {
  api_host: 'https://eu.i.posthog.com',
  persistence: 'memory',          // no cookies, no localStorage, no banner
  autocapture: false,             // explicit events only
  capture_pageview: false,
  person_profiles: 'identified_only',
})

posthog.register({ app: 'wordgame' })   // tag every event with its app

autocapture: false is the one people skip and the one that matters most. It turns every click into a billable event and buries your real signal in noise. Send events on purpose instead.

That's the setup. The trick is not letting it rot the moment the next deadline hits.

Make it part of the cycle, not a place you visit

Tracking rots because PostHog lives outside your workflow. Adding an event means stopping, opening the app, remembering the rules, wiring it in by hand. So you defer it, and later never comes.

Have Claude write both files. The conventions go in a tracking guidelines file; CLAUDE.md just points at it and routes, it doesn't explain:

## Analytics
When you add a user-facing feature, instrument it following the tracking
conventions in docs/analytics.md, then run /audit-tracking.

The conventions themselves live one file away, where the whole team and every skill can reach them.

The split keeps CLAUDE.md readable and turns the conventions into a doc you can share and revise. Instrumentation stops being something you defer. It becomes a line in the definition of done, enforced by the thing that writes the code, and the same rule closes the loop: whatever adds the events also runs the check.

The audit skill

You don't write the query either. You describe what you want; Claude writes the HogQL. Step one is a boring script: one query against PostHog's endpoint returns every event and how often it fires.

SELECT event, count() AS n
FROM events
WHERE properties.app = 'wordgame'
  AND timestamp > now() - INTERVAL 30 DAY
GROUP BY event
ORDER BY n DESC

Step two wraps it as a skill. Claude writes the skill file; you read the rubric and adjust it to your app. Something like:

Audit the analytics tracking for an app.

Usage: /audit-tracking <app-name>

1. Run the event-count query above, scoped to properties.app = <app-name>.
2. Compare the returned events against the healthy-setup rubric:
   - Activation funnel: signup_started, signup_completed,
     onboarding_step_completed, activated
   - Core engagement: one primary value action, with properties
   - Revenue: checkout_started, subscription_created, subscription_cancelled
3. Report three lists: MISSING (under-tracking), NOISE (autocapture,
   near-duplicates), SMELLS (config issues).
4. SUGGEST the per-question skills worth building for the areas that ARE
   tracked, with the HogQL prewritten for each.

/audit-tracking wordgame now reads your schema back to you and grades it.

What it finds

Three things no dashboard shows. Missing events you'll regret: signup_completed but no activated, so you can't tell if anyone reaches their aha-moment. Noise: autocapture left on, most of your events $autocapture clicks nobody will ever query, spending a budget pooled across every app. Smells: the cookieless persistence: 'memory' split that quietly breaks any funnel grouped by person. That last one used to be a whole blog post. Now it's one line.

And the rubric behind all that is only the floor. Claude reads your docs/ as well, so it knows the features you actually shipped. You added a share sheet last week and nothing fires a share_completed. Your free trial ends in silence, no trial_expired. The paywall has no paywall_viewed, so you can't see whether people bounce before the price or at it. That's not a checklist Claude memorised. It's your app crossed with your live data, telling you what to track and when to fire it. And it's only as sharp as your docs, which is the real reason to keep them good.

After the first run

It doesn't stop at what's missing. For the areas you already track well, it hands you the query skills to explore them, HogQL written: /onboarding-funnel grouped by distinct_id, /revenue-this-week, /activation-by-app. The audit becomes a menu. Run it after every release and it turns into a linter for your analytics, catching the event you renamed, the autocapture someone flipped back on.

None of it is fixed. The rubric and your docs are both files, so change what your app cares about and the audit changes with it. It does lean on PostHog's schema, which can shift, and a skill that silently drifts is worse than a clunky chart because it still looks like it's working. So put it on a schedule. It's the first to notice when its own assumptions rot.

You don't review your tracking because you can't see what's missing by staring at what's there.

So stop staring. Ask.