Migrate from Odoo CRM to EspoCRM

Moving from Odoo CRM to EspoCRM is mostly a data mapping and pipeline rebuild job, with documented CSV import doing the transfer. This page sets out what maps, what does not and what drives effort.

On this page

Migrate from Odoo CRM to EspoCRM: what the move involves

If your team runs leads, contacts, companies and opportunities in Odoo CRM and wants EspoCRM on servers you control, the data move is the simpler part of the job. Records can be exported from Odoo list views and imported into EspoCRM with its documented CSV import, but pipelines, activities and access rules have to be rebuilt by hand. Effort depends mostly on how much of your sales process lives in Odoo configuration and how many records and related activities you need to carry over, not on the import itself. On the Odoo side, the export starts from list views. Odoo's Action > Export option writes values from selected records to .csv or .xls, and its import-compatible export option produces a file closer to what an importer expects. Odoo advises smaller batches for large exports, so plan the export by object (leads, contacts, companies, opportunities) and by record count, and confirm the export format against your Odoo version in the Odoo 18.0 export and import documentation. On the EspoCRM side, the import supports Create Only, Create and Update, and Update Only modes, field mapping and duplicate matching, so decide your matching keys (email, company identifier or an external ID you add) before the first run.

Pipelines, stages, activities and user access are where the real work sits. Odoo stage logic, probability values and activity types will not transfer as configuration, so you need to map each stage to an EspoCRM status value, recreate the pipeline view with layouts and filters, and decide which Odoo activities become open tasks or meetings. Ownership and team membership also need a deliberate decision, since EspoCRM controls access through roles and teams. Confirm with your team which historical data must be kept and which can be archived, because each extra object type adds mapping and testing work. Before cutover, confirm the target stack. EspoCRM's server configuration lists PHP 8.3 to 8.5, MySQL 8.0 or newer, MariaDB 10.6 or newer or PostgreSQL 15, and background jobs need cron. Run a test import on a copy, reconcile record counts and relationships, and agree a rollback path with your team. A written scope from a partner should state which objects, mappings and validation steps are covered, so you can compare it with doing the work internally.

Which Odoo CRM objects and features map cleanly to EspoCRM

This table compares the main Odoo CRM objects and features with their closest EspoCRM equivalents and flags where a direct import path does not exist. Read the rows with a clean mapping as candidates for import, and the rows marked for rebuilding as design work to scope before data moves.

Odoo CRM itemEspoCRM equivalentMigration handling
LeadsLead entityImport with field mapping. Confirm which Odoo lead fields your team uses before mapping, since unused fields add noise.
Contacts (res.partner persons)Contact entityImport as contacts. Odoo stores people and companies in one partner model, so split records by type during export preparation.
Companies (res.partner companies)Account entityImport companies first so contacts and opportunities can link to them. Odoo many-to-one parent links must be translated into EspoCRM link fields.
Opportunities and stagesOpportunity entity with a stage enumStage names and probabilities rarely match one to one. Define the EspoCRM stage list first, then translate each Odoo stage value to it in the mapping sheet.
TagsMulti-enum or Entity Manager fieldTags map to a multi-select field. Confirm whether tag values are shared across records or need a new list of allowed options.
Teams and usersTeams and users with rolesRecreate users and teams in EspoCRM before importing records so ownership and assignment fields resolve. Odoo sales team membership does not carry over automatically.
Activities (calls, meetings, to-dos)Calls, meetings and tasksActivities are not a single import object in both systems. Rebuild open activities as tasks or meetings and confirm which completed history you need to keep.
AttachmentsAttachments field storageExport attachments separately and re-link them to records after import. Confirm file sizes and storage location before the transfer.
Odoo Studio customizationsEntity Manager, layouts and formula logicNo direct import path. Rebuild custom fields, layouts and rules in EspoCRM and document each one before loading data.
Multi-company recordsTeams, roles and separate instancesNo direct equivalent to Odoo's company switcher. Decide whether companies become teams, separate instances or access rules, then map records accordingly.

Documented export and import paths for this move

The move has two documented halves: exporting from Odoo list views and importing into EspoCRM. The cards below cover what each side offers, where batch size and matching decisions sit, and what to confirm on your own Odoo edition before planning the extract.

Odoo list-view export

In Odoo 18.0, select the records in a list view, then use Action > Export to pull values from any field on those records. You can choose .csv or .xls output, and an import-compatible export option produces a file shaped for re-import. Export one object at a time (leads, contacts, companies, opportunities) so each file maps cleanly to one EspoCRM entity. Odoo advises smaller batches for large exports, so plan to split the extract by date range or owner.

