Skip to content
posthog-cost-tuning logo

PostHog Cost Tuning

posthog-cost-tuning

Optimize PostHog costs: autocapture tuning, event sampling with before_send,

SKILL.md

Full skill instructions

PostHog Cost Tuning

Overview

PostHog Cloud pricing is event-based: 1M events/​month free, then usage-based pricing beyond that. Session recordings, feature flag evaluations, and surveys each have their own free tiers. The biggest cost drivers are typically $autocapture events, $pageview on high-traffic pages, and bot traffic. This skill covers specific techniques to reduce event volume without losing analytical value.

Prerequisites

  • PostHog Cloud account with billing access
  • Application instrumented with posthog-js
  • Understanding of which events drive your analytics

PostHog Cloud Free Tiers (2025)

ProductFree TierOverage
Product analytics1M events/​month~$0.00031/​event
Session recordings5K sessions/​month~$0.04/​session
Feature flags1M API requests/​month~$0.0001/​request
Surveys250 responses/​month~$0.10/​response

Instructions

Step 1: Audit Current Event Volume

set -euo pipefail
# See which events consume the most quota (last 30 days)
curl "https://app.posthog.com/​api/​projects/​$POSTHOG_PROJECT_ID/​query/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  -H "Content-Type: application/​json" \
  -d '{
    "query": {
      "kind": "HogQLQuery",
      "query": "SELECT event, count() AS total FROM events WHERE timestamp > now() - interval 30 day GROUP BY event ORDER BY total DESC LIMIT 20"
    }
  }' | jq '.results[] | {event: .[0], count: .[1]}'

Step 2: Tune Autocapture

$autocapture is often the largest event volume. Restrict it to only useful interactions.

import posthog from 'posthog-js';

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: 'https://us.i.posthog.com',
  autocapture: {
    // Only capture click and submit events (skip change, scroll, etc.)
    dom_event_allowlist: ['click', 'submit'],
    // Only capture meaningful elements
    element_allowlist: ['a', 'button', 'form', 'input[type=submit]'],
    // Only capture elements with this CSS class
    css_selector_allowlist: ['.track-click', '[data-track]'],
    // Skip internal/​admin pages entirely
    url_ignorelist: ['/​admin', '/​health', '/​api/​internal', '/​_next'],
  },
});

Step 3: Event Sampling with before_send

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: 'https://us.i.posthog.com',
  before_send: (event) => {
    // 1. Always send business-critical events (no sampling)
    const critical = ['purchase', 'signup', 'subscription_started', 'subscription_canceled', 'error'];
    if (critical.includes(event.event)) return event;

    // 2. Drop bot traffic entirely
    const ua = navigator?.userAgent?.toLowerCase() || '';
    if (/​bot|crawler|spider|scrapy|headless|phantom|puppeteer/​i.test(ua)) {
      return null;
    }

    // 3. Sample pageviews to 25% on high-traffic pages
    if (event.event === '$pageview') {
      const highTraffic = ['/', '/​pricing', '/​blog'];
      const url = event.properties?.$current_url || '';
      if (highTraffic.some(p => url.endsWith(p))) {
        return Math.random() < 0.25 ? event : null;
      }
      return event; // Keep other pageviews at 100%
    }

    // 4. Sample autocapture to 20%
    if (event.event === '$autocapture') {
      return Math.random() < 0.2 ? event : null;
    }

    // 5. Sample pageleave to 50%
    if (event.event === '$pageleave') {
      return Math.random() < 0.5 ? event : null;
    }

    return event; // Keep all other events
  },
});

Step 4: Optimize Session Recording Costs

posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: 'https://us.i.posthog.com',
  session_recording: {
    // Record only 10% of sessions (saves 90% on recording costs)
    sampleRate: 0.1,
    // Don't record sessions shorter than 5 seconds (bounces)
    minimumDurationMilliseconds: 5000,
    // Record 100% of sessions with errors (most valuable for debugging)
    // This is configured in PostHog dashboard under Session Replay settings
  },
});

// Alternatively: disable recording for non-paying users
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
  api_host: 'https://us.i.posthog.com',
  disable_session_recording: true, // Start disabled
});

// Enable only for paying users
if (user.plan !== 'free') {
  posthog.startSessionRecording();
}

Step 5: Monitor Usage and Set Alerts

