CRM migration
Field-level mapping, validation, and rollback between Odoo CRM and Freshsales. We move data and schema; workflows are rebuilt natively in Freshsales.
Odoo CRM
Source
Freshsales
Destination
Compatibility
3 of 8
objects map 1:1 between Odoo CRM and Freshsales.
Complexity
BStandard
Timeline
2-4 weeks
Try the reverse
Overview
Moving from Odoo CRM to Freshsales is a schema rationalization, not a straight copy. Odoo stores Leads and Opportunities in a single crm.lead table with a type discriminator, and Contacts are res.partner records shared with the ERP side of the install. Freshsales uses a separate Contacts module (Leads auto-convert to Contacts with linked Accounts and Deals), which means the Odoo crm.lead split must be resolved during migration design, not after data lands. We export res.partner records to build Freshsales Contacts and Accounts, map crm.lead type='lead' to Contact-only records and type='opportunity' to Contact plus Deal records, and preserve activity history from mail.activity with its original timestamps. Automation rules, server actions, and Enterprise-only features like AI lead scoring do not migrate; we deliver a written inventory of every Odoo automation requiring rebuild in Freshsales Workflows and the customer's admin handles the rebuild post-migration.
Every standard and custom field arrives verified.
AI proposes the map; you confirm before any record moves.
Parent–child, lookups, and ownership stay linked.
Calls, emails, meetings — with original timestamps.
Documents, uploads, and inline notes move with the record.
Source platform
Odoo CRM platform overview
Scorecard, SWOT, gotchas, and pricing for Odoo CRM.
Destination platform
Freshsales platform overview
Scorecard, SWOT, gotchas, and pricing for Freshsales.
Data migration guide
The complete Freshsales migration guide
Data model, import mechanisms, field mapping strategy, pitfalls, and cutover — by the engineers running it.
Source platform guide
Odoo CRM migration guide
Understand the data you're exporting from Odoo CRM before mapping it.
Destination checklist
Freshsales migration checklist
Pre- and post-cutover tasks for moving onto Freshsales.
Source checklist
Odoo CRM migration checklist
Exit checklist for unwinding your Odoo CRM setup cleanly.
Why teams make this switch
Leaving
What's pushing teams away
Choosing
What's pulling them in
Object mapping
Each row shows how a Odoo CRM object lands in Freshsales, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
Odoo CRM
res.partner
Freshsales
Contact and Account
1:manyOdoo stores both individual contacts and company records in the same res.partner table, with the commercial partner linked via parent_id. We split this into Freshsales Contacts (individual) and Accounts (organization). Where parent_id is set in Odoo, we create the parent as a Freshsales Account and link the child records as Contacts under it. The commercial partner_id field becomes the Account link for individual contact records. Email serves as the dedupe key during import. Odoo's partner fields (phone, street, city, country) map to Freshsales Contact and Account address fields with a rule applied: if the Odoo record has child partners, it lands as an Account; standalone partners with no children land as Contacts.
Odoo CRM
crm.lead (type=lead)
Freshsales
Contact
1:1Odoo Leads are crm.lead records where type='lead'. These map directly to Freshsales Contacts without an associated Account or Deal. The lead's contact_name, email_from, phone, source_id (lead source), and any custom fields migrate. We set the Lead Status in Freshsales to New and preserve Odoo's stage_id as a custom field crm_original_stage__c so the customer's admin can re-stage leads after migration if needed.
Odoo CRM
crm.lead (type=opportunity)
Freshsales
Contact + Account + Deal
1:manyOdoo Opportunities are crm.lead records where type='opportunity', linked to res.partner via partner_id and to crm.stage via stage_id. We create a Freshsales Account from the Odoo partner_id, link a Contact to that Account, then create a Freshsales Deal tied to the Contact and Account. The Odoo expected_revenue maps to Freshsales Deal amount, probability migrates as a custom field deal_probability__c (Freshsales does not use Odoo's float probability natively), and date_closed maps to the Deal's close date. Odoo's lost reasons stored in the crm.lead write_date and stage_id transitions become Freshsales Deal stage notes.
Odoo CRM
crm.stage
Freshsales
Deal Stage
lossyOdoo pipeline stages are stored in crm.stage and ordered per team via crm.team.stage.rel. We extract the full stage list per team and configure Freshsales pipeline stages in the same sequence. Each Odoo stage name becomes a Freshsales stage name, and the probability values stored in crm.stage.on_change_state migrate to the corresponding Freshsales stage probability. Custom stages added by the customer via Studio or custom addons are included in the export. We sequence stage creation before Deal migration so that Deals can reference valid stage IDs at import time.
Odoo CRM
crm.team
Freshsales
Sales Team
1:1Odoo Sales Teams map to Freshsales Teams. We extract team members from crm.team.member_ids and map each Odoo team member (res.users) to a Freshsales User by email match. Odoo's team-level stage configurations map to Freshsales pipeline assignments per team. If Odoo's team structure is flat (no separate teams), we create a single Freshsales team and assign all Deals to the default pipeline.
Odoo CRM
mail.activity
Freshsales
Task
1:1Odoo Activities linked to crm.lead records migrate to Freshsales Tasks. Activity type (call, email, meeting, todo, reminder) maps to Freshsales Task type. date_deadline migrates to the Task due date, user_id resolves to the Freshsales User by email, and the activity note (mail.message body) becomes the Task description. Activity history is high-volume and loosely coupled via activity_ids on crm.lead; we resolve the parent Odoo crm.lead record to its Freshsales Contact or Deal counterpart before inserting each Task so no orphaned activity records appear in Freshsales.
Odoo CRM
crm.tag
Freshsales
Tag (Contact and Deal)
lossyOdoo Tags are stored in crm.tag and applied to crm.lead via a many2many field. We export the full tag list as flat name values and create matching tags in Freshsales before record import. During Contact and Deal import, we resolve each tag name and attach it via Freshsales' tag API. Custom tags added by the customer are included in the export. Note that Freshsales uses a separate tagging system for Contacts and Deals; Odoo's shared tag pool is preserved but customers may choose to maintain separate tag lists per object post-migration.
Odoo CRM
Custom fields on crm.lead
Freshsales
Custom fields on Contact and Deal
lossyOdoo custom fields defined via Studio or custom addons are stored as columns in crm.lead. We export field definitions alongside data, then pre-create matching custom fields in Freshsales before import. Selection fields map to Freshsales dropdown; many2one fields to Freshsales lookup relationships (where the related Odoo model has a corresponding destination object); many2many to Freshsales multi-select. Float and integer fields map directly. HTML-formatted custom fields are stripped to plain text because Freshsales custom fields do not support rich-text storage. If the Odoo custom field references an Enterprise-only addon, we flag it as unmigratable and document the data loss for the customer's admin.
| Odoo CRM | Freshsales | Compatibility | |
|---|---|---|---|
| res.partner | Contact and Account1:many | Fully supported | |
| crm.lead (type=lead) | Contact1:1 | Fully supported | |
| crm.lead (type=opportunity) | Contact + Account + Deal1:many | Fully supported | |
| crm.stage | Deal Stagelossy | Fully supported | |
| crm.team | Sales Team1:1 | Fully supported | |
| mail.activity | Task1:1 | Fully supported | |
| crm.tag | Tag (Contact and Deal)lossy | Fully supported | |
| Custom fields on crm.lead | Custom fields on Contact and Deallossy | Fully supported |
Gotchas + challenges
Platform-specific issues from each side, plus the pair-specific challenges that don't show up on either platform's page on its own.
Odoo CRM gotchas
Odoo.sh version gating blocks assisted migrations from trial
Enterprise modules fail to install on Community after database restore
Custom module view inheritance breaks between Odoo major versions
Custom fields risk losing their application context on Community
API access for Community is gated behind the Custom Plan
Freshsales gotchas
Freddy AI is Pro-tier only despite heavy marketing
Post-migration emails and sequences are disabled
Bot session credits are a one-time 500-session allocation
Phone credits charged per minute with no cap
File storage limits scale with plan tier
Pair-specific challenges
Migration approach
Discovery and API access check
We audit the source Odoo instance across edition (Community vs Enterprise vs Odoo Online), version, installed modules, and API availability. For Community edition sources, we test XML-RPC connectivity and fall back to a PostgreSQL read-only connection if the endpoint is unavailable or rate-limited. We inventory crm.lead records (count by type, stage, and team), res.partner records (count, parent-child relationships), crm.tag entries, mail.activity volume, and any custom addons that extend crm.lead with additional columns. The discovery output is a written migration scope and a schema diff between the Odoo model and the Freshsales target schema.
Schema design and field-level mapping
We design the Freshsales target schema before any data moves. This includes creating Freshsales pipeline stages matched to the Odoo crm.stage sequence, setting stage probabilities, creating Teams per Odoo crm.team, provisioning any custom fields on Contact and Deal objects, and defining the crm.lead split rule (which Odoo Leads become Contacts, which Opportunities become Account-Contact-Deal triplets). For each Odoo crm.lead custom field, we assign a Freshsales custom field with a matching type or document the transformation required. Schema is built in the customer's Freshsales sandbox first.
Data audit and cleansing
We export a sample of Odoo records and run a data quality audit: duplicate email addresses on res.partner, incomplete crm.lead records missing required Freshsales fields, inconsistent date formats in date_closed and activity deadlines, and any Odoo-specific field values that have no Freshsales equivalent. We flag dirty data (duplicate records, missing required fields) in a written report and provide a deduplication rule for the customer's admin to approve before migration runs. This step prevents record rejections at import time and is the most common cause of migration delays if skipped.
Sandbox migration and reconciliation
We run a full migration into the Freshsales sandbox using production-like data volume. The customer's RevOps lead reconciles record counts (Contacts in, Accounts in, Deals in, Tasks in), spot-checks 25-50 records against the Odoo source, and signs off the schema and mapping before production migration begins. Any field mapping corrections, stage adjustments, or split rule refinements happen here. This step is mandatory before we proceed to production because Odoo's relational model means corrections in production require re-running the entire migration.
Production migration in dependency order
We run production migration in record-dependency order. Accounts (from Odoo res.partner with parent_id set) load first. Contacts load second with AccountId resolved from the parent_id lookup. Leads from Odoo type='lead' load as Freshsales Contacts with no Account. Opportunities from Odoo type='opportunity' load as Deals with ContactId and AccountId resolved. Tasks migrate via Freshsales REST API with parent record lookup (Contact or Deal ID) resolved at migration time. Tags attach to their parent records after the parent record IDs are confirmed in Freshsales. Each phase emits a row-count reconciliation report before the next phase begins.
Cutover, validation, and automation rebuild handoff
We freeze Odoo writes during cutover, run a final delta migration of any records created or modified during the migration window, then set Freshsales as the system of record. We deliver a written inventory of every Odoo automation rule and server action with its trigger, conditions, and recommended Freshsales Workflow equivalent. We support a one-week hypercare window where we resolve any reconciliation issues raised by the customer's sales team. We do not rebuild Odoo automation rules as Freshsales Workflows inside the migration scope; that work is handled by the customer's admin using the inventory document.
Platform deep dives
Odoo CRM
Source
Strengths
Weaknesses
Freshsales
Destination
Strengths
Weaknesses
Complexity grading
Standard CRM migration. 2 of 8 objects need a mapping; the rest are 1:1.
Overall complexity
Standard migration
Derived from compatibility, mapping clarity, API constraints, and data volume across Odoo CRM and Freshsales.
Object compatibility
2 of 8 objects need a mapping; the rest are 1:1.
Field mapping clarity
Field mapping is derived from defaults — final spec confirmed during the sample migration.
Timeline complexity
8-object category — typical timelines run 2–7 days end-to-end.
API constraints
Odoo CRM: Not publicly documented; no published rate limit found in Odoo's official developer documentation.
Data volume sensitivity
Odoo CRM doesn't expose a bulk API — REST + parallelization used for high-volume runs.
Estimator
Rule-based pricing — no per-record fees, no manual quotes. Migrations over 2M records are scoped individually.
Step 1
Pick a category, then your source and destination platforms.
Category
FAQ
Answers to the questions buyers ask most during Odoo CRM to Freshsales migration scoping. Not seeing yours? Book a call.
Walk through your Odoo CRM to Freshsales migration with a real engineer — 30 minutes, free, written quote within 24 hours.
Book a free 30 minute consultationAdjacent paths
Other ways to leave Odoo CRM
Other ways to arrive at Freshsales
Ready when you are
Tell us record counts and timeline. We'll come back with a written quote inside 1 business day — no commitment, no sales pitch.