Migrate from Heap to PostHog

Moving from Heap to PostHog is mainly a data export and identity problem, and the export path you can use depends on your Heap plan. This page sets out what moves cleanly, what needs rework and how to sequence the work.

On this page

How to migrate from Heap to PostHog without losing history you need

The migration is an export, identity and rebuild project, and its scope depends on which Heap plan you hold. The data you can move is limited by what Heap will release to you, so the first task is to confirm your plan and your data history window before anything else. Product analytics owners usually lead this work, with data engineering support for the export, the transformation and the replay of events into PostHog. Your Heap account owner or a Heap contact should confirm in writing which export path your contract includes. There are two export paths. Heap Connect syncs data to S3, Redshift, BigQuery or Snowflake, and it is only available on Heap's Pro or Premier plans. If you are on a lower tier, you can request a one-time JSON export from Heap support, which also requires a paid plan. In both cases, the chart view CSV export does not contain the data you need to rebuild events, so do not plan around it. Ask Heap what data history is retained on your account, because anything older than that window cannot be recovered through either path.

Effort and risk concentrate in three places: querying each event table separately (the all_events table lacks properties), mapping Heap's user_id and identity to PostHog identities, and deciding which historical events and person properties are worth re-sending. PostHog's Heap guide uses posthog.alias() for identity linking and $set and $set_once for person properties, and it sends historical events with the historical_migration flag on a paid product analytics plan. Historical imports are not deduplicated, and there is no way to selectively delete imported event data, so run a small test batch and agree the event mapping with your analysts before a full load. Confirm durations and staffing with your data engineering team against your own event volume, since none are fixed in the guide.

Which Heap capabilities map cleanly to PostHog and which need rework

This table compares the main Heap capabilities with their closest PostHog equivalents and marks each as clean, needs rework or gap. Read the status column first, then check the notes for what must be rebuilt during migration. Most product analytics events move across, but retroactive virtual events and historical definitions must be recreated in PostHog before teams rely on them.

Heap capabilityPostHog equivalentStatus
AutocaptureAutocapture and actions in PostHog. Confirm the autocapture settings on your domains before you compare event counts.Needs rework
Virtual events defined retroactivelyActions or HogQL queries built in PostHog. Retroactive definitions do not carry over, so each one must be rewritten from its logic.Needs rework
User and identity model (user_id, identity)Identities linked with posthog.alias() and person properties set with $set and $set_once, following PostHog's Heap guide.Needs rework
Event and property history from Heap Connect or JSON exportHistorical import with the historical_migration flag, requiring a paid PostHog product analytics plan. Each event table is queried separately.Needs rework
Funnels, retention and dashboardsPostHog insights, funnels and dashboards. Rebuild each saved Heap report with its definitions and check results against a known period.Needs rework
Session replayPostHog session replay. Replays start recording only after the new SDK is deployed, so historical sessions are not available. Confirm coverage with PostHog before you rely on it.Gap
SurveysPostHog surveys. Confirm the features you use and whether they cover your site before you rely on them.Gap
Data export to your warehousePostHog data pipelines and the same warehouse destinations, kept as a separate export path from Heap Connect.Clean

Which exports and identities move from Heap to PostHog

Moving history out of Heap depends on two things: getting the event data out through a paid export path, and rebuilding user identity so events attach to the right people in PostHog. The cards below cover the export options, the query pitfalls that cause incomplete data, and how identities and person properties are carried across.

Heap Connect warehouse export

Heap Connect syncs event data to S3, Redshift, BigQuery or Snowflake, and PostHog's Heap guide documents it as the export path. It is only available on Heap's Pro or Premier plans, so confirm your current plan and the warehouse you can receive into before you assume this route is open. Ask Heap in writing which tables and history window your contract includes.

One-time JSON export from support

If Heap Connect is not available to you, PostHog's guide describes a one-time JSON export that you request from Heap support. This route requires a paid Heap plan. Ask support for the export format, the date range covered and the delivery method, and confirm that it includes the properties you need for each event.

Why chart CSV exports fall short

The CSV you download from a Heap chart view is aggregated output, not the raw event records PostHog needs. Teams that start here often migrate counts without user-level detail. Treat chart exports as a reference for checking totals after import, not as the migration source.

