CRM migration

Migrating from Salesforce to HubSpot without losing history

Converted leads, stage history, files and logic in Flows or Apex: where Salesforce migrations go wrong and how to make them repeatable.

Migrating from Salesforce to HubSpot without losing history

To migrate from Salesforce to HubSpot without losing history you need three things: a documented mapping of every object and field, the Salesforce ID stored on every HubSpot record and a full test load before cutover. With those in place, accounts, opportunities, activities and attachments arrive with their original dates and relationships, and you can repeat the process as many times as needed without duplicating anything.

Below is the method we follow on every HubSpot migration, with the points where Salesforce migrations tend to go wrong: converted leads, stage history, files and the logic that lives in Flows and Apex.

What "not losing history" means in Salesforce

When someone asks to keep the history, they almost never mean just the records. They want to open a customer record and see what was discussed three years ago, which opportunity was lost and why, who was handling it and which contract was attached. In Salesforce that information is spread across many objects: Task and Event for activities, EmailMessage for emails, ContentDocument and ContentVersion (or the older Attachment) for files, OpportunityHistory for stage changes and the Field History tables for tracked fields.

Before mapping, take an inventory: how many records there are per object, which fields actually contain data, which custom objects are in use and which automations depend on them. In orgs with years of use it is normal to find fields nobody has filled in for ages and objects created for a project that no longer exists. Not everything deserves to travel, and what does not travel does not need validating.

How Salesforce objects map to HubSpot

The basic correspondence is well known, but every row hides decisions worth putting in writing before writing any code.

SalesforceHubSpotDecision to make
AccountCompanyHierarchies (ParentId) as a parent and child company association
ContactContactContacts linked to several accounts: labelled associations and a primary company
Unconverted leadContact (lifecycle stage) or Leads objectLeads already converted are not migrated as separate records
OpportunityDealPipelines, stages, lost reason, currency
OpportunityContactRoleContact–deal associationRoles as labels: decision-maker, influencer, signatory
Product2 and OpportunityLineItemProducts and line itemsPrice books and per-line discounts
CaseTicketCase queues as teams or assignment rules
Task, Event, EmailMessageTasks, calls, meetings, emailsOriginal activity date and associations
Custom objectsCustom object or propertiesHubSpot custom objects require an Enterprise edition

Converted leads are the most frequent source of duplicates. When Salesforce converts a lead, the Lead record still exists with IsConverted ticked and its information moves to Contact, Account and sometimes Opportunity. If you migrate every lead without filtering, you duplicate every customer. The right approach is to migrate only unconverted leads and, if useful, carry the source data from the converted lead (source, campaign, creation date) into contact properties.

The other trap is contacts related to several accounts. HubSpot lets you associate a contact with several companies and label each association, so you do not have to choose just one, but you do need to decide which is the primary, because that is the one reports and workflows will use.

Activities, emails and files: the heaviest part

Activities make up the bulk of the volume and are the reason many migrations end up half done. In HubSpot each activity is an object (note, call, email, meeting, task) with an activity date property you can fill in with the original date. If you leave it empty, HubSpot uses the load date and the customer's timeline gets squashed into a single day.

In Salesforce, Task mixes calls, logged emails and genuine tasks: you have to read the subtype to send each one to the right object in HubSpot. Events become meetings. EmailMessage records can carry very long HTML bodies, and you need to decide whether to migrate the full body or a summary with the original attached.

Files need an extra step: download them from Salesforce, upload them to HubSpot's files tool and associate them with the record, usually through a note that contains them. It is slow and takes up space, so agree on a rule: only contracts and proposals, only active customers or only the last few years.

The HubSpot properties that record when a deal entered each stage are read-only and calculated from movements inside HubSpot. Salesforce stage history cannot be loaded into them: store the dates that matter (entered proposal, original close date) in your own properties or in a separate history record.

Owners and users: who handled each account

The owner of a record in HubSpot has to be a user in the account. Before loading anything, create the users and prepare a lookup table between the Salesforce user Id and the HubSpot owner. Reps who have left the company are the typical case: assign their records to a current manager and keep the original owner in a text property so you do not lose who handled the relationship.

Something similar happens with cases. If Salesforce distributed them through queues, decide whether HubSpot will handle that with teams, the ticket owner or assignment rules in workflows.

Is HubSpot's tool enough or do you need a script?

