Growth
PostHog · Loops · Feature flags · Onboarding checklist
Growth at <$10M ARR is a discipline, not a department. Instrument the AARRR funnel (Acquisition / Activation / Retention / Referral / Revenue), invest 80% of effort in Activation (time-to-value is the only metric that compounds), and run every change behind a feature flag so 'wins' are measurable rather than anecdotal. PostHog covers funnels + flags + experiments; Loops covers lifecycle email; the rest is your discipline.
Primary stack
The default picks this pillar assumes
- Loops
Alternates worth knowing
Swap in when scale, cost or constraints change
- Customer.io
AARRR Instrumentation
Each AARRR stage has a defining event: visited_landing (Acquisition), signed_up (Activation start), activated (Activation done — your magic moment), session_started (Retention), invited_user (Referral), upgraded_plan (Revenue). Define them once, fire from everywhere.
How it flows
step by step- 01step
Catalog all events in lib/posthog/events.ts as typed constants.
- 02step
Fire on the user action, not on a server response — 'signed_up' fires on click, not on webhook.
- 03step
Properties: include orgId, plan, source (utm), platform (web/mobile).
- 04step
PostHog Funnels dashboard charts each stage; cohort by source to find what's working.
Cases & edge cases
watch for theseDon't over-instrument — 30 well-chosen events beat 300 fuzzy ones.
Always identify before capture (posthog.identify) — anonymous events lose meaning.
Event names: snake_case past-tense (paid_invoice, not 'Invoice Paid' or 'pay_invoice').
Checklist
ship readiness- must
5 core AARRR events instrumented
- must
Typed event catalog (no ad-hoc strings)
- should
UTM capture on first touch
Where it lives
code references- lib/posthog/events.ts // typed event catalog
- lib/posthog/funnel.ts
Onboarding Checklist
A 4-6 step checklist users see post-sign-up that walks them to the magic moment. Each step ticks off as they complete it. Dramatically improves activation rate vs. dropping people into an empty app.
How it flows
step by step- 01step
Sign-up complete → /app shows onboarding checklist as a sidebar or modal.
- 02step
Steps: complete profile, invite teammate, create first <core entity>, integrate <key vendor>, hit first 'aha'.
- 03step
Each step has a CTA that deep-links to the relevant screen.
- 04step
Completion fires a `onboarding_step_done` event with step_id; full completion fires 'activated'.
Cases & edge cases
watch for theseMaximum 6 steps. Anything longer is 'I'll do it later' territory.
Make step 1 trivial (set a profile pic). Momentum matters more than substance.
Persist progress per (user, org) — switching orgs resets.
Where it lives
code references- components/onboarding/checklist.tsx
- lib/onboarding/steps.ts
Notes
marginTime-to-value is the metric. Measure: signed_up → activated, p50 and p99. Optimize p50 down.
Activation Magic Moment
The single event that, once a user hits it, makes them likely to retain. Define it explicitly — it's not 'signed up', it's 'did the thing the product is for'. For Slack it's 'sent 2k messages'. For your SaaS, write it down.
How it flows
step by step- 01step
Define the magic moment with the team — concrete event with a threshold.
- 02step
Fire 'activated' event when reached.
- 03step
Funnel: signed_up → activated → returned_7d. Optimize the first arrow.
- 04step
Sanity-check via retention curves: do activated users stick around at ≥80%?
Cases & edge cases
watch for theseWrong magic moments mislead — validate with retention data, not gut.
Multiple personas may have different magic moments — segment when needed.
Don't gamify the metric — your goal is real value, not fake events.
Notes
marginIf you can't articulate your magic moment in one sentence, your onboarding can't optimize for it. Lock this down first.
Feature Flags
Every new significant feature ships behind a flag. Roll out to 1% → 10% → 100% over a week. Kill switch is a config change, not a deploy. PostHog handles flags including multivariate + per-org targeting.
How it flows
step by step- 01step
Create flag in PostHog: my-new-feature, default off.
- 02step
In code: const enabled = await getFlag('my-new-feature', { user, org }).
- 03step
Target by org_id, plan, user role, or % rollout.
- 04step
Promote: 1% → bake 24h → 10% → bake → 100%.
- 05step
Stale flags: weekly review, remove or convert to permanent config.
Cases & edge cases
watch for theseFlags that live > 6 months become liabilities — clean them up.
Server-side evaluation > client-side for security-sensitive flags.
Always wrap the OLD path in 'if (!enabled) { ... }' — you'll need it for rollback.
Where it lives
code references- lib/flags/index.ts // typed flag access
A/B Testing
Run experiments on the changes that matter (pricing copy, onboarding step order, CTA placement). PostHog experiments give you statistical significance; before shipping, you know whether the change actually helped.
How it flows
step by step- 01step
Hypothesis: 'New onboarding copy lifts activation by 10%'.
- 02step
Create experiment in PostHog with control + variant.
- 03step
Define success metric (activation rate in 7 days).
- 04step
Run until significance (PostHog tells you).
- 05step
Ship the winner; document the loser so it doesn't get re-suggested.
Cases & edge cases
watch for theseDon't A/B trivial changes — only run experiments worth ≥5% effort to ship.
Sample size discipline — stop the experiment early ONLY at 95%+ confidence.
Avoid simultaneous overlapping experiments — they confound.
Notes
marginMost experiments lose. The discipline of running them lets you stop debating subjectively.
Lifecycle Email
Email sequences triggered by user state: welcome, day-3 'did you try X?', day-7 inactivity, day-30 'we miss you'. Loops is the 2026 default for solo founders; Customer.io for teams that need complex segmentation.
How it flows
step by step- 01step
Event-triggered campaigns: 'signed_up' → 4-email welcome sequence over 7 days.
- 02step
Behavior-triggered: 'no_login_3_days' (computed in PostHog Action) → re-engagement email.
- 03step
Lifecycle stages: trial, active, paid, churned. Each gets a different email cadence.
- 04step
Unsubscribe per-category, not all-or-nothing.
Cases & edge cases
watch for theseSend transactional via Resend; send lifecycle via Loops — different reputation, different unsubscribe semantics.
Personalization: use first name + use case from onboarding. Generic 'Hi there' converts terribly.
Send at the user's local 'good time' (9am their tz) — providers handle this.
Vendors & tools
what implements thisLoops
primaryModern lifecycle email built for SaaS.
Customer.io
alternateHeavier; better segmentation.
Referral Program
Referred customers convert 3-5x better and have 16% higher LTV. The mechanic: existing user shares a link → friend signs up → referrer gets credit/discount. Built once, runs forever.
How it flows
step by step- 01step
Each user has a unique referral code (shortlink).
- 02step
Sign-up landing detects ?ref=<code> → stores in cookie → attaches to user on sign-up.
- 03step
Referrer gets credit (1 month free, $10 credit, etc.) when referred user activates.
- 04step
Both sides see the reward in-app and via email.
Cases & edge cases
watch for theseReward both sides — pure self-interest from the referrer feels slimy to the friend.
Track via PostHog event 'referral_sent' + 'invitation_accepted' for funnel analysis.
Anti-fraud: same IP / same browser fingerprint counts but is flagged.
Checklist
ship readiness- must
Per-user referral codes
- must
Both-sided reward
- should
Fraud detection on activation event
Apple Pencil draws with pressure. Fingers still scroll. Saved per pillar.