Querying each event table separately

PostHog's guide notes that the all_events table lacks event properties, so each event table must be queried on its own and its properties kept. Build an inventory of event tables from your warehouse export before you write any conversion code, and check row counts per table against Heap's own reports.

Aliasing Heap user IDs

PostHog's guide links Heap's user_id and identity values to PostHog users with posthog.alias(), so historical events join to the same person as new ones. Decide which Heap identifier is canonical before aliasing, because a mismatch splits one person into two profiles that cannot be merged later.

Person properties with $set and $set_once

Person properties are written with $set, which overwrites values, and $set_once, which only fills a value that is not yet set. Use $set_once for attributes such as first-seen source and $set for values that change, such as plan tier. Send these with the historical_migration flag and confirm the flag behaves as expected on a small test batch.

The migration sequence from inventory to decommission

This sequence moves Heap's data and tracking into PostHog in an order that keeps a fallback in place until the team has checked the results. Each step has a named output, so the team can confirm progress before moving on.

  1. Inventory events, properties, users and integrations

    The analytics owner and a data engineer list every event definition, property, user identity field and integration in the Heap project, including autocaptured events that someone may rely on in a dashboard. They also list every dashboard, saved report, funnel and downstream system that reads Heap data. Output: a written inventory with an owner and a keep, rebuild or drop decision for each item. Confirm the list with the people who own each dashboard before any data leaves Heap, because the Heap data is the source for every later step.

  2. Confirm the Heap export path and plan

    Decide how the data will leave Heap. Heap Connect, which PostHog's Heap guide lists as an export to S3, Redshift, BigQuery or Snowflake, is available only on Heap's Pro or Premier plans. A one-time JSON export is requested from Heap support and also requires a paid Heap plan. Confirm with Heap which plan and export option apply to your contract, the data history retained on that plan, and whether Heap Connect or the JSON export will cover the full history you need. Output: a signed-off export method and a written confirmation from Heap.

  3. Pilot import with the historical_migration flag

    Choose a narrow pilot scope, such as one event table and a limited date range, and agree it in writing before any import. Export those tables, convert events and users following PostHog's Heap guide, alias Heap's user_id and identity with posthog.alias(), and send the events with the historical_migration flag. This needs a paid PostHog product analytics plan. Imports cannot be selectively deleted once loaded, so a mistake in the pilot scope stays in the project. Output: a pilot dataset in PostHog that the team has checked row by row against the Heap source for counts, property values and user matching.

  4. Rebuild dashboards and validate the pilot

    Recreate the highest-priority dashboards and funnels in PostHog using the pilot data and the inventory from the first step. Compare each rebuilt chart with the Heap original for the same period and document any difference, including differences caused by Heap's retroactive definitions that PostHog does not reproduce in the same way. Output: a comparison log signed off by the analytics owner, with each gap either fixed or accepted as a known change.

  5. Run both tools in parallel

    Send new events to Heap and PostHog at the same time, using the SDK configuration that the engineering team controls. Set up an agreed set of reconciliation checks, such as daily event counts per key event and sample user journeys, and assign someone to review them. Output: a record showing that the two tools agree within the tolerance the team agreed in advance. Keep the parallel run in place until the checks pass consistently for the period the team sets, and note that PostHog's self-hosted deployments are officially unsupported with no vendor support for infrastructure questions, so the internal operations owner must hold that responsibility if you self-host.

  6. Cut over dashboards and SDKs

    Point dashboards, alerts, reports and downstream consumers to PostHog, and remove the Heap SDK from front-end and back-end code in a release that engineering tests in staging first. Update consent and tracking notices where they name Heap as a processor. Output: a change record that lists every consumer moved, the release that removed Heap tracking, and a sign-off from each dashboard owner that their reports match expectations.

  7. Decommission Heap after a retention check

    Before ending the Heap contract, export and store any data the organization must keep for legal, financial or audit reasons, and confirm with Heap what remains accessible after cancellation. Check the retention position in PostHog against your policy, including the retention limit of the plan you chose. Output: a decommission record showing the final export archive, the retention policy applied, confirmation from Heap that the account is closed, and the date each Heap integration was disabled.

How the event tables, users and aliases are converted

