Convex
Contents
Convex handles the database, server functions, and real-time sync for your app. PostHog covers what the database doesn't: signups, feature usage, exceptions, AI spend.
This page is the single landing point for using PostHog with Convex. Pick the surfaces you need from the table below. Most teams use three or four together.
Pick what you need
| You want to | Use |
|---|---|
| Capture events and evaluate feature flags from inside Convex functions | @posthog/convex component |
| Stitch frontend and backend events into one user timeline | Frontend + backend stitching |
Trace LLM calls or @convex-dev/agent runs | AI observability |
| Query your Convex tables alongside PostHog event data | Convex data warehouse source |
| Forward Convex logs to PostHog Logs | Convex dashboard log streams (no code) |
| Forward Convex exceptions to PostHog Error Tracking | Convex dashboard exception reporting (no code) |
The first row is what most teams reach for first. The last two are configured in the Convex dashboard with no PostHog-side setup.


Get your PostHog project token
Every integration on this page needs the same two values:
- Project token, starts with
phc_. Found in PostHog under Settings → Project → General → Project API Key. - Host,
https://us.i.posthog.comfor PostHog US Cloud,https://eu.i.posthog.comfor EU Cloud, or your own URL for self-hosted PostHog.
Have those ready before starting any of the sections below.
Capture events and flags from your Convex code
The @posthog/convex component lets you capture events, identify users, evaluate feature flags, and forward exceptions directly from your Convex queries, mutations, and actions. Reach for this surface when you want analytics tied to specific server-side behavior.
1. Install the component
Then register it in convex/convex.config.ts:
2. Set environment variables
For local feature flag evaluation (covered in step 5), also set a feature flags secure API key:
3. Initialize the client
Create convex/posthog.ts. Every other backend function will import the posthog instance from here.
4. Capture events and identify users
capture and identify work in mutations and actions. They schedule the PostHog API call via ctx.scheduler.runAfter, so they return immediately without blocking the caller.
Use the same Convex user ID as the distinctId everywhere. PostHog stitches events onto a single person timeline by matching distinct IDs across sources. See stitching frontend and backend below for the matching frontend setup.
5. Evaluate feature flags
@posthog/convex supports two flag evaluation paths. Default to local evaluation. It's faster (no network round-trip), works in queries (so reading a flag re-runs your query reactively when the flag changes), and works in mutations and actions too. Only reach for remote evaluation when local can't handle the flag (experience continuity flags, static cohorts, flags whose targeting depends on person properties you don't pass in).
- Local (
getFeatureFlag,isFeatureEnabled) runs against flag definitions cached on your Convex deployment. Works in queries, mutations, and actions. No per-call network round-trip. Queries re-run reactively when cached definitions refresh. - Remote (
evaluateFlag,evaluateAllFlags) hits PostHog's/flagsendpoint on every call. Action-only. Handles every flag, including the ones local can't.
To enable local eval, add a cron that refreshes flag definitions on whatever interval suits you:
Then read a flag from a query:
Because this is a regular Convex query, the React client that subscribes to it will re-run and re-render automatically the next time the cron refreshes flag definitions (up to your configured interval, one minute in the example above).
If you're running an experiment against a locally-evaluated flag, fire an exposure event yourself from a mutation or action, since local eval can't schedule capture from inside a query:
A handful of flag types can't be resolved locally (experience continuity flags, static cohorts, flags whose targeting depends on person properties you don't pass in). For those, getFeatureFlag returns null. Call evaluateFlag from an action to hit /flags directly. See the full list of limitations.
6. Capture exceptions with custom properties
If you want every uncaught exception forwarded to PostHog automatically without wrapping each call site, configure Convex's first-party PostHog Error Tracking destination in the Convex dashboard. Use captureException when you want to attach custom properties at a specific call site:
Use the dashboard destination for catch-all coverage. Use captureException here when you need explicit control over the properties on the exception event.
Stitch frontend and backend events together
Convex apps almost always have a frontend talking to a Convex backend. PostHog stitches both sides onto the same person timeline when you use the same distinctId string on both.
Install posthog-js and @posthog/react in your frontend. The example below is React, but the same identity-stitching technique works with any JavaScript framework PostHog supports. The only requirement is that you call posthog.identify() with the same string the backend uses as distinctId.
Initialize PostHog at the root of your app, the same way you would in any React project:
Then, right after a user signs in via Convex Auth (or Clerk, Auth0, etc.), call identify on the frontend with the same Convex user ID your backend uses. The currentUser query referenced below is whatever Convex query exposes the authenticated user to your client (the Convex Auth docs cover defining it):
Mount <AuthSync /> once near the root of your app, inside the <PostHogProvider> and below your Convex <Authenticated> boundary if you have one. The me?._id guard skips the identify call until the user is authenticated.
Now an event captured from a mutation with distinctId: userId and a $pageview from the browser with the same user ID land on the same person in PostHog. Session replays, server-side mutations, exceptions, and logs all land on one timeline for that user.
Trace LLM calls and Convex Agent
If your app calls LLM providers from Convex actions, or uses @convex-dev/agent, pipe the traces into PostHog AI observability. You get token counts, latency, and cost per generation, the full request and response transcript for every model call, and groupings by user, model, and agent run.
Setup uses @posthog/ai and OpenTelemetry rather than the @posthog/convex component. The full installation steps live on the Convex AI observability installation page, covering both vanilla Vercel AI SDK or OpenAI calls and experimental_telemetry on @convex-dev/agent.
Sync Convex tables into PostHog
If you want to query Convex data alongside event data, use the Convex data warehouse source to stream your tables into PostHog's warehouse. You can then query them with SQL, join them to event data, and build insights over the union.
Requires a Convex Professional plan. Convex's streaming export API is gated there.