Import-compatible output and encoding

The import-compatible option matters because it keeps field names and relational values in a form that a second system can read. Confirm that your export produces UTF-8 text, since names and addresses often carry accented characters. Check how many-to-one fields such as salesperson, company and stage come out, because EspoCRM needs those values matched to users, accounts and pipeline statuses before import.

EspoCRM import modes

EspoCRM's CSV import offers Create Only, Create and Update and Update Only modes. Create Only suits a first load into an empty instance. Create and Update fits a re-run after corrections. Update Only is useful when enriching records that already exist, such as adding Odoo IDs to contacts created by hand. Choose the mode per entity and run a small test file before the full load.

Field mapping and duplicate matching

The import screen maps source columns to EspoCRM fields and lets you choose the fields used for duplicate matching. Matching on a stable external identifier, such as the Odoo record ID stored in a custom field, is more reliable than matching on names, which repeat across companies and contacts. Create that identifier field in the Entity Manager before exporting, so every record can be traced back to its source.

Cron execution and reverting imports

Large files should run idle through cron, which EspoCRM requires for background jobs, so the browser session does not have to stay open. Confirm that cron is scheduled on the target server before the first large load. EspoCRM also documents reverting imported records, so keep the import run identifiers and test the revert on a sample file before relying on it for a bad batch.

Export access and edition checks

A list-view export does not need the Odoo Community or Enterprise source code, only a user account with access to the relevant app and records. Confirm with your Odoo administrator that export is enabled for the users who will run it and that the database holds the records you need. Your Odoo edition and hosting plan determine which version you run and who can administer it, so confirm the exact edition and version before you schedule the extract.

How the Odoo to EspoCRM migration runs from inventory to decommission

The sequence moves CRM records and working pipelines from Odoo into EspoCRM in controlled stages, with a checkpoint and rollback path at each one, so the old system can be retired only after the new one is proven. Each phase produces evidence that the previous phase is finished.

  1. Inventory Odoo models, fields and users

    Your team and the implementation partner list every Odoo CRM object in scope: leads, contacts, companies, opportunities, stages, activities, tags, teams and sales users. Custom fields added through Odoo Studio or custom modules are recorded with their types, required flags and option values, and any data that lives outside CRM, such as quotes or invoices linked to opportunities, is marked as in or out of scope. The output is a signed inventory that names an owner for each object. You know this step is done when every field in scope has a target decision: map, transform, archive or drop.

  2. Define the field and stage mapping

    Each Odoo field is mapped to an EspoCRM field, entity or relationship, and each Odoo pipeline stage is mapped to an EspoCRM opportunity stage. Option lists, currency handling, owner assignment, and the rules for matching duplicate contacts and companies are written down. Where a field has no direct equivalent, the mapping states whether it becomes a custom field in the Entity Manager or is kept as text in a notes field. The checkpoint is a mapping sheet that the sales operations lead has reviewed line by line, with each unresolved item assigned to a named person.

  3. Export and load a pilot batch

    A small, representative slice of records is exported from Odoo list views using the import-compatible export option, in batches sized to the volume your team can check by hand. The batch is loaded into a non-production EspoCRM instance using the CSV import with the mapping from the previous step, with duplicate matching set on chosen fields and cron running so larger files process in the background. Imported records can be reverted if the batch is wrong. The checkpoint is a reconciliation report comparing record counts and sample field values between Odoo and EspoCRM, with every mismatch explained or fixed in the mapping.

  4. Rebuild pipelines and activities

    Opportunities are rebuilt with their stages, owners, amounts, close dates and contact or company links. Open activities such as calls, meetings and tasks are recreated against the right parent records, and historical notes are imported where they add value to the sales team. Pipeline views, list layouts and any reports your team relies on are set up in EspoCRM before users see the data. The checkpoint is a sales lead walkthrough of several live opportunities per team, confirming that each stage, owner and next step matches what Odoo shows.

  5. Run both systems in parallel

    For an agreed period, sales users work in EspoCRM while Odoo remains available, and the team records any differences between the two systems. Discrepancies are logged with the record, the field and the cause, then fixed in the mapping or the import rules before the next full load. This is also the period to confirm access rules in EspoCRM, including roles, teams and two-factor authentication, which the security guidance recommends enforcing. The checkpoint is a defect log with no open high-impact items, signed off by the business owner. If parallel use shows a serious gap, the team returns to the mapping step and the Odoo system stays the system of record.

  6. Freeze Odoo edits and run the final load

    Odoo CRM is set to read-only for sales users at an agreed time, and a final delta export is taken from Odoo and loaded into EspoCRM using the same mapping and matching rules as the pilot. Counts and key fields are reconciled again, and EspoCRM becomes the system of record. Before the freeze, the team confirms the rollback plan: if reconciliation fails, Odoo edit rights are restored and the cutover is postponed. The checkpoint is a signed reconciliation report and a go decision from the business owner, recorded before users are told the switch is complete.

  7. Decommission Odoo access and retain archives

    After a stability period agreed in advance, sales user accounts in Odoo are disabled and administrative access is limited to a small group. A final export of the CRM objects is stored as a read-only archive under your retention policy, with the mapping sheet and reconciliation reports kept beside it so future audits can trace how each record was moved. Your team confirms what your Odoo edition and support terms allow for the instance, since Odoo's support windows and upgrade obligations differ by plan and deployment. The checkpoint is a documented decommission record listing archive location, access controls and the date access was removed.