The conversion starts with the export shape. PostHog's Heap guide has you query each Heap event table separately, because the all_events table lacks properties. Each table holds one event type with its properties, so your script reads a table per event, maps the Heap event name and its property names to the PostHog event name and property keys you chose, and sends each row as a PostHog event with its original timestamp. Build that mapping as a written table before you write code. Confirm with your team which Heap autocaptured events you want to carry over, because a faithful copy of every autocaptured click can add events you never report on. Keep the event and property mapping under version control so the same conversion can be rerun and reviewed.

Identities need the most care. The guide links Heap's user_id and identity to PostHog with posthog.alias(), so the anonymous or device-level identifiers from Heap resolve to the same person as the identified user. Person properties are set with $set for values that should follow the latest state and $set_once for values that should keep the first value seen, such as a first acquisition source. Decide which Heap user properties are current state and which are historical facts before choosing between the two. Send history with the historical_migration flag so the imported events are handled as past data rather than live traffic.

Scripting is the only documented route for Heap. PostHog's managed migrations import historical events directly from Mixpanel and Amplitude, but each direct job covers at most one year and does not apply to Heap, so your team owns the export, transform and send steps. Those managed jobs also do not deduplicate events. Your Heap script has the same exposure, so run a test batch on a short date range, count events per table and per day in both systems, and rerun a batch only after you remove the previous one, since PostHog provides no selective deletion of imported event data. Treat the deduplication check as a required step in the cutover plan, not an optional one.

How the migration changes by starting point and hosting choice

If your Heap contract includes Heap Connect, you can sync raw event and user tables to a warehouse you control. PostHog's Heap guide lists Amazon S3, Amazon Redshift, Google BigQuery and Snowflake as the destinations to use. Heap Connect is available only on the Pro or Premier plans, so confirm the tier on your order form before you plan around it.

  • Pick the destination first: choose the warehouse you already operate, since the export lands there before PostHog reads it.
  • Query each event table: the all_events table lacks properties, so export every event table separately.
  • Avoid chart CSVs: chart view CSV exports do not carry the data the migration needs.
  • Map identities early: plan the posthog.alias() calls for Heap user_id values before the first import.
  • Check the sync window: confirm with Heap how far back the synced tables reach under your data history setting.

Ask Heap in writing which tables are included in your Connect configuration and whether historical backfill is part of it.

What drives the cost and duration of a Heap to PostHog move

This table lists each cost component of a Heap to PostHog move, who is paid for it, whether it is one-time or recurring, and what pushes it up or down. Use it to see which quotes to request before committing to a timeline. Heap's export pricing is not published, so the first row is the one most likely to change your budget.

Cost componentWho is paidOne-time or recurringWhat drives it up
Heap plan and data export accessHeap (plan fee and any Heap Connect or export charge, unpublished, so ask Heap in writing)Recurring while the plan runs, plus any one-time export feeHeap Connect is only on Pro or Premier plans, and a one-time JSON export requires a paid plan, so a lower tier may need an upgrade first
PostHog Cloud usage or self-hosted infrastructurePostHog (Cloud usage) or your cloud provider and staff (self-hosted)RecurringEvent volume, since PostHog's README says open-source deployments should scale to about 100k events per month and points larger teams to Cloud; the hobby deployment starts from 4 vCPU, 16 GB RAM and more than 30 GB storage per PostHog's self-host docs
Historical import and paid PostHog planPostHog, for the paid product analytics plan that unlocks the historical_migration import featuresRecurring while the plan is active, with historical events ingested free of ingestion fees when sent with the historical_migration flagLength of history you import, since there is no way to selectively delete imported event data
Engineering time for conversion scriptsYour engineers or an implementation partnerOne-timeNumber of event types and properties, and how many per-event tables must be queried separately because the all_events table lacks properties
SDK and identity changesYour engineers or an implementation partnerOne-timeNumber of tracked pages and apps, and how many user_id and identity links need posthog.alias() and $set or $set_once person properties
Dashboard and funnel rebuildYour analysts or an implementation partnerOne-timeNumber of dashboards, saved funnels and reports, and whether session replay must be recreated alongside them
Internal QA and parallel runningYour team, with time for comparing Heap and PostHog countsOne-time, with ongoing operations after cutoverStrictness of reconciliation requirements, and whether regulated reporting depends on the migrated history
Operations and supportYour team or a retained support partner, since PostHog does not offer support for self-hosted instancesRecurringSelf-hosting ownership, upgrades, backups and on-call coverage, all of which grow with the number of services you operate

