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.comPOSTHOG_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 Cloud | Self-Hosted | |
|---|---|---|
| Setup effort | Minimal | Requires infrastructure |
| Data residency | US or EU region | Your own servers |
| Cost | Free up to 1M events/mo | Infrastructure costs only |
| Maintenance | Managed | You manage upgrades |
| HIPAA / SOC 2 | Available on paid plans | Your 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
user_signed_uporg_createdproject_createdapi_key_created
Upgrade Funnel
quota_warning- Pricing page view
plan_upgraded
AI Adoption Funnel
project_createdai_chat_startedai_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?
Last updated on