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_selectedwith aplanproperty, notplan_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.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.