What usually goes wrong in a Heap to PostHog migration

Most failed Heap exits trace back to a few decisions made early: which Heap plan holds the data, how identities are merged, and who runs PostHog after go-live. The cards below pair each risk with a check to run before the export starts, so the gaps surface while Heap is still available.

Plan lacks the export path

Heap Connect is only available on Heap's Pro or Premier plans, and the one-time JSON export requires a paid Heap plan. A team on a lower tier can find out at renewal or cancellation that the data it needs cannot be pulled out. Confirm in writing with Heap which plan and add-on you hold, whether Heap Connect is included, and how the JSON export is requested before you give notice.

Chart CSV exports mistaken for full data

Chart view CSV exports do not provide the event-level data a migration needs, so a team that exports only charts ends up with aggregates it cannot replay. Each event table must also be queried separately, since the all_events table lacks properties. Build an inventory of every event table and its properties before writing any transformation code.

Duplicate events from direct imports

PostHog's direct import jobs cover at most one year of data per job, and events are not deduplicated. Overlapping date ranges or a re-run after a failure will double-count events in dashboards. Track the date range of each job in a log, run jobs once per window, and compare event counts per day against Heap before retiring the old dashboards.

Identity merges set in the wrong order

The Heap guide links Heap's user_id and identity with posthog.alias(), and sets person properties with $set and $set_once. If aliases run after events have been sent under the anonymous ID, users can split into two profiles or merge incorrectly. Test the alias sequence on a sample of known users, and confirm the result in PostHog before sending the full history with the historical_migration flag.

Dashboards built on virtual events

Heap's retroactive virtual events let teams define events after data was captured, and many dashboards depend on them. PostHog does not automatically reproduce those definitions from raw history. List every virtual event and autocaptured selector used in production dashboards, then recreate each one as a PostHog action or event and check that the historical numbers match.

Self-hosted operations without vendor support

PostHog's self-host documentation states that self-hosted deployments are officially unsupported and that PostHog does not offer customer support for product, infrastructure or other questions on self-hosted instances. Premium features in the ee directory also need a PostHog license. Decide who owns upgrades, backups and on-call before go-live, and confirm the hosting size against the self-host documentation, which recommends a server equivalent to 4 vCPU, 16 GB of RAM and more than 30 GB of storage.

EU visitor data and consent gaps

Moving history into a new tool changes where personal data sits and who processes it, which the consent and transfer review must reflect. Confirm whether the PostHog Cloud region (US Virginia or EU Frankfurt) or a self-hosted instance in your own infrastructure fits your transfer assessment, and check that tracker lifetimes and consent flows match your records. Involve your privacy lead before the first historical import.

Questions teams ask before moving from Heap to PostHog

Which Heap plan do I need to get my data out?

For a warehouse export, you need a Heap plan that includes Heap Connect, and PostHog's Heap guide states that Heap Connect is only available on Heap's Pro or Premier plans. The guide also describes a one-time JSON export, which you request from Heap support and which requires a paid Heap plan. Check both options in your current contract before you plan the exit, because the export path, the data history you are entitled to and any extra fees for these features are set by your Heap agreement, not by PostHog. Ask Heap in writing which export options are included at your tier.

Can our own team do the Heap to PostHog migration in-house?

Yes, if your engineers can query warehouse tables, write event conversion code and work with PostHog's SDK and API. PostHog's Heap guide is a scripted path: you query each event table separately, convert events and users, link identities with posthog.alias() and set person properties with $set and $set_once. Your team also needs a paid PostHog product analytics plan to send historical events with the historical_migration flag. The harder part is usually the business work of deciding which events, properties and dashboards carry over, which is easier to get right with the people who own the product.

What drives the effort of a Heap to PostHog migration?

The main drivers are the number of event types and properties you track, how much your identity model depends on Heap's user_id and identity fields, how many dashboards and definitions you rebuild, and whether you need full history or only recent data. Autocapture-heavy setups, where many events were never named deliberately, take longer to map because someone must decide what each event means in PostHog. Warehouse export volume and the number of destinations also affect the work. Ask any implementation partner for a written scope that lists these items before agreeing to a price or timeline.