How leads, opportunities and activities are rebuilt, not just copied

A CSV import moves field values, but it does not carry the Odoo pipeline the way your sales team uses it. Stage transitions, the dates they happened, the activity timeline on each record and the email linked to it live in Odoo's own data model, so an export of list-view columns gives you a flat snapshot. Plan to rebuild the pipeline in EspoCRM deliberately: decide which history must remain visible to users, which can be summarized in a note or an archive, and which can be dropped. Confirm this list with the sales managers before the first test import, because it determines how much of the work is data transfer and how much is configuration.

Import in dependency order: companies first, then contacts, then leads, then opportunities. Each child record needs a reference to its parent, and an exported CSV contains Odoo database IDs in relation columns, not EspoCRM IDs. Keep a mapping table from each Odoo identifier to the EspoCRM record it created, and use an identifier field you control, such as an external ID stored on each record, so the second and third imports can match existing parents instead of creating duplicates. The EspoCRM import docs describe duplicate matching on chosen fields and Update Only mode, which are the controls to use for this re-linking. Verify a sample of links after every stage before you proceed.

Stage names and probability values need an explicit translation table. Map each Odoo stage to an EspoCRM opportunity stage, and decide whether Odoo probability percentages are kept as stored values or recalculated from the new stage through a formula in the Entity Manager. Where stage changes should trigger tasks, owner reassignment or notifications, build that logic as workflows or formula scripts after the data is loaded, so that the imported history does not fire automations for records that are already closed. Ask the EspoCRM partner or your own administrator to test these rules against a copy of the data in a non-production instance.

What drives the cost and duration of the move

This table lists the factors that change the effort of moving from Odoo CRM to EspoCRM and shows which costs are paid once and which recur after go-live. Use it to see where a quote can move up or down, and to check that each item in a written scope is priced.

DriverWhy it changes cost or durationWhat to ask for or confirm
Odoo models and custom fieldsEach custom field on leads, contacts, companies or opportunities needs a matching EspoCRM field, layout and mapping decision.Field inventory per model, with a named target entity or field for each
Record volume and export batchesLarge Odoo list-view exports are split into smaller batches, and each batch needs its own check after import.Record counts per model, batch plan and the reconciliation method used after each run
Data quality and duplicatesDuplicate contacts, missing owners and inconsistent stage names add cleaning and matching rules before import.Duplicate matching fields, a cleaning rule list and who approves merged records
Pipeline and activity rebuildOdoo stages, teams and scheduled activities must be recreated as EspoCRM statuses, workflows and tasks rather than copied as-is.A written list of pipelines, stage mapping and which activities are migrated versus recreated
Users, teams and rolesEach user, team and role needs an EspoCRM account and permission set, and access rules are often redesigned during the move.User count, role matrix and whether SSO through OpenID Connect is in scope
Integrations with email, telephony or accountingEach connected system needs its own sync design, credentials and testing, and some may require official EspoCRM extensions.Named integrations, data direction for each, and which extensions are included
Odoo customizationsCustom modules, Studio changes and automated actions in Odoo each need a decision to rebuild, replace or drop them.Inventory of custom modules and automations, with a rebuild or retire decision for each
Parallel run lengthRunning both systems for a period means extra sync or double entry, and a longer window adds coordination effort.Length of the parallel run, who enters data in each system and the cutover acceptance criteria
One-time costs: mapping, pilot and cutoverMapping, a pilot import on a test copy and the final cutover are paid once, but repeat if the pilot fails.Separate line items for mapping, pilot, final import and post-cutover fixes
Recurring costs: hosting, extensions and supportHosting, extension licenses and support continue after go-live and scale with users and modules.Hosting model, extension licensing terms and support hours or retainer terms, stated per year

