PostHog

Set up PostHog for product analytics, feature flags, session recording, and funnel analysis in Nebutra.

PostHog is the primary product analytics tool in Nebutra. It tracks in-product behaviour, powers feature flags tied to billing plans, and records sessions for UX debugging.

Prerequisites

  • A PostHog account — posthog.com (Cloud) or a self-hosted instance
  • A Nebutra project with environment variables accessible

Setup

Log in to app.posthog.com (or your self-hosted instance) and create a new project for your Nebutra deployment. Choose the Web platform.

From the PostHog project settings, copy the Project API Key. It starts with phc_.

Add the following to your .env.local (development) and your deployment environment (production):

POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
POSTHOG_HOST=https://app.posthog.com
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_POSTHOG_HOST=https://app.posthog.com

POSTHOG_KEY is used for server-originated product events. NEXT_PUBLIC_POSTHOG_KEY is used by the browser SDK. For EU data residency, use https://eu.posthog.com. For a self-hosted instance, use your own URL (e.g. https://posthog.yourcompany.com).

Start your development server and perform any action (sign up, create a project, etc.). Open PostHog → Live Events and confirm that events appear within a few seconds.

PostHog Cloud vs Self-Hosted

PostHog CloudSelf-Hosted
Setup effortMinimalRequires infrastructure
Data residencyUS or EU regionYour own servers
CostFree up to 1M events/moInfrastructure costs only
MaintenanceManagedYou manage upgrades
HIPAA / SOC 2Available on paid plansYour responsibility

For most early-stage Nebutra deployments, PostHog Cloud (EU region) is the fastest path to compliance without infrastructure overhead.

Custom Event Tracking

Client-Side (Next.js)

import { useAnalytics } from "@nebutra/analytics";

export function CreateProjectButton() {
  const { track } = useAnalytics();

  const handleCreate = async () => {
    const project = await createProject();

    track("project_created", {
      projectId: project.id,
      plan: subscription.plan,
      tenantId: org.id,
    });
  };

  return <button type="button" onClick={handleCreate}>Create Project</button>;
}

Server-Side (API Gateway)

Use createProductAnalyticsClientFromEnv for events that originate in the Hono API layer, where no browser context is available:

import { createProductAnalyticsClientFromEnv } from "@nebutra/analytics";

app.post("/api/v1/checkout/complete", async (c) => {
  const { organizationId, userId, plan } = c.get("tenantContext");
  const analytics = createProductAnalyticsClientFromEnv();

  const checkout = await completeCheckout(c.req);

  await analytics.track("checkout", {
    action: "completed",
    userId,
    organizationId,
    tier: plan,
  });

  return c.json({ success: true, data: checkout });
});

User Identification

Call identify after a user signs in so PostHog can link anonymous pre-login events to the authenticated user:

import { useAnalytics } from "@nebutra/analytics";

export function useAuthEffect(user: User, subscription: Subscription, org: Org) {
  const { identify } = useAnalytics();

  useEffect(() => {
    if (!user) return;

    identify(user.id, {
      email: user.email,
      name: user.name,
      plan: subscription.plan,
      orgId: org.id,
      createdAt: user.createdAt,
    });
  }, [user.id]);
}

identify is called automatically by Nebutra's auth hooks on session start. You only need to call it manually if you update user properties (e.g. after a plan upgrade).

Feature Flags

Feature-flag decisions are owned by @nebutra/feature-flags, not by @nebutra/analytics. PostHog can be used as a future flag provider, but product-event capture and flag evaluation stay separate.

import { useFeatureFlag } from "@nebutra/feature-flags";

export function AiChatButton() {
  const { enabled, loading } = useFeatureFlag("ai_chat");

  if (loading) return <Skeleton />;
  if (!enabled) return <UpgradePrompt feature="AI Chat" />;

  return <button type="button">Open AI Chat</button>;
}

Feature flags are evaluated server-side for API routes through the feature-flags package:

import { isFeatureEnabled } from "@nebutra/feature-flags";

const enabled = await isFeatureEnabled("ai_chat", {
  userId,
  tenantId,
});

Feature flag payloads (e.g. model name, rate limits) are managed in the PostHog UI under Feature Flags. No code deployment is required to update them.

Session Recording

Session recording is enabled by default. It helps debug UX issues by replaying exact user interactions.

Disabling Session Recording

To disable globally, set the following in your PostHog project settings under Session Recording → turn off Record user sessions.

To disable for specific users (e.g. for compliance with enterprise customers who require no data collection):

import { useAnalytics } from "@nebutra/analytics";

const { optOut } = useAnalytics();

// Called when user opts out of analytics in account settings
optOut();

Session recording captures all DOM interactions including form input. Ensure sensitive fields (passwords, card numbers) are masked. Nebutra masks [type="password"] and Stripe iframe elements automatically, but verify any custom payment flows.

Funnel Analysis

PostHog funnels let you measure conversion at each step of your core flows. Recommended funnels to create in your PostHog project:

Activation Funnel

  1. user_signed_up
  2. org_created
  3. project_created
  4. api_key_created

Upgrade Funnel

  1. quota_warning
  2. Pricing page view
  3. plan_upgraded

AI Adoption Funnel

  1. project_created
  2. ai_chat_started
  3. ai_chat_completed

Set the funnel conversion window to 7 days for activation and 30 days for upgrade funnels to capture typical user behaviour.


How is this guide?

Edit on GitHub

Last updated on

On this page