tools-posthog

Standard pattern for implementing freemium/pro features with PostHog feature flags, usage tracking, upgrade prompts, and Stripe-ready payment hooks. Use when adding any feature that will eventually be paid.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tools-posthog" with this command: npx skills add aussiegingersnap/cursor-skills/aussiegingersnap-cursor-skills-tools-posthog

Feature Gating Skill

Pattern for implementing freemium/pro features with per-user feature flags, usage measurement, and payment-ready architecture.

When to Use

  • Adding a feature that will eventually be paid/pro-only
  • A/B testing feature availability
  • Gradual rollouts to user segments
  • Gating existing features for pro users
  • Measuring demand before building paywall

Architecture Overview

┌─────────────────────────────────────────────────────────┐
│                     PostHog                              │
│  ┌─────────────────────────────────────────────────────┐│
│  │ Feature Flag: cloud-notes-sync                      ││
│  │ Targeting: plan = 'pro' OR beta-tester = true       ││
│  └─────────────────────────────────────────────────────┘│
└──────────────────────┬──────────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────────┐
│                    Client                                │
│  ┌─────────────────┐  ┌────────────────────────────────┐│
│  │ useProFeature() │──│ Feature Component              ││
│  │ - enabled       │  │ - Show feature if enabled      ││
│  │ - trackAttempt  │  │ - Show upgrade prompt if not   ││
│  └─────────────────┘  └────────────────────────────────┘│
└──────────────────────────────────────────────────────────┘

Part 1: PostHog Feature Flags

Naming Convention

Use descriptive, kebab-case names:

{feature-name}-enabled

Examples:
- cloud-notes-sync
- advanced-models
- export-features
- unlimited-messages

Creating Flags in PostHog Dashboard

  1. Go to Feature FlagsNew Feature Flag
  2. Key: cloud-notes-sync
  3. Rollout: Start at 0% (disabled)
  4. Targeting (when ready to enable):
    • Beta testers: beta-tester is true
    • Pro users: plan is pro
    • Percentage rollout: 10% → 50% → 100%

PostHog User Properties (for targeting)

Set these properties when user state changes:

// When user subscribes
posthog.setPersonProperties({ 
  plan: 'pro',
  subscribed_at: new Date().toISOString(),
})

// When user joins beta
posthog.setPersonProperties({ 
  'beta-tester': true,
})

Part 2: Feature Flag Hooks

Basic Hook

// hooks/useFeatureFlags.ts

import { useEffect, useState, useCallback } from 'react'
import { posthog } from '@/lib/posthog'

export function useFeatureFlag(flagKey: string): boolean {
  const [enabled, setEnabled] = useState(false)
  
  useEffect(() => {
    if (typeof window === 'undefined') return
    
    const checkFlag = () => {
      const value = posthog.isFeatureEnabled(flagKey)
      setEnabled(value ?? false)
    }
    
    if (posthog.__loaded) checkFlag()
    posthog.onFeatureFlags(checkFlag)
  }, [flagKey])
  
  return enabled
}

Pro Feature Hook (with tracking)

export function useProFeature(flagKey: string): {
  enabled: boolean
  loading: boolean
  trackAttempt: () => void
  trackUpgradeShown: () => void
  trackUpgradeClicked: () => void
} {
  const [enabled, setEnabled] = useState(false)
  const [loading, setLoading] = useState(true)
  
  useEffect(() => {
    const checkFlag = () => {
      setEnabled(posthog.isFeatureEnabled(flagKey) ?? false)
      setLoading(false)
    }
    
    if (posthog.__loaded) checkFlag()
    posthog.onFeatureFlags(checkFlag)
  }, [flagKey])
  
  const trackAttempt = useCallback(() => {
    posthog.capture(`${flagKey}_attempted`)
  }, [flagKey])
  
  const trackUpgradeShown = useCallback(() => {
    posthog.capture(`${flagKey}_upgrade_shown`)
  }, [flagKey])
  
  const trackUpgradeClicked = useCallback(() => {
    posthog.capture(`${flagKey}_upgrade_clicked`)
  }, [flagKey])
  
  return { enabled, loading, trackAttempt, trackUpgradeShown, trackUpgradeClicked }
}

Typed Convenience Hooks

Create specific hooks for each feature:

export function useCloudNotesSync() {
  return useProFeature('cloud-notes-sync')
}

export function useAdvancedModels() {
  return useProFeature('advanced-models')
}

Part 3: Usage Tracking Events

Track feature usage to measure demand and conversion:

Event Schema

EventWhenProperties
{feature}_attemptedUser tries to use gated feature{ feature }
{feature}_completedFeature used successfully{ feature, duration_ms? }
{feature}_upgrade_shownUpgrade prompt displayed{ feature, trigger }
{feature}_upgrade_clickedUser clicked upgrade CTA{ feature }

Implementation

