Skip to content

Latest commit

 

History

History
253 lines (181 loc) · 5.48 KB

File metadata and controls

253 lines (181 loc) · 5.48 KB

@posthog/convex

@posthog/convex

PostHog analytics and feature flags for your Convex backend.

npm version

Warning

This package is in alpha and under active development. APIs may change between releases.

🦔 What is this?

The official PostHog component for Convex. Capture events, identify users, manage groups, and evaluate feature flags — all from your mutations and actions.

Found a bug? Feature request? File it here.

🚀 Quick Start

Install the package:

pnpm add @posthog/convex

Register the component in your convex/convex.config.ts:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import posthog from "@posthog/convex/convex.config.js";

const app = defineApp();
app.use(posthog);

export default app;

Set your PostHog API key and host:

npx convex env set POSTHOG_API_KEY phc_your_project_api_key
npx convex env set POSTHOG_HOST https://us.i.posthog.com

Create a convex/posthog.ts file to initialize the client:

// convex/posthog.ts
import { PostHog } from "@posthog/convex";
import { components } from "./_generated/api";

export const posthog = new PostHog(components.posthog);

You can also pass the API key and host explicitly:

export const posthog = new PostHog(components.posthog, {
  apiKey: "phc_...",
  host: "https://eu.i.posthog.com",
});

📊 Capturing Events

Import posthog from your setup file and call methods directly:

// convex/myFunctions.ts
import { posthog } from "./posthog";
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const createUser = mutation({
  args: { email: v.string() },
  handler: async (ctx, args) => {
    const userId = await ctx.db.insert("users", { email: args.email });

    await posthog.capture(ctx, {
      distinctId: userId,
      event: "user_created",
      properties: { email: args.email },
    });

    return userId;
  },
});

capture

Capture an event. Works in mutations and actions.

await posthog.capture(ctx, {
  distinctId: "user_123",
  event: "purchase_completed",
  properties: { amount: 99.99, currency: "USD" },
  groups: { company: "acme-corp" },
});

Options: distinctId, event, properties, groups, sendFeatureFlags, timestamp, uuid, disableGeoip.

identify

Set user properties.

await posthog.identify(ctx, {
  distinctId: "user_123",
  properties: { name: "Jane Doe", plan: "pro" },
});

groupIdentify

Set group properties.

await posthog.groupIdentify(ctx, {
  groupType: "company",
  groupKey: "acme-corp",
  properties: { industry: "Technology", employees: 500 },
});

alias

Link two distinct IDs.

await posthog.alias(ctx, {
  distinctId: "user_123",
  alias: "anonymous_456",
});

All of the above methods schedule the PostHog API call asynchronously via ctx.scheduler.runAfter, so they return immediately without blocking your mutation or action.

🚩 Feature Flags

Feature flag methods evaluate flags by calling the PostHog API and returning the result. They require an action context (they use ctx.runAction internally).

getFeatureFlag

Get a flag's value.

import { posthog } from "./posthog";
import { action } from "./_generated/server";
import { v } from "convex/values";

export const getDiscount = action({
  args: { userId: v.string() },
  handler: async (ctx, args) => {
    const flag = await posthog.getFeatureFlag(ctx, {
      key: "discount-campaign",
      distinctId: args.userId,
    });

    if (flag === "variant-a") {
      return { discount: 20 };
    }
    return { discount: 0 };
  },
});

isFeatureEnabled

Check if a flag is enabled.

const enabled = await posthog.isFeatureEnabled(ctx, {
  key: "new-onboarding",
  distinctId: "user_123",
});

getFeatureFlagPayload

Get a flag's JSON payload.

const payload = await posthog.getFeatureFlagPayload(ctx, {
  key: "pricing-config",
  distinctId: "user_123",
});

getFeatureFlagResult

Get a flag's value and payload in one call.

const result = await posthog.getFeatureFlagResult(ctx, {
  key: "experiment-flag",
  distinctId: "user_123",
});
if (result) {
  console.log(result.enabled, result.variant, result.payload);
}

getAllFlags

Get all flag values for a user.

const flags = await posthog.getAllFlags(ctx, {
  distinctId: "user_123",
});

getAllFlagsAndPayloads

Get all flags and their payloads.

const { featureFlags, featureFlagPayloads } =
  await posthog.getAllFlagsAndPayloads(ctx, {
    distinctId: "user_123",
  });

All feature flag methods accept optional groups, personProperties, groupProperties, sendFeatureFlagEvents, and disableGeoip options. getAllFlags and getAllFlagsAndPayloads also accept flagKeys to filter which flags to evaluate.

📦 Example

See the example app for a working demo.

🛠️ Development

pnpm i
pnpm dev

🤝 Contributing

PRs welcome. See PostHog's contributing guide for general guidelines.

📄 License

MIT