How long should we run Heap and PostHog in parallel?

The length of parallel running depends on the scope of your migration and on how many teams still rely on Heap dashboards and reports, and no fixed duration is supplied for this. A common approach is to send events to both tools until dashboards and key funnels match within an agreed tolerance, then cut over. Plan for the Heap contract term and any renewal notice period, because you may need to keep paying for Heap while you verify the data. Confirm the notice terms with Heap before you set the cutover date.

What must our team provide before the migration starts?

Your team needs to provide an event dictionary that lists each event, its properties and its owner, a list of dashboards and reports that must be recreated, and working access to both Heap and PostHog with the rights to export data and manage projects. You should also name a decision-maker who can sign off on which events are kept, renamed or dropped. Without these inputs, the conversion script will carry over unclear data and the team will spend the parallel period fixing definitions. Prepare these items before you request a quote so the written scope is accurate.

Can we delete historical events from PostHog after import?

No. PostHog's migration documentation states that there is no way to selectively delete event data once it has been imported. Before you import, check that you are sending the right events, that identities are linked correctly and that duplicates will not be created, because the managed imports do not deduplicate events. Run a small test import in a non-production project first, and confirm the behavior with PostHog before you import production history.

Does PostHog support our self-hosted deployment?

PostHog's self-host documentation states that self-hosted deployments are officially unsupported and that PostHog does not offer customer support for product, infrastructure or other questions on self-hosted instances. The README also says open-source deployments should scale to about 100k events per month and recommends PostHog Cloud above that. If you plan to self-host, confirm this position with PostHog in writing and decide who in your organization or which partner will own operations, upgrades, backups and incident response before you commit to the design.

Does DeployOpen handle a Heap to PostHog migration?

DeployOpen plans, implements, customizes, integrates, hardens, backs up, upgrades, documents and supports self-hosted open-source platforms inside your own infrastructure. For a PostHog migration, that can include the self-hosted deployment, the export and conversion work and the parallel-run checks, under a fixed scope agreed in writing before work starts. DeployOpen does not publish a price list, so a quote follows from the written scope. Ongoing support and upgrades are available as retainers.

How DeployOpen scopes and runs a Heap to PostHog migration

DeployOpen plans, implements, customizes, integrates, hardens, backs up, documents and supports self-hosted PostHog inside your own cloud account, data center or air-gapped network. For a Heap exit, the work usually starts with a written, fixed-scope agreement that names the deliverables before any export is requested: which Heap event tables to query, how Heap's user identities are aliased in PostHog, which person properties are set, and where the self-hosted instance runs. Scope also has to account for the Heap plan you hold, since Heap Connect and the one-time JSON export both depend on a paid plan, and the PostHog import features depend on a paid product analytics plan. Confirm those entitlements with Heap and PostHog before the scope is signed, because they affect what can be delivered.

Delivery covers the parts a self-hosted team owns after the data leaves Heap. DeployOpen can set up the self-hosted PostHog deployment, configure the event conversion and identity aliasing work, sequence the historical import with the historical_migration flag, and document the runbooks for backups and upgrades. PostHog's self-host documentation states that self-hosted deployments are officially unsupported and that PostHog does not offer customer support for product, infrastructure or other questions on them, so ongoing operations need an owner. DeployOpen offers retainers for ongoing support, upgrades and continuous testing, and those are priced separately from the initial migration. Ask for the retainer terms in writing so the handover is explicit.

DeployOpen does not publish a price list. A quote follows from the written scope, and the components that drive it are the Heap export effort, the volume and shape of the data, the number of event tables and properties to convert, the hosting and hardening work, and the retainer level after go-live. Ask any provider, including DeployOpen, to itemize one-time migration work separately from recurring infrastructure, licensing and support, and to state what is excluded. Confirm with PostHog which plan and license terms apply to the premium features you need, since the ee directory requires a PostHog license on self-hosted instances. DeployOpen prepares systems and evidence for compliance assessments but does not issue audit reports or certifications, so any compliance requirement should be confirmed with an independent auditor.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.