A Zoho CRM to Salesforce migration requires strict load ordering, ID translation tables, and careful WhoId/WhatId mapping for polymorphic activities. Plan 2 to 14 weeks depending on complexity.
There is no native migration path from Zoho CRM to Salesforce; the process requires a full data-model translation rather than a simple CSV export and import. Fundamental differences in object naming (Deals vs. Opportunities), activity polymorphism (single related-record link vs. dual WhoId/WhatId fields), and stricter referential integrity enforcement in Salesforce mean that every record relationship must be carefully re-mapped and re-linked by Salesforce ID after insert. Additionally, Zoho Blueprints, workflow rules, custom functions, email templates, and reports cannot be migrated programmatically and must be manually rebuilt using Salesforce Flows, Apex, Lightning App Builder, and native reporting tools.
Read this first
Pair-specific gotchas that catch teams out. Each one has cost somebody a weekend.
Quick Answer: Zoho CRM to Salesforce Migration
A Zoho CRM to Salesforce migration is a data-model translation project, not a CSV lift-and-shift. Timelines range from 2 to 6 weeks for a standard sales org (under 500,000 records) to 6 to 14 weeks for enterprise orgs with custom modules, multi-currency, and heavy activity history. The single biggest risk is broken relationships: Zoho Deals linked to Contacts, Accounts, and Activities must be re-linked by Salesforce ID after insert, and any misstep orphans pipeline data. Zoho Blueprints, workflow rules, and custom functions cannot be migrated programmatically—they must be rebuilt in Salesforce Flows or Apex. Teams with fewer than 100,000 total records and no custom modules can handle this in-house. Teams with polymorphic activity histories, multi-currency Deals, or more than 500,000 records should use an API-based approach or a managed migration service.
Never load Tasks or Events before Contacts, Accounts, and Opportunities
Salesforce will reject any Task or Event where the WhoId or WhatId references a record that does not yet exist. The resulting error is INVALID_CROSS_REFERENCE_KEY with no indication of which specific parent record is missing—you must debug from your ID translation table.
Use Salesforce External ID fields
Create a custom text field (e.g., Zoho_ID__c) on each Salesforce object and mark it as an External ID. This lets you use upsert operations via Bulk API 2.0, which eliminates the need for a separate ID translation table for simple lookups. Salesforce resolves relationships using the External ID value automatically. This approach is especially valuable for Contacts referencing Accounts—set the relationship field to use Account.Zoho_ID__c in your CSV header instead of the Salesforce AccountId.
The runbook
Work top to bottom. Tick steps as you go — your progress is saved in this browser.
01 Discovery Agree scope, pipeline design and success criteria before touching data.
Objective A scope covering every object in the revenue model, with sales leadership signed up to the pipeline design.
Keep these open
-
Inventory every object in Zoho CRM
Count accounts, contacts, leads, deals or opportunities, activities, notes, emails, files, products and quotes. Activity and email history is usually the largest object by an order of magnitude and the one people forget to size.
Data Profiler Get real record counts instead of estimating from memory -
Map the current pipeline and agree the target model
Document every pipeline, stage, probability and required field, then agree the Salesforce model with sales leadership. Migrating a broken pipeline faithfully is a wasted opportunity; redesigning it mid-migration is a wasted migration.
Stage changes alter historical conversion rates. Agree how you will restate reporting before you change the model.
-
Catalogue integrations and automation
List every system touching Zoho CRM: marketing automation, quoting, billing, ERP, data enrichment, dialler, BI. Each is a separate cutover task with its own owner, and each can silently write bad data into your new CRM.
-
Capture the reporting that must survive
Interview the people who actually live in the dashboards — forecast, pipeline coverage, rep activity, cohort conversion. Every one of these needs the underlying fields to migrate, which frequently expands the scope.
-
Build the business case and pick the go-live date
Model licence delta, implementation effort and productivity dip. Then choose the date deliberately: mid-quarter is disruptive, quarter-end is worse. Most teams land on the first week of a new quarter.
COI & ROI Calculator Build the 36-month business case you will need for sign-off
Don't move on until
- Object counts confirmed for accounts, contacts, deals and activities
- Target pipeline and stage model agreed with sales leadership
- Reporting requirements captured from the people who use the reports
02 Data Audit CRM data is usually dirtier than anyone expects. Find out how dirty.
Objective A profiled export with duplicates, ownership gaps and relationship integrity all quantified and triaged.
Keep these open
-
Export and profile every object
Profile null rates, distinct values and type consistency across all objects. Pay attention to fields sales reps were supposed to fill in: an 80% null rate on a field your forecast depends on is a business finding, not a data one.
Data Profiler Profile the Zoho CRM export for nulls, outliers and type drift -
Quantify duplicates and agree the merge policy
Measure duplicate accounts (same company, different spellings and suffixes) and contacts (same email, or same person at a renamed company). Agree survivorship rules before merging: which record wins, which fields, and what happens to the activity history on the loser.
Merging before you have agreed survivorship rules destroys history irreversibly. Decide first, merge second.
Data Cleaner Strip empty rows, stray whitespace and dead columns -
Verify relationship integrity
Check every deal has a valid account, every contact a valid account, every activity a valid parent. Referential breaks are the defect that turns a clean-looking load into a CRM where the pipeline report does not tie to the account list.
-
Resolve ownership and the user map
Build the Zoho CRM user → Salesforce user map, including leavers. Every record needs a valid owner: records assigned to deactivated users either fail to load or land unassigned, and unassigned pipeline is pipeline nobody works.
Records owned by deactivated users are a top cause of load failures. Decide the reassignment target before you start.
-
Scan for PII and regional compliance
CRMs hold marketing consent, lawful basis and unsubscribe state. Confirm these fields migrate intact and that consent provenance survives — losing consent records is a regulatory problem, not a data-quality one.
PII & Compliance Scanner Find regulated fields before they land in a new system -
Clean, normalise and archive the pre-state
Normalise country and state values, phone formats, currencies and casing, and standardise all timestamps to UTC. Keep an untouched copy of the raw export — it is your only reference if a mapping decision turns out wrong.
Zoho CRM → Salesforce specifics
- Zoho Blueprints
- Rebuild as Salesforce Flows (Screen Flows or Record-Triggered Flows).
- Subforms
- (inline child records within a Zoho module) — Map to related lists on a child custom object.
- Email templates
- Zoho uses its own merge-tag syntax (${Contacts.Last Name}). Salesforce uses Handlebars-style merge fields ({{{Contact.LastName}}}). Templates must be recreated.
- Zoho Webforms
- Replace with Salesforce Web-to-Lead or Web-to-Case forms.
- Zoho SalesSignals notifications
- No direct equivalent. Use Einstein Activity Capture or custom Platform Event notifications.
Don't move on until
- Duplicate rate quantified per object with a merge policy agreed
- Every record has a valid owner mapped to a target user
- Relationship integrity verified — no orphaned deals or contacts
03 Field Mapping Map objects, relationships and picklists — in that order.
Objective A signed mapping spec that covers objects, relationships, picklist values and currency handling.
Keep these open
-
Map objects and their relationships first
Establish how Zoho CRM objects correspond to Salesforce objects before any field work. Leads-versus-contacts, accounts-versus-organisations and deal hierarchies differ structurally between CRMs, and a field map built on the wrong object model has to be redone.
Schema Mapper Opens pre-loaded with the Zoho CRM → Salesforce field pair -
Generate and then hand-review the field map
Auto-match both schemas, then review every row. Look hardest at anything named "type", "source", "stage" or "status", where names match and meanings do not.
-
Map every picklist value, including retired ones
Enumerate all values on both sides — deal stages, lead sources, industries, statuses — and map each explicitly, including values no longer offered but still present on old records. Unmapped values either fail the row or land as blanks that quietly break segmentation.
Historical records often carry picklist values that were retired years ago and no longer appear in the UI.
-
Decide currency, amount and date handling
If you sell in multiple currencies, confirm how Salesforce stores amounts, exchange rates and dated conversion rates. Recalculating historical deal values at today's rate silently rewrites your revenue history.
Multi-currency deals re-converted at current rates will not tie to your historical reporting or your finance system.
-
Determine the load order
Sequence the load so parents exist before children: users, then accounts, then contacts, then deals, then activities and notes. Keep source IDs in custom fields so relationships can be rebuilt by lookup rather than guesswork.
-
Freeze the spec and sign off
Version-control the mapping, walk RevOps and sales leadership through the decisions that change reporting, and get written sign-off before the pilot.
Don't move on until
- Object and relationship model mapped and reviewed
- Every picklist value explicitly mapped, including dead values
- Load order determined so parents always exist before children
04 Test Migration Pilot with related records, not a flat sample.
Objective A pilot load whose relationships, ownership and roll-up reporting all verify against source.
Keep these open
-
Configure the Salesforce sandbox to match the agreed model
Build the pipelines, stages, custom fields, record types and user roles first. Load into a default configuration and you will only discover the configuration defects at full scale.
-
Select a connected pilot slice
Take complete account trees — 50-100 accounts with all their contacts, deals, activities and files — rather than a flat random sample. Relationship defects are the whole point of a CRM pilot and a flat sample cannot expose them.
-
Run the load in dependency order with full logging
Load users, accounts, contacts, deals, then activities, logging every request against its source ID. Note which failures are transient (rate limits, timeouts) and which are structural (validation, missing parent).
-
Verify relationships and roll-ups
Confirm every deal sits on the right account with the right owner and stage, and that pipeline totals per account and per rep match Zoho CRM exactly. Roll-up mismatches almost always mean a relationship or currency defect upstream.
Migration Validation Tool Diff the pilot batch against source before scaling up -
Measure throughput and project the full load
Record actual records-per-hour under Salesforce's API limits and extrapolate, remembering activity history usually dominates volume. If the projection exceeds your window, split the load or trim activity scope now.
-
Let reps work the pilot data
Put two or three reps in the sandbox against their own accounts. They spot missing context, wrong owners and unusable notes far faster than any reconciliation script, and their buy-in is what makes adoption work.
Don't move on until
- Relationships intact across the whole pilot slice
- Pipeline roll-ups match source for the pilot accounts
- Reps have worked pilot records and confirmed they are usable
05 Cutover Switch the revenue system with the pipeline intact.
Objective All in-scope CRM data live in Salesforce, integrations repointed, and reps selling on day one.
Keep these open
-
Pre-load history ahead of the freeze
Load closed deals, historical activities and inactive accounts while Zoho CRM stays live. Only open pipeline and the final delta need to move inside the window.
-
Publish the cutover runbook
A timed sequence with owners and abort criteria: freeze, final export, delta load, integration switch, smoke test, go/no-go, rep enablement. Pick a window that avoids quarter-end and month-end close.
-
Freeze Zoho CRM and take the final delta
Set Zoho CRM read-only and export everything changed since the pre-load. Reps updating deals during an unenforced freeze is the classic way to lose the most recent — and most valuable — pipeline changes.
A rep who updates a deal in the old CRM during the freeze will lose that update permanently.
-
Load the delta and reconcile the pipeline
Run the delta, then verify open pipeline value and count per rep against Zoho CRM before anything else. If the pipeline number is wrong on day one, reps stop trusting the system and never fully come back.
Migration Validation Tool Confirm the final delta landed before you reopen -
Repoint every integration and verify with real records
Switch marketing automation, quoting, billing, enrichment, dialler and BI connections, then push a live record through each path. An unrepointed integration writing into the old CRM causes divergence that gets harder to reconcile every day.
Two-way integrations left pointing at the old CRM will keep writing there. Disable them before you switch, not after.
Cron Expression Builder Schedule the delta syncs that run through the freeze -
Go/no-go, then enable the reps
Call the decision explicitly against the exit criteria. Run enablement on real data with their own accounts on screen, and keep Zoho CRM read-only rather than cancelled until validation closes.
Don't move on until
- Historical load complete and reconciled before the freeze
- All integrations repointed and verified end to end
- Reps logged in with pipeline visible and correct
06 Validation Prove the revenue numbers tie out, then close the project.
Objective Reconciled data, forecast parity with pre-migration reporting, and signed acceptance.
Keep these open
-
Reconcile every object
Compare counts and values across accounts, contacts, deals, activities and files, plus field-level spot checks on a random sample. Produce a single report suitable for audit and for finance.
Migration Validation Tool Reconcile Zoho CRM and Salesforce record-for-record -
Tie the pipeline and forecast to baseline
Rebuild forecast, pipeline coverage and win-rate reporting and compare to pre-migration figures. Every variance needs an explanation — most trace back to stage or currency mapping decisions made in Field Mapping.
Stage-model changes will legitimately shift historical conversion rates. Restate the baseline rather than chasing the difference as a defect.
-
Verify ownership, visibility and permissions
Confirm every record has the right owner and that sharing rules, territories and role hierarchy give each rep exactly the visibility intended. Over-broad visibility in a CRM is a data-protection issue as much as a config one.
-
Re-profile for field completeness
Compare loaded null rates against the source profile per field. A field that arrived empty while counts matched is the failure counts alone cannot detect.
Data Profiler Prove field completeness held up through the load -
Test automation and integration write-back
Fire every workflow, assignment rule, sequence and notification, and confirm each integration writes correctly in both directions. Automation is rebuilt rather than migrated, so it is unproven until observed.
-
Sign off and schedule decommission
Get written acceptance against the Discovery criteria, keep Zoho CRM read-only for 30-90 days with a final archive export taken, then diarise cancellation so the contract does not auto-renew.
Don't move on until
- Full reconciliation report complete across all objects
- Forecast and pipeline reports tie to pre-migration baselines
- Acceptance signed and Zoho CRM decommission scheduled
Field mapping reference
The field-by-field mapping for each object. Use this as the starting point for your mapping spec.
Zoho CRM Salesforce Object Mapping
| Zoho CRM field | Salesforce field | Notes |
|---|---|---|
| Leads | Lead | Direct 1:1 mapping. Lead Source picklist values must match Salesforce entries exactly or be pre-created. |
| Accounts | Account | Zoho Account Owner maps to Salesforce OwnerId. Owner must exist as an active Salesforce User. Use Record Types to distinguish Account subtypes (e.g., Customer vs. Partner). |
| Contacts | Contact | Must reference a valid Account via AccountId. Zoho allows orphan Contacts; Salesforce does not if Account is required by your org configuration. |
| Deals (Potentials) | Opportunity | Stage names must match Salesforce Opportunity Stage picklist. Close Date is required in Salesforce but optional in Zoho. Use Record Types for different deal types (e.g., New Business vs. Renewal). |
| Products | Product2 | Salesforce requires a Pricebook Entry to associate Products with Opportunities. Zoho has no equivalent concept. |
| Price Books | Pricebook2 + PricebookEntry | Products must exist in the standard price book before custom price books. |
| Quotes | Quote + QuoteLineItem | Salesforce Quotes are children of Opportunities. The Opportunity must exist before the Quote is inserted. (help.zoho.com) |
| Tasks | Task | Zoho's single related-record link must be split into WhoId (Contact/Lead) and WhatId (Account/Opportunity). |
| Calls | Task (Type = 'Call') | Salesforce has no native Call object. Calls are logged as Tasks with a Type picklist value of "Call." |
| Events (Meetings) | Event | Zoho UI may say "Meetings," but the API name remains Events. Recurring events need special logic. |
| Emails | EmailMessage | Zoho stores email threads linked to records. Salesforce uses EmailMessage (child of Case) or Task with Type='Email'. For non-Case email history, Einstein Activity Capture can sync going forward but does not import historical emails. Manual migration to Tasks with Type='Email' or a custom Email_Log__c object is required for historical records. |
| Notes | ContentNote or Note | Salesforce Enhanced Notes (ContentNote) require a ContentDocumentLink for association. Legacy Note is simpler but deprecated. |
| Attachments | ContentVersion + ContentDocumentLink | Modern Salesforce file storage is a two-step upload. Each file requires a separate API call for binary content. (zoho.com) |
| Campaigns | Campaign | Campaign Member associations must be rebuilt using CampaignMember junction records. |
| Sales Orders | Order | Salesforce Orders require an activated Contract or direct Account reference. |
| Vendors | Custom Object | Salesforce has no standard Vendor object. Build a custom object or flatten vendor data into Account with a Record Type of "Vendor." |
| Territories | Territory2 (Territory Management 2.0) | Zoho territory rules must be manually rebuilt. Salesforce Territory Management 2.0 (available in Enterprise Edition+) uses assignment rules, not the same logic as Zoho territory hierarchies. |
| Custom Modules | Custom Object (__c) | Each custom module becomes a custom object. All field API names change. Every relationship field needs re-mapping. |
Zoho Integration Equivalent
| Zoho CRM field | Salesforce field | Notes |
|---|---|---|
| Zoho Campaigns | Salesforce Marketing Cloud, Pardot, or third-party (Mailchimp via AppExchange) | Campaign Member sync logic changes completely. |
| Zoho Books / QuickBooks sync | QuickBooks connector via AppExchange (e.g., Breadwinner, DBSync) | Field mappings and sync direction must be reconfigured. |
| Zoho Desk | Salesforce Service Cloud | If migrating support data, Cases and Knowledge Articles require a separate migration workstream. |
| Zoho PhoneBridge (Twilio, RingCentral) | Salesforce Open CTI + same telephony provider | CTI adapter configuration is platform-specific. |
| Zoho Social | Salesforce Social Studio or third-party (Hootsuite, Sprout Social) | Social listening and publishing workflows must be rebuilt. |
| Custom Zoho CRM API integrations | Rebuild against Salesforce REST/SOAP API | Endpoint URLs, authentication (OAuth flow), and data schemas all change. |
| Zoho Flow / Zoho Creator automations | Salesforce Flow, MuleSoft, or third-party iPaaS (Zapier, Workato) | Automation logic must be rebuilt; no export/import path exists. |
Risk matrix
Per-object risk for this pair. Plan extra validation around anything marked high.
| Object | Risk | Notes |
|---|---|---|
| Leads | low | Direct 1:1 mapping exists between Zoho Leads and Salesforce Leads, requiring only that Lead Source picklist values are pre-created in Salesforce. |
| Accounts | low | Straightforward mapping with the main requirement being that every Account Owner must exist as an active Salesforce User before import. |
| Contacts | medium | Zoho allows orphan Contacts without an Account association, but Salesforce may require a valid AccountId depending on org configuration, causing insert failures for unlinked records. |
| Deals (Opportunities) | high | Stage names must exactly match a configured Salesforce Sales Process, Close Date is required in Salesforce but optional in Zoho, and multi-currency CurrencyIsoCode must be set per record. |
| Tasks and Events (Activities) | high | Zoho's single related-record link must be split into Salesforce's dual polymorphic WhoId and WhatId fields, and any misresolution orphans the activity from its parent records. |
| Email History | high | No clean one-to-one migration path exists; historical email threads must be manually migrated to Tasks with Type='Email' or a custom object since Salesforce EmailMessage is a child of Case only. |
| Products and Price Books | medium | Salesforce requires Products to have PricebookEntry records in the standard price book before they can be associated with Opportunities, a concept that has no equivalent in Zoho. |
| Notes and Attachments | medium | Salesforce Enhanced Notes (ContentNote) require a ContentDocumentLink for association and each file attachment requires a separate API call for binary content upload. |
| Custom Modules | high | Each Zoho custom module must become a Salesforce custom object with entirely new API names, and every relationship field and subform must be re-mapped to Salesforce lookups and child objects. |
| Campaigns | medium | Campaign-to-record associations must be rebuilt using CampaignMember junction records in Salesforce, requiring an additional mapping and insert step beyond the campaign records themselves. |
The hard parts
What makes this specific migration difficult, beyond the mechanics.
Relationship Re-Linking After Insert
Zoho Deals linked to Contacts, Accounts, and Activities must be re-linked using new Salesforce IDs post-insert, and any failure orphans pipeline data due to Salesforce's strict referential integrity enforcement.
Activity Polymorphism Translation
Zoho Tasks and Events store a single related-record link, but Salesforce requires splitting this into two separate polymorphic fields—WhoId (Contact/Lead) and WhatId (Account/Opportunity/Case)—requiring resolution logic for every migrated activity.
Picklist and Stage Validation
Zoho allows free-text picklist entry by default, while Salesforce rejects records with values not predefined in restricted picklists, causing INVALID_OR_NULL_FOR_RESTRICTED_PICKLIST errors if stage names and picklist values are not pre-created exactly.
Historical Email Migration Gap
Zoho stores email threads linked to records, but Salesforce has no clean one-to-one import path for historical emails, requiring manual migration to Tasks with Type='Email' or a custom Email_Log__c object.
Blueprint and Automation Rebuild
Zoho Blueprints, workflow rules, custom functions, and approval processes cannot be exported programmatically and must be entirely rebuilt in Salesforce using Flows, Apex, or both.
File and Attachment Model Mismatch
Salesforce modern file storage uses a two-step process requiring ContentVersion and ContentDocumentLink objects with separate API calls for binary content, replacing Zoho's simpler single-attachment model.
Tools used in this playbook
All free, all run entirely in your browser — nothing is uploaded.
FAQ
How long does a Zoho CRM to Salesforce migration take?
A standard sales org with under 500,000 records takes 2 to 6 weeks. Enterprise orgs with custom modules, multi-currency, and heavy activity history take 6 to 14 weeks. The timeline depends on data cleanup effort, number of custom modules, and automation rebuild scope.
What data cannot be migrated from Zoho CRM to Salesforce?
Workflow Rules, Blueprints, Custom Functions, email templates, Canvas Views, approval histories, reports, dashboards, and Zoho SalesSignals cannot be migrated. These are platform-specific logic or UI constructs that must be rebuilt manually in Salesforce using Flows, Apex, and Lightning App Builder.
Can I migrate custom modules from Zoho CRM to Salesforce?
Yes. Zoho CRM custom modules map to Salesforce custom objects. You must create each custom object, define all fields with matching data types, and set up Lookup or Master-Detail relationships before loading data. All API names change because Salesforce appends __c to custom object and field names.
How much does a Zoho CRM to Salesforce migration cost?
Small orgs (under 50,000 records, standard modules) typically cost $2,000 to $5,000 with a managed service or 40 to 80 hours of internal engineering time. Enterprise migrations with custom modules and activity history range from $10,000 to $50,000 with a service provider, or 200 to 500+ hours of engineering effort.
Is there downtime during a Zoho CRM to Salesforce migration?
Not necessarily. The best practice is to run the migration while the sales team continues working in Zoho CRM. After the bulk historical migration completes, run a delta sync to capture records created or modified during the migration window. Then cut over to Salesforce and set Zoho to read-only. This eliminates downtime.