HubSpot offers Smart Transfer, a guided tool for bringing data in from other applications, Salesforce included. According to its documentation, it converts accounts into companies, contacts and leads into contacts, opportunities into deals and cases into tickets, carries over tasks, events, notes, emails and users, and moves attachments in a later one-off transfer. It is also clear about its limits: it does not support custom objects or lookup or formula fields, and it is designed for a one-time migration. If you are going to keep using Salesforce, HubSpot recommends the native integration and warns that combining both creates duplicates. The detail is in the official list of supported apps.

For a standard org with little customisation, Smart Transfer or HubSpot's importer may be enough. When there are custom objects, multi-level relationships, stage history to preserve or lots of files, the usual route is a script against both systems' APIs: extract with the Salesforce API or Data Loader, transform with the mapping rules and load with the HubSpot API, leaving the Salesforce Id on every record.

The method: identifiers, test loads and delta

  1. 01Org inventory
  2. 02Validated mapping
  3. 03Full test load
  4. 04Validation with users
  5. 05Delta and cutover
Fig. 1 The five phases of a Salesforce to HubSpot migration. The test load is repeated until validation comes back clean.

What makes the process repeatable is the source identifier. On every HubSpot object, create a "Salesforce ID" property that requires unique values and use it as the key when loading. If the second test load brings in a record that already exists, it is updated instead of duplicated, and associations are resolved by looking up that ID. As a bonus, every HubSpot record can be traced back to its origin.

The test load must be complete, not a sample of a hundred records. It is the only way to see the errors that appear at real volume: phone numbers in odd formats, retired picklist values, invalid emails, opportunities without an account. Then it is validated with counts per object and with key users opening records they know well.

On cutover day Salesforce is frozen, the delta is loaded (whatever was created or modified since the last load, filtering by LastModifiedDate) and the team starts working in HubSpot. A good cutover plan sets the freeze time, who validates what and the rollback criteria in advance.

What is not data: Flows, Apex and validations

Salesforce tends to accumulate logic: Flows, Apex triggers, validation rules, formula fields and roll-up summaries. None of that travels with the data. It has to be inventoried and you need to decide how it is rebuilt: workflows, calculated properties, property validation rules, custom code actions or custom development when the logic is complex.

1,615contract flows recovered with a backfill in a migration from Salesforce
Fig. 2 A real project for a fintech SaaS company: as well as the data, the bespoke logic moved to a dozen microservices.

At a fintech SaaS company we migrated from Salesforce, that logic ended up spread across around 12 microservices: sequential numbering, ARR and account type calculated daily, chained renewals, stage history for the data warehouse and the connection to its contract management tool, with a backfill of 1,615 flows. You can read the full case study on our site. Not every org needs that much, but it is worth knowing before you budget.

If you are still deciding whether the switch is worth it, the HubSpot vs Salesforce comparison helps you see what you gain and what you leave behind.

Vexco team

HubSpot consultants and developers in Sabadell, Barcelona and Madrid. HubSpot Diamond Solutions Partner. About us →

FAQs

What clients ask us before we start

Does HubSpot have a native tool for migrating from Salesforce?

Yes. Smart Transfer can bring over accounts, contacts, leads, opportunities, cases, activities, notes and users, plus attachments as a one-off transfer. It does not support custom objects or some field types, such as lookup or formula fields, so in heavily customised orgs it is usually combined with scripts against the API.

Are the original dates of calls, emails and meetings kept?

Yes, as long as you set each activity’s activity date to the original Salesforce date when loading it. If you do not, HubSpot uses the load date and the whole timeline ends up on the same day.

Can opportunity stage history be migrated?

Not into the native date-entered-stage properties, which are read-only and calculated from movements inside HubSpot. The usual approach is to store the key dates in your own properties or in a separate history record.

Can we keep working in Salesforce while we migrate?

Yes. The team stays in Salesforce until the cutover date; on that day it is frozen, the delta of changes is loaded and everyone moves to HubSpot. If you need both to coexist for months, the option is the native HubSpot-Salesforce integration, not a migration.

Blog

Keep reading

Back to the blog →

Free audit

Want to move Salesforce to HubSpot with all its history?

We inventory your org, document the mapping, rehearse the full load and plan the cutover so sales never stops.

We reply within 24 business hours.

Free audit