PostHog

posthogAnalytics44 lines

Product analytics, feature flags and session replay.

Current — as published in v1.3.2. Written by hand for PostHog, not generated.

The rule

Event naming

object_action, past tense, snake_case:

ts
posthog.capture('subscription_started', { plan: 'annual', source: 'paywall' });
  • Never put a value in the name. plan_selected with a plan property, not plan_selected_annual.
  • Never invent a second convention. Renaming events later does not backfill history, so inconsistency is permanent.

What to track

  • Track decisions and outcomes, not every tap. If you cannot name the question an event answers, do not add it.
  • Analytics calls go through src/services/analytics/, never directly from a component.

Privacy

  • No personal data in properties: no email, name, phone number, address, or message content.
  • Identify by internal user id only.
  • posthog.reset() on sign-out — without it the next user on a shared device inherits the previous person's identity.

Feature flags

  • Never block first render on a flag. Render the default and update when the flag arrives.
  • Always handle the "flag unavailable" case explicitly; the fetch can fail.
  • Remove a flag from the code once it has fully rolled out. Stale flags become permanent dead branches.

Never

  • Never let an analytics failure break a user flow. Wrap it, and let it fail silently.
  • Never send an event containing a token, key or session id.
  • Never point a development build at the production project.

As each tool receives it

The same guidance, in the shape each editor reads. Cursor and Claude Code are written separately by hand; the rest are derived from the Cursor rule.

.cursor/rules/posthog.mdchand-written for this tool
.cursor/rules/posthog.mdc
---
description: PostHog analytics conventions
globs: ["src/**/*.ts", "src/**/*.tsx"]
alwaysApply: false
---

# PostHog

## Event naming

`object_action`, past tense, snake_case:

```ts
posthog.capture('subscription_started', { plan: 'annual', source: 'paywall' });
```

- Never put a value in the name. `plan_selected` with a `plan` property, not
  `plan_selected_annual`.
- Never invent a second convention. Renaming events later does not backfill
  history, so inconsistency is permanent.

## What to track

- Track decisions and outcomes, not every tap. If you cannot name the question
  an event answers, do not add it.
- Analytics calls go through `src/services/analytics/`, never directly from a
  component.

## Privacy

- No personal data in properties: no email, name, phone number, address, or
  message content.
- Identify by internal user id only.
- `posthog.reset()` on sign-out — without it the next user on a shared device
  inherits the previous person's identity.

## Feature flags

- Never block first render on a flag. Render the default and update when the
  flag arrives.
- Always handle the "flag unavailable" case explicitly; the fetch can fail.
- Remove a flag from the code once it has fully rolled out. Stale flags become
  permanent dead branches.

## Never

- Never let an analytics failure break a user flow. Wrap it, and let it fail
  silently.
- Never send an event containing a token, key or session id.
- Never point a development build at the production project.

What else this module writes

Selecting PostHog contributes more than a rule file — all of it merged with every other module you pick, with conflicts resolved rather than duplicated.

Environment
EXPO_PUBLIC_POSTHOG_KEYrequiredProject API key. Write-only, safe in the client.
EXPO_PUBLIC_POSTHOG_HOSTrequiredIngestion host. Replace `<region>` with `eu` or `us` — this decides where your data is stored, so choose deliberately.
POSTHOG_PERSONAL_API_KEYoptionalServer-side API access. Never ship in the app.
Dependencies
posthog-react-native^4.61.0expo-file-system^57.0.0expo-application^57.0.0expo-device^57.0.0expo-localization^57.0.0
Folders
src/services/analytics/
Put this in your repo

Adds PostHog to a project this tool generated, without starting over. Files you have hand-edited are left alone.