Migrate from...From PostHog

Migrate from PostHog

Most teams complete a PostHog → TrackCrumb migration in one day. This guide covers historical event backfill and SDK swap.

What carries over

PostHog conceptTrackCrumb equivalent
posthog.capture()tracker.track()
posthog.identify()tracker.identify()
Feature flagsFeature Flags (same concept, different UI)
Session replaySession Replay (same concept)
Person propertiesIdentity traits in tracker.identify()

What doesn’t carry over automatically

PostHog featureStatus
Group analyticsNot yet supported — planned Q3 2025
Cohorts (saved)Recreate manually in the dashboard
Dashboards (saved)Recreate manually or use AI chart builder

Migration steps

Export historical events from PostHog

# PostHog export via their API (replace with your project API key)
curl "https://app.posthog.com/api/projects/<project_id>/events/?format=json" \
  -H "Authorization: PersonalApiKey <your_key>" \
  > posthog_events.json
💡

PostHog rate-limits exports to ~100K events/minute. For large workspaces, paginate using the ?after= cursor parameter.

Transform to TrackCrumb Batch API format

// transform.js
const events = require('./posthog_events.json');
 
const transformed = events.results.map(e => ({
  event: e.event,
  distinctId: e.distinct_id,
  timestamp: e.timestamp,
  properties: {
    ...e.properties,
    $migrated_from: 'posthog',
  },
}));
 
require('fs').writeFileSync(
  'st_events.ndjson',
  transformed.map(e => JSON.stringify(e)).join('\n')
);

Ingest via the events API

The ingest endpoint is POST /e. Authenticate with your API key in the X-API-Key header and wrap events in a { "batch": [...] } envelope (max 500 events per request):

# Split into 500-event batches and POST each
split -l 500 st_events.ndjson batch_
for f in batch_*; do
  curl -X POST https://ingest.trackcrumb.com/e \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $ST_API_KEY" \
    -d "{\"batch\": $(jq -s '.' "$f")}"
  sleep 0.5
done

Each line of st_events.ndjson must match the event payload shape.

Install the TrackCrumb SDK

Remove posthog-js and install @trackcrumb/sdk. Replace all posthog.capture() calls with tracker.track() and all posthog.identify() calls with tracker.identify().

Remove PostHog

npm uninstall posthog-js
# or
bun remove posthog-js

Verify

Open the dashboard Trends view. Confirm historical events are visible and new events are arriving.

Property name mapping

PostHog auto-captures some properties with $ prefix. If you relied on these:

PostHog propertyHow to replicate
$current_urlPass url: window.location.href in track() properties
$browserParse from User-Agent, or omit
$osParse from User-Agent, or omit
$screen_widthPass screenWidth: window.screen.width

Need help?

Reach us at [email protected]. We’ll pair with you on the migration if your workspace is > 10M events.