Skip to content
DevLaunch home

Guide · CRM & customer operations

Move from HighLevel to Seedly: The GoSeedly Migration Guide

Install, connect, export, clean, approve, import, and verify your CRM move with the GoSeedly Transfer Tool.

By DevLaunchPublished

Install the Transfer Tool, connect both sides read-only, prove the whole flow on sample data, then export, clean, approve, import and verify one sub-account at a time. Everything runs on your computer.

Leg 1 · Prepare

Nothing here touches a real record. By the end of this leg both sides are connected, the sample migration has run end to end, and you know exactly what will and will not move.

Know what you are running

Five facts that shape every decision after this one.

  • It is a one-time move, not a sync. It copies records once; afterwards the two systems are unrelated.
  • It runs entirely on your computer, on 127.0.0.1. Nothing is sent to DevLaunch. Credentials live in an encrypted local vault, and everything exported is sealed in an encrypted archive.
  • It only reads from HighLevel. There is no code path that creates, edits, deletes or sends anything there.
  • It writes to Seedly only after a person approves an exact plan, identified by a hash. Change anything and the approval resets on purpose.
  • It is not a Seedly installer and contains no Seedly code. Seedly must already be installed, deployed and set up; the tool adds one import add-on to it.

What you need

Gather these before you unzip anything.

ItemDetail
A Mac or Windows computerAt least 10 GB free. Large accounts take hours, so a machine that can stay awake.
Node.js LTSOne normal installer from nodejs.org. About five minutes.
Your Seedly CRMInstalled, deployed and set up separately, version 5.8.x with extension API 1. You need the source folder you deploy from, a working Convex development deployment, and agency-owner access in the dashboard.
Agency admin access to HighLevelFor OAuth, the ability to create a private developer app and authorise it. For a Private Integration Token, access to the sub-account's Private Integrations settings.
An empty test sub-account in SeedlyThe first real import goes here, never into a populated account.

Install and run the sample

See the whole flow with made-up records before any account is connected.

Do this

Unzip into its own folder. On a Mac, double-click Start GoSeedly.command; if macOS says it cannot verify the developer, right-click, choose Open, then Open again. On Windows, double-click Start GoSeedly.bat. From a terminal inside the folder:

npx pnpm install
npx pnpm start

The first start installs dependencies, checks the computer, opens the local page in your browser, and creates a private data folder at ~/.goseedly. Leave the window open while you work.

Check

Choose Explore sample data and walk all five stops. Sample mode is deterministic, synthetic and offline; it never touches a real account or the network. The same run works headless:

npx pnpm cli sample --tier small     # or --tier messy; add --json for a summary
Exit codeMeaning
0Completed, or the job reached the state you asked for
2Completed with exceptions. The job finished, but some records need your attention. Read the exception list before you treat the migration as done.
1Failure. The job stopped on an error, or the command itself could not run.

Add the import add-on to Seedly

The add-on is what makes an import historical: original dates, inert messages, no automations, no webhooks. Connecting a plain Seedly URL cannot promise that.

Do this

From the unzipped folder, check first, then install. The dry run checks the Seedly version and extension ownership, lists every file it would write, and changes nothing.

node seedly-module/bin/install.mjs --seedly /absolute/path/to/your/seedly-checkout --dry-run
node seedly-module/bin/install.mjs --seedly /absolute/path/to/your/seedly-checkout

The installer copies the add-on into convex/goseedly/, writes the extension registry lines Seedly expects, records the install in .modules.json, runs Seedly's own install, build, type check and the add-on's tests, and prints the deploy command. It never deploys and never touches SETUP/, LICENSE.md or SUPPORT.md. Deploy to development yourself:

npx convex dev --once

Then

In the Seedly dashboard, as an agency owner: Settings → API Keys → Create key. Grant exactly two scopes, GoSeedly - Read and GoSeedly - Write, and nothing else. A sub-account key (sk_live_…) locks the tool to that one destination; an agency key (sk_agency_live_…) lets you pick the destination per job.

In the wizard, enter the Convex HTTP Actions URL, https://<name>.convex.site, and the key. Not the dashboard login address and not the .convex.cloud client URL.

Check

Test connection should show the add-on version, the destination agency and sub-account IDs, and the users available for owner mapping. Read the destination it names, not just the green message. A blank key field after saving is normal: the key lives in the vault and is not shown again.

Connect HighLevel, read-only

Two methods, one engine. Pick by how many sub-accounts you are moving.

OAuthPrivate Integration Token
Best forSeveral authorised sub-accounts under one agencyOne sub-account, simplest setup
SetupCreate a private developer app in the HighLevel marketplace and approve it for your agencySub-account → Settings → Private Integrations → Create, read permissions only
RenewalAutomatic token refreshRotate by hand; HighLevel suggests every 90 days
CoverageInstalled-location discovery and agency-authorised endpointsSub-account endpoints only