What usually goes wrong in CRM moves from Odoo and how to prevent it

Most failed Odoo to EspoCRM moves fail in predictable places: records are duplicated, relationships are flattened, and pipelines drift from what sales expects. Each card below names one failure, why it matters for this move, and the preventive step to build into the plan before the first import runs.

Duplicate records from re-imports

Running the same import twice without a matching key creates a second copy of every contact and company. EspoCRM's import offers Create Only, Create and Update, and Update Only modes, so pick the mode deliberately for each run. Set duplicate matching on a stable identifier such as the Odoo record ID carried in a custom field, and run a test batch on a copy of the instance first. Check record counts per entity after every run against the Odoo export.

Lost many-to-one links

Odoo stores an opportunity's company and contact as relational fields, and a flat CSV keeps only the display name. If two companies share a name, opportunities attach to the wrong account. Export the relational ID columns where Odoo offers them, import companies first, and map contacts and opportunities to those imported IDs. Sample a few opportunities per company after import to confirm the link points to the right record.

Stage mismatches that distort pipeline reports

Odoo stage names and sequences rarely match a default EspoCRM opportunity stage list. Unmapped stages can land as blanks or as a generic value, and win rates, forecasts and stage-based reports then mislead managers. Build a stage translation table before importing, agree it with sales leadership, and compare total open value by stage in both systems before go-live.

Activities that do not carry over

Meetings, calls and follow-up tasks live in Odoo's activity model, which a standard list export does not reliably carry across. Open activities are what sales actually works from, so losing them costs more than losing closed history. Decide which activity types must move, export them separately, and link each one to its parent contact or opportunity. Confirm the open-task count per owner after import.

Export truncation from large lists

Odoo's own documentation advises smaller batches for large exports, and a list view with a filter applied can silently hold fewer records than the database. Truncated files produce gaps that appear only weeks later. Export by filtered batches such as by owner or creation range, record the row count of each batch, and reconcile the sum against a count taken directly from Odoo before importing.

Access rules not mirrored in roles and teams

Odoo restricts records through its own user groups and record rules, and those rules do not transfer to EspoCRM. A rep who saw only their region in Odoo may see the whole pipeline after cutover. Document each Odoo access group, then build matching EspoCRM roles and teams before importing owners. Log in as a sample user from each team and confirm the visible record set matches the old system.

Users working in both systems

During a parallel run, reps who update a deal in Odoo while a colleague edits the same deal in EspoCRM create conflicting versions that the next import overwrites. Set a freeze date per entity, announce which system is the system of record for each week, and block edits in the retired system once cutover is confirmed. Re-run only the delta since the last import, and keep an agreed list of who may edit during the overlap.

Questions buyers ask before moving from Odoo CRM to EspoCRM

What does moving from Odoo CRM to EspoCRM cost?

The cost depends on the volume and quality of the data, how many custom fields and pipeline stages must be rebuilt, and whether activities and history need to move. The EspoCRM open-source edition has no license fee to self-host, so the spend is mainly your team's time, any partner services, and the infrastructure you run EspoCRM on. Ask for a quote built from a written scope that lists the objects to move, the fields to map, the pipelines to rebuild and the validation steps. Also ask which costs are one-time (migration, mapping, testing) and which recur (hosting, backups, upgrades, support). Odoo licensing is a separate question for the source system. Confirm the plan you are on before you plan the export.

How long does an Odoo to EspoCRM migration take?

Duration is set by the number of records, how clean the source data is, how many custom pipelines and fields need rebuilding, and how many people must test before cutover. Export batch sizes matter too, since Odoo advises smaller batches for large exports. Plan separate phases for a test import, a review of mapped fields, a full load, and a user acceptance check on real sales workflows. Ask any partner for a timeline tied to the written scope and to the test and cutover dates your business can accept, rather than a generic estimate.

What does our team need to provide for the migration?

Your team needs to name a business owner who can approve the field mapping and pipeline stages, and a data owner who knows which Odoo records are current. Expect to provide Odoo access with rights to export the list views in scope, a list of users and teams that must map to EspoCRM accounts, and sample records for testing. You will also need an EspoCRM environment with a known PHP, database and web server stack, and a decision on how to handle historical activities. Confirm these responsibilities in the written scope before work starts.

Can our own team migrate from Odoo CRM to EspoCRM without a partner?

