Migrate from PostHog
If your product already calls PostHog for events, identify, and feature flags, you can move it to Databuddy without rewriting those call sites. The @databuddy/sdk package ships adapters that keep PostHog's method names and argument shapes, so most of the migration is changing three import paths.
Change the imports
bun remove posthog-js posthog-node
bun add @databuddy/sdkBrowser
Pass your Databuddy client ID where PostHog expected a project token. PostHog transport options such as api_host, defaults, and person_profiles still compile and are ignored, because events always go to Databuddy.
import posthog from '@databuddy/sdk/posthog';
posthog.init(process.env.NEXT_PUBLIC_DATABUDDY_CLIENT_ID!, {
capture_exceptions: true,
trackWebVitals: true,
});
posthog.identify(user.id, { email: user.email, plan: user.plan });
posthog.capture('checkout_completed', { total: 49 });
posthog.onFeatureFlags(() => {
if (posthog.isFeatureEnabled('new-checkout')) {
showNewCheckout();
}
});The second argument also accepts every Databuddy configuration option, so you can turn on Web Vitals, outgoing link tracking, or path masking in the same call.
Feature flags load asynchronously, so read them inside onFeatureFlags(), which runs once flags are ready and again after every reload. Calling identify() or group() re-evaluates flags for that user and group, and the callback runs again with the new values, so targeting rules on traits such as plan apply as soon as the user signs in.
React
import {
PostHogProvider,
useFeatureFlagEnabled,
} from '@databuddy/sdk/posthog/react';
export function Providers({ children }: { children: React.ReactNode }) {
return (
<PostHogProvider apiKey={process.env.NEXT_PUBLIC_DATABUDDY_CLIENT_ID!}>
{children}
</PostHogProvider>
);
}
function CheckoutButton() {
const newCheckout = useFeatureFlagEnabled('new-checkout');
return newCheckout ? <NewCheckout /> : <Checkout />;
}usePostHog, useFeatureFlagVariantKey, useFeatureFlagPayload, and PostHogFeature are available with the same signatures.
Server
The server adapter needs a Databuddy API key with the track:events scope and the website ID the events belong to.
import { PostHog } from '@databuddy/sdk/posthog/node';
import { waitUntil } from '@vercel/functions';
const posthog = new PostHog(process.env.DATABUDDY_API_KEY!, {
websiteId: process.env.DATABUDDY_WEBSITE_ID!,
waitUntil,
});
posthog.capture({ distinctId: user.id, event: 'invoice_paid' });
const variant = await posthog.getFeatureFlag('pricing-page', user.id, {
personProperties: { plan: user.plan },
});In serverless functions, either pass waitUntil so each capture is delivered before the function freezes, or call await posthog.shutdown() before returning. flushAt, flushInterval, requestTimeout, and disabled keep their PostHog meaning. getAllFlags and getAllFlagsAndPayloads return every flag for a user when you bootstrap flags during server rendering.
What changes
Most calls behave the same, but a few PostHog concepts map differently or have no Databuddy equivalent yet.
How is this guide?