// Track when user tries to use feature
const handleFeatureClick = () => {
  if (!cloudSync.enabled) {
    cloudSync.trackAttempt()
    cloudSync.trackUpgradeShown()
    setShowUpgradeModal(true)
    return
  }
  // ... feature logic
}

Part 4: Upgrade Prompt Patterns

Modal Pattern

function UpgradeModal({ feature, onClose }: { feature: string; onClose: () => void }) {
  const { trackUpgradeClicked } = useProFeature(feature)
  
  return (
    <Dialog open onOpenChange={onClose}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Upgrade to Pro</DialogTitle>
        </DialogHeader>
        <div className="space-y-4">
          <p>Get access to cloud sync and more for just $7/month.</p>
          <ul className="space-y-2">
            <li>✓ Sync notes across devices</li>
            <li>✓ Cloud backup</li>
            <li>✓ Export options</li>
          </ul>
          <Button 
            onClick={() => {
              trackUpgradeClicked()
              window.location.href = '/pricing'
            }}
          >
            Upgrade Now — $7/mo
          </Button>
        </div>
      </DialogContent>
    </Dialog>
  )
}

Inline Lock Pattern

function FeatureLock({ 
  feature, 
  children 
}: { 
  feature: string
  children: React.ReactNode 
}) {
  const { enabled, loading, trackAttempt, trackUpgradeShown } = useProFeature(feature)
  
  if (loading) return <Skeleton />
  
  if (!enabled) {
    useEffect(() => {
      trackAttempt()
      trackUpgradeShown()
    }, [])
    
    return (
      <div className="relative">
        <div className="opacity-50 pointer-events-none blur-sm">
          {children}
        </div>
        <div className="absolute inset-0 flex items-center justify-center">
          <ProBadge />
          <span>Pro Feature</span>
        </div>
      </div>
    )
  }
  
  return <>{children}</>
}

Part 5: Stripe-Ready Architecture

Structure code so payment integration is additive:

Current (Pre-Stripe)

// User properties are set manually or via feature flags
posthog.setPersonProperties({ plan: 'free' })

Future (With Stripe)

// After Stripe webhook confirms subscription
const handleSubscriptionCreated = async (subscription: Stripe.Subscription) => {
  const plan = subscription.items.data[0].price.lookup_key // 'pro' or 'free'
  
  // Update PostHog for feature flag targeting
  posthog.setPersonProperties({ 
    plan,
    stripe_customer_id: subscription.customer,
    subscribed_at: new Date().toISOString(),
  })
  
  // PostHog flag `cloud-notes-sync` targets `plan: 'pro'`
  // Features automatically unlock
}

Pricing Page Structure

// app/pricing/page.tsx
export default function PricingPage() {
  return (
    <div className="grid md:grid-cols-2 gap-6 max-w-4xl mx-auto">
      <PricingCard
        plan="Free"
        price="$0"
        features={[
          'Local notes storage',
          '50 AI messages/day',
          'Basic Bible reading',
        ]}
        cta="Current Plan"
        disabled
      />
      <PricingCard
        plan="Pro"
        price="$7"
        period="/month"
        features={[
          'Cloud sync across devices',
          'Unlimited AI messages',
          'Advanced AI models',
          'Export notes & highlights',
          'Priority support',
        ]}
        cta="Upgrade to Pro"
        highlighted
        onClick={() => {/* Stripe checkout */}}
      />
    </div>
  )
}

Part 6: Implementation Checklist

When adding a new pro feature:

Setup

  • Create PostHog feature flag in dashboard
  • Add typed hook in useFeatureFlags.ts
  • Export from hooks barrel file

Implementation

  • Use hook in feature component
  • Gate feature behind enabled check
  • Show upgrade prompt when !enabled

Tracking

  • Track _attempted when user tries to use
  • Track _upgrade_shown when prompt displays
  • Track _upgrade_clicked when user clicks CTA
  • Track _completed when feature is used successfully

Documentation

  • Add to TASKS.md if significant feature
  • Document in this skill if pattern evolves

Quick Reference

ItemPattern
Flag naming{feature-name} (kebab-case)
HookuseProFeature('flag-key')
TrackingtrackAttempt(), trackUpgradeShown(), trackUpgradeClicked()
TargetingSet plan: 'pro' in PostHog properties
Typical price$5-15/month for indie SaaS

Example Use Cases

FeatureFreePro
Cloud syncLocal storage onlyCross-device sync
API usage25 calls/dayUnlimited
AI modelsGPT-4o-miniClaude, GPT-4o, etc.
ExportNonePDF, Markdown
SupportCommunityPriority

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tools-repo-review

No summary provided by upstream source.

Repository SourceNeeds Review
General

db-postgres

No summary provided by upstream source.

Repository SourceNeeds Review
General

ui-principles

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-rest

No summary provided by upstream source.

Repository SourceNeeds Review