Yes, a capable internal team can do the work if it has time to test and someone who understands both systems. EspoCRM's CSV import supports Create Only, Create and Update, and Update Only modes, field mapping, duplicate matching on chosen fields and reverting imported records, which makes a staged approach practical. The hard parts are usually rebuilding pipelines and activities, handling relationships between leads, contacts, companies and opportunities, and proving the result is complete. A partner is most useful when volume is high, timelines are tight, or the team has no spare capacity for testing and rollback.

Does Odoo CRM export access depend on the edition or plan?

Odoo's export feature sits in the list view, where users choose records and use Action > Export to download values in .csv or .xls format, with an import-compatible option. Whether your team can export at all depends on the user rights in your Odoo setup and on the plan you run. Odoo's pricing page lists One App Free, Standard and Custom plans, and only the Custom plan can be hosted on Odoo.sh or on-premise. Confirm with your Odoo administrator that the users doing the export have the rights they need, and confirm your plan and hosting model before you rely on a specific export path.

Is the EspoCRM open-source edition free to self-host?

Yes. According to the EspoCRM pricing page, the open-source edition can be downloaded and self-hosted for free, and the project is licensed under AGPL-3.0 according to its GitHub repository metadata. Costs still arise from the servers, database, backups, email delivery and the staff or partner time to run it. EspoCRM Cloud is a separate paid option priced per user per month, with the Advanced Pack included in all cloud plans. Check the license terms for any extensions you plan to use, because official extensions are licensed separately from the core.

How do we revert a bad import into EspoCRM?

EspoCRM's import feature supports reverting imported records, so a failed batch can be undone without rebuilding the database. Keep the source CSV files, the field mapping and a record of each import run so you can identify what changed. Test the revert on a small batch in a non-production instance before you rely on it at full scale. Also confirm that relationships, activities and duplicates created by the import are handled as you expect, because a revert may not undo every downstream change. Make a database backup before each full load as an additional safeguard.

What should we check after the import is complete?

Check record counts for leads, contacts, companies and opportunities against the Odoo export, then sample records to confirm field values, owners and relationships. Verify that pipeline stages map correctly, that open opportunities keep their amounts and close dates, and that activities link to the right records. Confirm user accounts, teams and roles, since access mistakes are easy to miss after a load. Keep a sign-off checklist owned by the business, and confirm your EspoCRM security baseline, including password policy, two-factor authentication and restricted admin use, before users sign in.

How DeployOpen scopes, delivers and supports the Odoo to EspoCRM move

The Odoo to EspoCRM move runs as one written, fixed-scope agreement that connects mapping, batched loads, a pilot, pipeline rebuild, parallel running and cutover. Each card below covers one part of that sequence, from the scope document through delivery inside your own infrastructure to optional support after go-live.

Written fixed-scope agreement

Before work starts, the scope, deliverables and timeline are agreed in writing. For this move, the agreement should name the Odoo objects in scope (leads, contacts, companies, opportunities and the activities attached to them), the Odoo version being exported, the EspoCRM version being built, and the users who will sign off each phase. Ask for a quote that follows directly from this written scope, with each phase listed as a separate deliverable.

Field mapping and value translation

Odoo list-view exports and EspoCRM import fields rarely line up one to one. The mapping document records each Odoo field, its EspoCRM field or custom entity attribute, how stages and tags translate, and which fields are dropped. Review it with the sales operations owner before any batch is loaded, because a wrong stage mapping affects every opportunity that follows.

Batch loads and reverts

Large Odoo exports are split into smaller batches, following Odoo's advice to export in smaller sets. Each EspoCRM import runs with a documented match rule, so duplicates are caught instead of created twice. Every batch is logged with its record count and import identifier, so a bad batch can be reverted without touching the batches that loaded cleanly.

Pilot, rebuild and parallel run

A pilot batch of one sales team's records is loaded first, and the team checks pipelines, owners and open activities against Odoo. Once the pilot is accepted, pipelines, stages and activity reminders are rebuilt in EspoCRM, not copied as raw data. Odoo and EspoCRM then run in parallel for a period you agree in the scope, so sales can confirm that nothing is missing before cutover.

Delivery in your infrastructure

The EspoCRM instance, its database and the migration tooling run in cloud accounts, data centers or networks you control. Odoo credentials are used only for the export window and then removed. Confirm where export files are stored, who can read them, and how they are deleted after cutover, because they contain customer personal data.

Documentation and optional retainer support

The handover includes the mapping document, batch log, revert procedure, the list of rebuilt workflows and the cutover checklist, so your team can explain every migrated record later. After go-live, support can be added as a retainer for fixes, upgrades and questions about the imported data. Ask whether the retainer covers EspoCRM version upgrades and how response times are defined in writing.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.