Moving a CRM into GoHighLevel: the order that stops data going missing
A GoHighLevel data migration is an architectural translation, not an export and an import. Here is the order that keeps fields, dates and consent state intact.
7 min read
Almost everybody plans a migration as two steps: export a CSV, import the CSV. Two steps, one afternoon, done.
That plan loses data every time, and the loss is quiet. Nothing errors. The row count matches. Six weeks later somebody asks which customers are on a maintenance plan and the answer is sitting in a notes field where nothing can filter on it.
A migration is an architectural translation. You are not moving records, you are rebuilding the shape those records lived in and then pouring them into it. The order is the whole job.
A snapshot and a migration are different jobs
Worth separating these before anything else, because they get booked as one.
A snapshot brings the machinery: workflows, funnels, pipelines, calendars, forms, the message copy. A migration brings the records: people, their history, their consent state, their place in your pipeline. One is a shelf, the other is stock.
Doing both on the same afternoon is how a five-year-old list gets a “thanks for your enquiry, we will call you within the hour” text at nine on a Tuesday morning. Load the crate, fill its custom values, prove it works with test contacts, and only then bring the real records in. The installation and fit-out service and the CRM data migration service are two separate lines on a docket for exactly this reason.
If your snapshot is not in yet, the step by step import guide covers that half. This post is the other half.
Inventory before you export
Open the old system and write down what is actually in it, not what you think is in it.
You want four lists. Every custom field, with its type and whether anything real is stored in it. Every pipeline and every stage name. Every tag, with a count of how many contacts carry it. Every calendar or appointment type.
The counts matter more than the names. A tag on four contacts out of eleven thousand is not a tag, it is somebody’s abandoned experiment, and carrying it across costs you a field you will never use and a decision you will have to make again later. Migration is the one moment where deleting is cheap.
Build the destination shape first
Nothing gets exported until the destination can receive it properly.
Custom fields, with their types
This is where most of the damage happens. GoHighLevel will not invent a field to hold data it was not expecting. Anything arriving without a matching destination field goes into a note if you are lucky and nowhere if you are not, and a note is not searchable, filterable or usable as a workflow condition.
Create every field you decided to keep, and create it as the right type. A date field created as text will accept your dates and then refuse to drive a reminder, because “12/03/2024” to a text field is a string, not a moment. A dropdown created as free text will accept forty spellings of the same three options.
Pipelines, stages, tags and calendars
Stages first, in the order deals really move, using your team’s words rather than the source system’s defaults. Then tags, only the ones that survived the count. Then calendars, with owners, real availability and a notice period, because an imported contact with an appointment attached needs somewhere for that appointment to sit.
Load a sample before you load the list
The full load is the last thing that happens, not the first.
Load one hundred rows, then stop
Export everything. Import one hundred.
Pick the hundred deliberately: your oldest records, your newest, and a handful of the messiest ones you know about. If a record is going to break, it will be one of those, and finding out at a hundred rows is a five minute fix rather than an eleven thousand row cleanup.
Check the sample by opening records, not by counting them
Row counts prove almost nothing. Open twenty contacts and read them.
Look for a field with the right label and the wrong content. Look for dates that arrived as text. Look for a multi-select that had three values in the old system and now holds one, or holds all three concatenated into a single unreadable string. Look for a phone number that lost its country code somewhere in the export.
Then run one contact through a real workflow condition. If the condition is “maintenance plan is yes” and the field is text holding “Yes “, with a trailing space, you want to know now.
The four things that reliably go missing
Fields with no home. Covered above, and worth repeating because it is the expensive one. Anything without a destination field becomes unstructured text.
Dates arriving as text. Renewal dates, policy expiry, last service date, birthday. These are the fields that drive the most valuable automations in a crate, the seasonal recall on the HVAC contractor crate or the renewal run on the insurance agency crate, and they only work as real dates.
Multi-select values flattening. Three services become one, or become a comma-separated string that no filter can read. Decide before the import whether these become separate fields, separate tags, or a single value you accept losing detail on.
Activity history. Call logs, email threads, note timestamps and old conversations usually do not come at all, and the ones that do arrive as an undated block. Decide what you actually need. Most businesses need the last outcome and the last date, not five years of email bodies, and pulling only those two into fields is far more useful than a wall of pasted text.
Consent state is its own migration
This is the risk nobody puts on the plan.
Your old system knows who unsubscribed, who asked not to be texted, and who never opted in to anything. That state lives in a flag, and flags are exactly the sort of thing a CSV export drops.
Migrate the suppression list first, as its own import, before the main list arrives. Tag it. Then confirm that every sequence in your account respects the tag, and check it by looking at a suppressed contact and confirming they are excluded, not by trusting that the platform sorted it out.
A list arriving without its opt-outs is not a data problem. It is a complaint, then a carrier problem, then a sending reputation problem, in that order, and it takes months to undo. If you are also standing up SMS for the first time, the sending side has its own approval queue and that belongs at the start of the project too.
Cut over in two stages
The records arriving is not the cutover. Two things still have to happen in order.
Rebuild automations after the records land, not before
Import with every workflow paused.
This sounds obvious and it is the single most common way a migration turns into an apology. A “new contact created” trigger does not know the difference between a lead who filled in a form and eleven thousand rows arriving at once from a CSV. Pause everything, load, verify, then switch things on one at a time.
Switch them on in the order a real customer would meet them: intake first, then booking, then reminders, then the reviews and retention machinery. Watch the first live contact through each one before you publish the next. If one of them stays silent, work down the diagnostic order for a snapshot that will not fire rather than guessing at the migration.
The dual-running fortnight
Keep the old system readable, not writable, for about two weeks.
New records go into GoHighLevel only. The old system stays open for lookups so nobody is blocked when a field turns out to be missing. That fortnight is your safety margin and it costs one more month of a subscription you were cancelling anyway.
Switch the old system off when three things are true: no one on the team has opened it for lookups in a week, the reports you actually run monthly can be produced from the new account, and one full cycle of your longest process has completed end to end in the new system. For a law firm crate running long matters, that cycle is longer than a fortnight, and the answer is to keep the old system in read-only for longer rather than to rush the cut.
What to decide next
Two decisions, in this order. First, whether your destination shape is designed or inherited: if you are recreating the old system’s fields one for one, you are migrating its problems too. Second, whether the crate goes in before or after the records, and the answer is always before.
Pick the aisle your business sits on in the aisle directory, or start from the professional services aisle if you run long cycles and referral work, and the full catalog will tell you which crate you are fitting around the data you are about to move.