Before you export anything
Migrations fail in the first hour, not the last. Before touching an export button, we do three things. We freeze the old CRM: no new fields, no renamed stages, no clean-up sprints, because every change now has to be repeated in the map. We export everything, not just contacts: companies, deals, notes, tasks, email and call activity, and the field definitions themselves. And we agree what "done" means with the client, in writing, usually as a count: this many contacts, this many open deals, this much pipeline value, all visible in GoHighLevel and matching the source.
Build the field map
The field map is a spreadsheet with one row per source field. For each row we decide its destination in GoHighLevel:
| Source field (HubSpot) | Destination in GoHighLevel | Notes |
|---|---|---|
| First name, Last name, Email, Phone | Standard contact fields | Phone normalised to E.164 first. |
| Lifecycle stage | Tag stage:lead, stage:customer | Drives smart lists. |
| Lead source | Custom field "Lead Source" | Values merged into a fixed list of eight. |
| Deal stage | Opportunity pipeline stage | Old 11 stages mapped to new 6. |
| Deal amount, close date | Opportunity value, expected close | Currency confirmed. |
| Notes, call logs, emails | Contact notes with date prefix | Oldest first so the timeline reads correctly. |
| "Newsletter 2021" checkbox | Dropped | Unused since 2022; documented as dropped. |
Every source field ends up in one of four columns: a GoHighLevel field, a tag, a note, or "dropped" with a reason. Nothing is allowed to be blank. The client signs the map before we import a single row, which is the moment most surprises get caught.
Clean in the spreadsheet, not the CRM
The export is where you clean, because a spreadsheet has undo and a CRM does not. We normalise phone numbers to international format, lower-case and trim emails, merge duplicates by email and then by phone, and collapse free-text fields like "Lead Source" into a fixed list. Anything we can't resolve goes into a "review" tab for the client to decide, rather than being guessed.
GoHighLevel merges on email and phone by default. If the same person exists twice in the source with two emails, you will get two contacts and split their history. Decide which record wins before importing, and store the losing email as a secondary field.
Import in the right order
- Custom fields, tags and pipelines first. The structure has to exist before the data lands in it.
- Contacts. One import, one test batch of 50 first, then the full file. Check a handful by hand.
- Opportunities. Matched to contacts by email, placed in the mapped stage with value and close date.
- Notes and activity. Imported oldest to newest, each prefixed with its original date, so the contact timeline reads like history rather than a dump.
- Tasks and follow-ups that are still open, assigned to the right user.
Between each step we stop and count. If contacts imported at 4,812 and the source had 4,830, we find the 18 before moving on, because a missing contact means missing deals and notes downstream.
Reconcile and sign off
Reconciliation is a short report the client can read in five minutes: source count and destination count for contacts, companies, open deals and total pipeline value, plus ten randomly chosen contacts opened side by side in both systems with screenshots. When the counts match and the spot checks pass, the client signs off. That signature is what turns "we think it worked" into verified.
The cut-over week
For one week both systems run, with the old CRM set to read-only. New leads flow only into GoHighLevel, the team works from it, and anyone who needs to check something old still can. At the end of the week we do a final delta import of anything that changed in the old system during the freeze, then export a full archive of the old CRM for safekeeping and switch it off.
Done this way, a migration of a few thousand contacts takes about two weeks end to end, and nobody on the team discovers a missing note three months later. If you are planning a move and want a second pair of eyes on the field map, that is exactly the kind of thing the free audit covers.
Key takeaways
- Freeze the old CRM's structure and export everything, including notes and activity, before changing anything.
- Write a field map with a home for every source field: a GoHighLevel field, a tag, a note, or a documented "dropped".
- Clean and de-duplicate in a spreadsheet where you can undo, not inside the live CRM.
- Import contacts first, then opportunities, then notes, and reconcile counts after each step.
- Run both systems for one week with the old one read-only, then switch off.