OAuth

  1. Create the app as Private, target user Sub-account, installable by everyone, bulk install allowed. Private is visibility; the version must also be published Live for normal agency OAuth. Never submit it for public review.
  2. Add scopes from the wizard's preset as a checklist, one by one. Core CRM is 12 permissions; Everything readable is 69, 68 reads plus oauth.write for the token exchange. Never use a group's Select all; it includes write permissions.
  3. Add the redirect URL the wizard shows, http://127.0.0.1:48231/oauth/callback by default, click Add, and Save. A URL typed but not added is not registered.
  4. Under Manage → Secrets → Client keys, add a key and paste the Client ID and secret into the tool. Not the Shared secret; that is a different feature.
  5. Start the connection from the tool so it can verify the callback, then run Check access.

PIT

Create one read-only token per sub-account, paste it with the agency and location IDs, and run Check access. To replace a rotated token later, use Saved connections → Replace token on the same connection; adding a new connection does not repair an existing job.

Leg 2 · Move

One job per sub-account, five stops each. Every stop can be paused and resumed; nothing is lost by closing the window.

Get the data

Pick the accounts, the record types, the date range and where the encrypted archive goes.

Do this

Tick the sub-accounts, choose categories and a date range, and pick an archive folder with room. An empty date range defaults to the last ten years; set From explicitly if your history is older. Start with core CRM for a focused first test; broader archive coverage is a separate check.

npx pnpm cli jobs create --location <id> --sub-account <id>   # add --everything for the whole readable surface
npx pnpm cli run <job id>
npx pnpm cli status <job id>   # pause, resume and cancel take the same id

Check

Progress shows fetched against known totals. When HighLevel cannot say how many records exist, it says counting. Rate-limit waits are automatic; a large account simply takes longer, and restarting does not make it faster.

Clean the data and approve the plan

Duplicates, phone numbers, owners, stages and fields. Then a dry run that lists exactly what will be created, and nothing else.

Decide

  • Duplicates: a shared phone or name is a match signal, not proof. Keep records separate when unsure.
  • Owners and users: invite or create people in Seedly first, assign their permissions there, then refresh and map. The tool never invents users.
  • Pipelines and stages: map to existing ones, or create empty pipelines and append missing stages from the mapping page. Updates are append-only and same-name stages are reused.
  • Custom fields: create now, or leave as create during import. Existing definitions are reuse-only; the tool never renames a field or changes its type.
  • Anything it refuses to invent stays on the issues list until you decide.

Do this

Run the dry run. Read the create, link, skip and reject counts and resolve every blocker. Then approve that exact plan.

npx pnpm cli run <job id>                                # from Review: runs the dry run, prints the plan hash
npx pnpm cli approve <job id> --plan-hash <hash>

Import, then verify

Batches go in through the add-on in dependency order. Then the tool reads everything back.

Do this

npx pnpm cli run <job id>      # after approval: imports, then verifies
npx pnpm cli report <job id>   # the summary and where the files are

Check

Open representative contacts, deals and historical conversations in Seedly yourself. Completed with exceptions is not Completed: open the exception list, which names each record, the reason and the recommended action. Typical entries are an attachment that had expired in HighLevel, a phone number without a country code, or an owner with no matching Seedly user.

Rebuild assets, a beta

Workflows, forms and published pages do not come across as records. Three side routes help you rebuild them; none is a one-to-one migration.

RouteWhat it producesWhat it cannot do
WorkflowsAn inactive review draft in Seedly with every imported action disabled, plus a per-node mapping logThe supported API exposes no graph or node content; the guided capture is evidence, not a complete definition
FormsSeedly forms with status draft, with a per-field status of exact, inferred or needs review, and a list of the fields your Seedly lacksPayment elements, booking calendars and captchas have no Seedly equivalent; submission history is not imported
SitesOne zip of static HTML per funnel step with assets, redirects, a manifest and a READMECheckout, booking, chat, memberships, dynamic custom values and A/B variants cannot be static

After the move

Revoke what you granted, keep what you need, know where everything is.

  • Verify the report and that you can still open the archive.
  • Uninstall the private app from the HighLevel agency (Settings → Integrations) and delete its client secret in the developer portal, or revoke the Private Integration Token. Changing a selection in the tool does not revoke remote access.
  • Revoke the GoSeedly API key in the Seedly dashboard.
  • Optionally uninstall the add-on with node seedly-module/bin/uninstall.mjs --seedly <path> --zip <your original Seedly download>, then empty the goseedly* tables in the Convex dashboard before your next deploy.
  • Back up ~/.goseedly before you ever replace the application folder.
ItemWhereEncrypted
Credentialsvault.json in your GoSeedly homeYes, by your passphrase
Job databasestate.sqlitePayload columns yes; metadata no
Raw archive per jobjobs/<job id>/archive/Yes
Reportsjobs/<job id>/reports/No. Reports contain contact data; store them accordingly
Logslogs/No. Secrets are redacted before writing

If stuck

Jobs resume from their last safe checkpoint. Run the doctor and read the recovery guide in the download before retrying an interrupted import. A support bundle from the report screen contains counts, codes and IDs only; preview it before you share it.

npx pnpm run doctor
npx pnpm cli resume <job id>

Keep building

View topic →