set -euo pipefail
# Check current month's event usage
curl "https://app.posthog.com/​api/​projects/​$POSTHOG_PROJECT_ID/​query/" \
  -H "Authorization: Bearer $POSTHOG_PERSONAL_API_KEY" \
  -H "Content-Type: application/​json" \
  -d '{
    "query": {
      "kind": "HogQLQuery",
      "query": "SELECT count() AS total_events, uniq(distinct_id) AS unique_users, count() / dateDiff('"'"'day'"'"', toStartOfMonth(now()), now()) AS events_per_day FROM events WHERE timestamp > toStartOfMonth(now())"
    }
  }' | jq '.results[0] | {
    total_events: .[0],
    unique_users: .[1],
    avg_events_per_day: .[2],
    projected_monthly: (.[2] * 30),
    over_free_tier: (.[2] * 30 > 1000000)
  }'
// Automated cost monitoring
async function checkPostHogBudget() {
  const result = await queryPostHog(`
    SELECT count() AS events_this_month
    FROM events
    WHERE timestamp > toStartOfMonth(now())
  `);

  const eventsThisMonth = result.results[0][0];
  const FREE_TIER = 1_000_000;
  const projectedMonthly = eventsThisMonth / (new Date().getDate() / 30);

  if (projectedMonthly > FREE_TIER * 0.8) {
    // Alert: approaching free tier limit
    await sendSlackAlert(`PostHog usage alert: ${Math.round(projectedMonthly / 1000)}K events projected this month (free tier: 1M)`);
  }
}

Cost Reduction Estimates

TechniqueTypical ReductionImpact on Analytics
Restrict autocapture elements40-60%Low (keep meaningful clicks)
Filter bot traffic10-30%None (bots are noise)
Sample $pageview on high-traffic20-40%Low (trends still accurate)
Session recording at 10%90% on recordingsMedium (fewer sessions to review)
Disable $pageleave15-20%Low (rarely analyzed)

Error Handling

IssueCauseSolution
Event volume spikeNew feature without volume estimateForecast events before launch
Bill higher than expectedBot trafficAdd bot filtering in before_send
Missing critical eventsSampling too aggressiveExclude revenue events from sampling
Free tier exceeded mid-monthAutocapture too broadRestrict to .track-click elements only

Output

  • Autocapture restricted to meaningful interactions
  • Event sampling reducing volume by 30-50%
  • Bot traffic filtered
  • Session recording sampled to 10%
  • Budget monitoring with alerting

Resources

More skills from jeremylongshore

openrouter-compliance-review logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-compliance-review

Review OpenRouter integration for regulatory compliance (SOC2, GDPR,

2.8K 0
View
maintainx-data-handling logo
jeremylongshore/claude-code-plugins-plus-skills

maintainx-data-handling

Data synchronization, ETL patterns, and data management for MaintainX.

2.8K 0
View
groq-core-workflow-a logo
jeremylongshore/claude-code-plugins-plus-skills

groq-core-workflow-a

Execute Groq primary workflow: chat completions with tool use and JSON

2.8K 0
View
validating-csrf-protection logo
jeremylongshore/claude-code-plugins-plus-skills

validating-csrf-protection

Validate CSRF protection implementations for security gaps. Use when

2.8K 0
View
api-contract logo
jeremylongshore/claude-code-plugins-plus-skills

api-contract

Configure this skill should be used when the user asks about "API contract",

2.8K 0
View
ideogram-incident-runbook logo
jeremylongshore/claude-code-plugins-plus-skills

ideogram-incident-runbook

Execute Ideogram incident response with triage, mitigation, and postmortem.

2.8K 0
View
gamma-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

gamma-sdk-patterns

Reusable patterns for the Gamma REST API (no SDK exists).

2.8K 0
View
deepgram-sdk-patterns logo
jeremylongshore/claude-code-plugins-plus-skills

deepgram-sdk-patterns

Apply production-ready Deepgram SDK patterns for TypeScript and Python.

2.8K 0
View
openrouter-upgrade-migration logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-upgrade-migration

Migrate to OpenRouter from direct provider APIs or upgrade between SDK/model

2.8K 0
View
openrouter-common-errors logo
jeremylongshore/claude-code-plugins-plus-skills

openrouter-common-errors

Diagnose and fix common OpenRouter API errors. Use when encountering

2.8K 0
View
linear-cost-tuning logo
jeremylongshore/claude-code-plugins-plus-skills

linear-cost-tuning

Optimize Linear API usage, reduce unnecessary calls, and maximize

2.8K 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View