CRM migration
Field-level mapping, validation, and rollback between HubSpot and Odoo CRM. We move data and schema; workflows are rebuilt natively in Odoo CRM.
HubSpot
Source
Odoo CRM
Destination
Compatibility
11 of 17
objects map 1:1 between HubSpot and Odoo CRM.
Complexity
BStandard
Timeline
3-5 weeks
Try the reverse
Overview
Moving from HubSpot Sales Hub to Odoo CRM is an architectural shift from a marketing-first CRM with separate engagement tools to an ERP-embedded CRM where sales, accounting, inventory, and operations share a single database. HubSpot separates Contacts and Companies as distinct objects with a many-to-many relationship; Odoo merges these into a single Contact record with an optional company field and partner_id field that represents both the person and the organization. We extract Contacts and Companies from HubSpot, merge them on domain or name, and land them as Odoo Contacts with the appropriate partner_category and company_type set. HubSpot Deals map to Odoo CRM Opportunities plus calendar.Events for stage-change milestones. Activity history (calls, emails, meetings, tasks) migrates as chatters and mail.message records threaded to the correct res.partner record. We do not migrate HubSpot Workflows or Sequences as Odoo Server Actions or Automations because the trigger models differ; we deliver a written inventory of every automation requiring rebuild. Odoo custom objects are available through developer-defined models rather than a self-serve UI, so any HubSpot Enterprise custom objects require Odoo developer scoping before migration begins.
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
HubSpot platform overview
Scorecard, SWOT, gotchas, and pricing for HubSpot.
Destination platform
Odoo CRM platform overview
Scorecard, SWOT, gotchas, and pricing for Odoo CRM.
Data migration guide
The complete Odoo CRM migration guide
Data model, import mechanisms, field mapping strategy, pitfalls, and cutover — by the engineers running it.
Source platform guide
HubSpot migration guide
Understand the data you're exporting from HubSpot before mapping it.
Destination checklist
Odoo CRM migration checklist
Pre- and post-cutover tasks for moving onto Odoo CRM.
Source checklist
HubSpot migration checklist
Exit checklist for unwinding your HubSpot 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 HubSpot object lands in Odoo CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.
Typical mapping — final map is confirmed during the sample migration step.
HubSpot
Contact
Odoo CRM
res.partner (company_type = 'contact')
many:1HubSpot Contacts with a Company association merge into the corresponding Odoo res.partner record with company_type='contact' and parent_id pointing to the merged Company partner. Contacts without a company association create standalone res.partner records. The HubSpot email address becomes the res.partner email field and the dedupe key. We use HubSpot's associatedCompany property to resolve the parent_id at migration time. Lifecycle Stage from HubSpot migrates as a res.partner category or customChar field for audit purposes.
HubSpot
Company
Odoo CRM
res.partner (company_type = 'company')
1:1HubSpot Companies map to Odoo res.partner with company_type='company'. The HubSpot company domain becomes the website field. Company properties (industry, annual revenue, number of employees) map to custom fields on res.partner that we define before migration. Company is created before any Contact import so that parent_id references are satisfied at the moment of Contact insert.
HubSpot
Deal
Odoo CRM
crm.lead (type = 'opportunity')
1:1HubSpot Deals map to Odoo crm.lead records with type='opportunity'. The HubSpot dealstage maps to Odoo crm.stage via a stage name lookup we configure before migration. Closed-Lost and Closed-Won dates from HubSpot become Odoo lost_reason and won_date fields. Probability percentage from HubSpot maps to Odoo's stage_id probability or a manual probability field if the stage probabilities do not align.
HubSpot
Deal Stage
Odoo CRM
crm.stage
lossyEach HubSpot pipeline stage becomes an Odoo crm.stage record within the appropriate crm.team. We configure stage names, sequence order, and probability percentages. If HubSpot has multiple pipelines, we map them to separate Odoo crm.team records with their own stage sequences.
HubSpot
Pipeline
Odoo CRM
crm.team
lossyHubSpot's multiple deal pipelines (up to 15 on Professional, 100 on Enterprise) map to separate Odoo crm.team records, each with its own stage sequence. Odoo supports unlimited teams at all tiers, removing the pipeline ceiling that HubSpot enforces at lower tiers.
HubSpot
Lead (Sales Hub Enterprise)
Odoo CRM
crm.lead (type = 'lead')
1:1HubSpot Lead records (Enterprise-only, introduced 2023) map to Odoo crm.lead with type='lead'. The HubSpot lead_status maps to the Odoo crm.stage for leads. Lead score and any custom lead properties migrate as custom fields on crm.lead.
HubSpot
Product
Odoo CRM
product.product
1:1HubSpot Products map to Odoo product.product records with the product type (goods, service) set from HubSpot product type. The HubSpot SKU becomes the Odoo default_code. Product descriptions and URLs migrate as product.description and product.website descriptions respectively.
HubSpot
Line Item
Odoo CRM
sale.order.line
1:1HubSpot Line Items attached to Deals map to Odoo sale.order.line records. We create a draft sale.order attached to the migrated crm.lead opportunity and populate line items with product_id, product_uom_qty, price_unit, and discount. If the Odoo Sale module is not active, line items attach to crm.lead as custom fields instead.
HubSpot
Owner
Odoo CRM
res.users
1:1HubSpot Owners map to Odoo res.users by email match. Any HubSpot Owner without a matching Odoo User is placed in a reconciliation queue for the customer's admin to provision before record import resumes. Inactive HubSpot owners map to Odoo inactive users so that deal and contact assignment history is preserved.
HubSpot
Engagement: Email
Odoo CRM
mail.message (chatter)
1:1HubSpot email engagements migrate to Odoo mail.message records attached to the res.partner record via model='res.partner' and res_id pointing to the partner id. Email body and subject migrate as mail.message body. The HubSpot timestamp becomes mail.message.date for chronological ordering in the Odoo chatter.
HubSpot
Engagement: Call
Odoo CRM
mail.message (subtype = call)
1:1HubSpot call engagements map to Odoo mail.message records with a custom call subtype. Call duration, disposition, and recording URL migrate as custom fields on the mail.message. We set mail.message.date to the original HubSpot timestamp for timeline ordering.
HubSpot
Engagement: Meeting
Odoo CRM
calendar.event
1:1HubSpot meeting engagements map to Odoo calendar.event records. Start datetime, stop datetime, location, and attendee list migrate. Attendees resolve to res.partner records via email match and are added as calendar.event partner_ids. The HubSpot meeting title becomes the calendar.event name.
HubSpot
Engagement: Note
Odoo CRM
mail.message
1:1HubSpot Notes (engagement type NOTE) migrate as Odoo mail.message records attached to the parent res.partner or crm.lead record. The note body migrates as plain text. Attachments on HubSpot notes migrate as Odoo ir.attachment records linked via res_model='res.partner' or 'crm.lead' and res_id pointing to the parent.
HubSpot
Engagement: Task
Odoo CRM
project.task or mail.message
lossyHubSpot Task engagements map to Odoo project.task if the Odoo Project module is active and the customer uses project tracking. Otherwise tasks migrate as mail.message records with a task subtype. Status, priority, and due date migrate directly. HubSpot owner assignment resolves to res.users via email match.
HubSpot
Ticket
Odoo CRM
helpdesk.ticket
1:1HubSpot Tickets migrate to Odoo helpdesk.ticket if the Helpdesk module is active. Ticket pipeline stages map to helpdesk.stage, and ticket properties migrate as custom fields on helpdesk.ticket. If Helpdesk is not active, tickets migrate to crm.lead with a ticket-type tag for manual triage.
HubSpot
Custom Object
Odoo CRM
ir.model (developer-defined)
lossyHubSpot custom objects (Enterprise-only) require Odoo developer scoping before migration. We create the ir.model definition and the corresponding database table via Odoo developer tools or a Python migration script before importing records. Custom object fields map to ir.model.fields with the appropriate ttype (char, many2one, selection, etc.). This step must complete before any custom object records are migrated and may extend the timeline by 2-4 weeks for complex schemas.
HubSpot
Tag (custom property)
Odoo CRM
res.partner.category or custom field
lossyHubSpot tags stored as multi-checkbox contact properties migrate to Odoo res.partner.category (tags) applied to the res.partner record. If the customer has used tags as structured data rather than loose labels, we map them to a custom field (char, selection, or many2many) chosen during scoping. The customer determines the tag strategy before migration.
| HubSpot | Odoo CRM | Compatibility | |
|---|---|---|---|
| Contact | res.partner (company_type = 'contact')many:1 | Fully supported | |
| Company | res.partner (company_type = 'company')1:1 | Fully supported | |
| Deal | crm.lead (type = 'opportunity')1:1 | Fully supported | |
| Deal Stage | crm.stagelossy | Fully supported | |
| Pipeline | crm.teamlossy | Fully supported | |
| Lead (Sales Hub Enterprise) | crm.lead (type = 'lead')1:1 | Fully supported | |
| Product | product.product1:1 | Fully supported | |
| Line Item | sale.order.line1:1 | Fully supported | |
| Owner | res.users1:1 | Fully supported | |
| Engagement: Email | mail.message (chatter)1:1 | Fully supported | |
| Engagement: Call | mail.message (subtype = call)1:1 | Fully supported | |
| Engagement: Meeting | calendar.event1:1 | Fully supported | |
| Engagement: Note | mail.message1:1 | Fully supported | |
| Engagement: Task | project.task or mail.messagelossy | Fully supported | |
| Ticket | helpdesk.ticket1:1 | Fully supported | |
| Custom Object | ir.model (developer-defined)lossy | Fully supported | |
| Tag (custom property) | res.partner.category or custom fieldlossy | 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.
HubSpot gotchas
Marketing Contacts billing model is migration-critical
Feature tier gating is not visible until onboarding
Mandatory onboarding fees inflate year-one cost
HubSpot CSV importer cannot migrate engagements or attachments
Custom objects require Enterprise and a pre-existing schema
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
Pair-specific challenges
Migration approach
Discovery and HubSpot tier audit
We audit the source HubSpot portal across tier (Starter/Professional/Enterprise), custom properties, custom objects, pipeline count, active sequences, active workflows, and engagement volume. We identify all HubSpot objects with data (Contacts, Companies, Deals, Leads, Products, Tickets, Engagements) and estimate record counts per object. We pair this with an Odoo readiness check: which Odoo apps are active in the target database (CRM, Sale, Project, Helpdesk), which Odoo tier the target is on (Community/Standard/Custom), and whether the target is Odoo Online or self-hosted. The discovery output is a written migration scope, record count estimate, and an Odoo module activation plan.
Schema design and Odoo field mapping
We design the destination schema in Odoo. This includes activating the required modules (CRM, Sale, possibly Project and Helpdesk), creating custom fields on res.partner and crm.lead to capture HubSpot properties that have no direct Odoo equivalent, configuring crm.team records to match HubSpot pipelines, configuring crm.stage records with probability percentages aligned to HubSpot dealstage values, and defining any custom ir.model records for HubSpot custom objects. Custom fields are created via Odoo Studio or developer access before any data import.
Contact-Company merge logic and data cleaning
We extract HubSpot Contacts and Companies in parallel, build a domain-to-partner lookup table for the Company merge, and apply the merge logic: Contacts with an associated Company get company_type='contact' with parent_id pointing to the merged res.partner; Contacts without an association create standalone res.partner records. We clean data in transit: duplicate email addresses, missing required fields (name, email), and invalid formats for fields that Odoo validates (email format, phone format). The cleaned output is a set of CSVs ready for Odoo XML-RPC import.
Owner reconciliation and user provisioning
We extract every distinct HubSpot Owner referenced on Contact, Company, Deal, and Engagement records and match by email against the Odoo target database's res.users table. Owners without a matching user go to a reconciliation queue for the customer's Odoo admin to provision. Inactive HubSpot owners map to inactive Odoo users so that historical assignment is preserved even if the original rep is no longer active. Migration cannot proceed past this step because partner and opportunity assignment depends on resolved user records.
Production migration in dependency order
We run production migration in record-dependency order: res.partner (Companies first, then Contacts), crm.lead (Opportunities from Deals, Leads from HubSpot Leads), product.product (Products), sale.order.line (Line Items from Deals), mail.message (Activity history via XML-RPC in batches of 500-1000 records), calendar.event (Meetings), ir.attachment (File attachments), helpdesk.ticket (Tickets if Helpdesk is active), and custom object records (last, after ir.model schema is confirmed). Each phase emits a row-count reconciliation report before the next phase begins.
Cutover, validation, and automation rebuild handoff
We freeze HubSpot writes during the cutover window, run a final delta migration of any records modified during the migration period, then enable Odoo as the system of record. We deliver the Workflow and Sequence inventory document to the customer's Odoo admin or certified Odoo partner. We support a one-week hypercare window where we resolve any reconciliation issues. We do not rebuild HubSpot Workflows as Odoo Server Actions inside the migration scope; that work is scoped as a separate engagement with an Odoo partner.
Platform deep dives
HubSpot
Source
Strengths
Weaknesses
Odoo CRM
Destination
Strengths
Weaknesses
Complexity grading
Standard CRM migration. 1 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 HubSpot and Odoo CRM.
Object compatibility
1 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
HubSpot: 110 requests per 10 seconds per installed account for OAuth apps on the latest platform versions (2025.2 / 2026.03). Free accounts: 100 req/10s and 250,000 daily requests. Professional and Enterprise: 190 req/10s. The CRM Search API has a separate ceiling of 4 requests per second per auth token. 429 is returned on exhaust..
Data volume sensitivity
HubSpot exposes a bulk API — large-volume migrations stream efficiently.
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 HubSpot to Odoo CRM migration scoping. Not seeing yours? Book a call.
Walk through your HubSpot to Odoo CRM migration with a real engineer — 30 minutes, free, written quote within 24 hours.
Book a free 30 minute consultationAdjacent paths
Other ways to leave HubSpot
Other ways to arrive at Odoo CRM
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.