---
title: "Connecting Odoo to Your Web Shop: What to Sync and How"
description: "Why Odoo on its own is not built to serve a fast shop, how a headless storefront with Meilisearch in between should be connected to it, which plan and API it needs, and what your marketing team can change alone."
date: 2026-10-06
author: "David Wippel"
tags: ["ecommerce", "migration"]
url: https://www.essentialcode.eu/blog/odoo-web-shop-integration/
---

# Connecting Odoo to Your Web Shop: What to Sync and How

> Why Odoo on its own is not built to serve a fast shop, how a headless storefront with Meilisearch in between should be connected to it, which plan and API it needs, and what your marketing team can change alone.

**TL;DR.** Odoo runs products, stock and orders well, but on its own it is not built to serve a fast, busy shop: on its cloud, Odoo's policy treats about one API call per second as normal. The build we use is a headless storefront that reads catalogue, prices, stock and search from Meilisearch, kept in sync from Odoo, with orders written back to Odoo. It needs a Custom plan and should use the new JSON-2 API.

Odoo already runs your products, stock, pricelists, orders and invoices, and it does that well. It also comes with its own shop. From building shops on Odoo, our view is that Odoo on its own is not built to serve a fast storefront with real traffic, and that its web front holds a marketing team back.

So the build we recommend has three parts: a headless storefront for everything the customer sees, Meilisearch in the middle holding a fast copy of the catalogue, and Odoo behind it, receiving the orders. The rest of this post covers why, how the data moves, which Odoo plan and API it needs, and what your marketing team can change on its own afterwards.

## Why is Odoo on its own not enough for a fast shop?

Odoo does include a shop. [Odoo eCommerce](https://www.odoo.com/documentation/19.0/applications/websites/ecommerce.html), in Odoo's words, "provides an open-source platform for building and managing an online store". For a small catalogue with modest traffic that can be enough. We see three reasons it stops being enough.

**The web front is Odoo-specific technology.** Odoo's pages are rendered with [QWeb](https://www.odoo.com/documentation/19.0/developer/reference/frontend/qweb.html), which Odoo describes as "the primary templating engine used by Odoo" and "an XML templating engine". Its JavaScript runs on [Owl](https://github.com/odoo/owl), a UI framework "built by Odoo", and Odoo's own documentation says the framework ["is also used in other situations, such as the Odoo website"](https://www.odoo.com/documentation/19.0/developer/reference/frontend/framework_overview.html). Few web developers outside the Odoo world work with either, and in our experience finding one for a design or campaign change takes a while. Within those templates, design and campaign pages are limited to what the theme and the website builder allow.

**Odoo's cloud is not meant to answer page views through the API.** Odoo's [acceptable use policy](https://www.odoo.com/acceptable-use) prohibits "sending large numbers of RPC or remote API calls to our systems without appropriate throttling" and gives the working figure: "Throttled calls are typically acceptable for unsustained usage at a rate of 1 call/second, with no parallel calls." A product listing and a product page from a handful of visitors exceed that within seconds, and the policy says customers who break its rules "may see their subscriptions suspended without prior notice". Odoo names one exit: "On Odoo.sh the dedicated hosting mode can be considered as an alternative to lift this restriction." On-premise, the ceiling is your own server.

**Every API call is a separate piece of work.** In Odoo's [JSON-2 API](https://www.odoo.com/documentation/19.0/developer/reference/external_api.html), "all calls to the JSON-2 endpoint run in their own SQL transaction." A page that needs a product, its price and its stock either makes several round trips or depends on a custom method that bundles them.

Odoo is an ERP, and it is good at being one. A shop page has to load in a moment for every visitor, during a campaign as well, and that is a different job.

## How does the layer between the storefront and Odoo work?

We use [Meilisearch](https://www.meilisearch.com/docs/learn/getting_started/what_is_meilisearch) as that layer. It holds a copy of every product with its prices and stock, and the storefront reads listings, product pages, search and filters from it. Odoo never sees a page view.

What Meilisearch documents about itself, and why it matters here:

| Meilisearch, in its own documentation                                                                                                                                                                      | What it means for the shop                             |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| "Every query returns results in under 50 milliseconds, whether your index contains a thousand documents or tens of millions."                                                                              | Category pages and search do not wait on the ERP       |
| Built for "search-as-you-type interfaces, faceted navigation, filtering, sorting"                                                                                                                          | Filters by size, colour or price come with it          |
| ["Typo tolerance is enabled by default"](https://www.meilisearch.com/docs/learn/relevancy/typo_tolerance_settings)                                                                                         | A search for a misspelled product still finds it       |
| A partial update means ["fields not included in the update remain unchanged"](https://www.meilisearch.com/docs/capabilities/indexing/how_to/add_and_update_documents)                                      | A stock change updates only the stock field            |
| ["Processing operations asynchronously allows Meilisearch to handle resource-intensive tasks without impacting search performance."](https://www.meilisearch.com/docs/learn/async/asynchronous_operations) | A full catalogue re-sync runs without slowing the shop |

The last row has a consequence worth knowing: updates are queued as tasks, so a change reaches the shop shortly after it is made. For prices and descriptions that does not matter. For stock it is one more reason the order step checks with Odoo.

Data moves in two directions:

- **Odoo to Meilisearch, for catalogue, prices and stock.** Odoo's automation rules can [send a webhook notification](https://www.odoo.com/documentation/19.0/applications/studio/automated_actions.html), a POST request "with the values of the selected Fields" to a URL you set, so an edit in Odoo triggers an update. A scheduled full sync on top catches anything a webhook missed.
- **Storefront to Odoo, for orders.** Orders skip the copy and go straight into Odoo, written once, with retries, and never lost when Odoo is briefly unreachable.

## Does your Odoo plan allow an external shop?

Check this first, because it can end the project before it starts. Odoo's API documentation states that ["access to data via the external API is only available on Custom Odoo pricing plans"](https://www.odoo.com/documentation/19.0/developer/reference/external_api.html) and "is not available on One App Free or Standard plans." Syncing to Meilisearch and writing orders back both need that access.

Where Odoo is hosted decides how much you can extend it:

| Hosting     | What it means for the integration                                                                                                                                                                                     |
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Odoo Online | ["Odoo Online is incompatible with custom modules or modules from the Odoo Apps Store"](https://www.odoo.com/documentation/19.0/administration/odoo_online.html), so the integration works with standard methods only |
| Odoo.sh     | Odoo's platform for ["development, staging and production branches, allowing you to develop or use custom modules"](https://www.odoo.com/pricing)                                                                     |
| On-premise  | You host Odoo Enterprise yourself. Custom modules are possible                                                                                                                                                        |

The custom module question decides whether the integration can add one method inside Odoo for a job like "create this web order and confirm it", or has to string several standard calls together from outside.

## Which system owns what?

Meilisearch holds a copy of products, prices and stock, and Odoo stays the system that owns them. Settle the rest before anyone writes code.

| Data                                 | Owned by                   | Why                                                                                                                                                                                                                                                    |
| ------------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Products and variants                | Odoo                       | Stock, purchasing and invoicing all hang off the product record                                                                                                                                                                                        |
| Prices and discounts                 | Odoo                       | [Pricelists](https://www.odoo.com/documentation/19.0/applications/websites/ecommerce/configuration/prices.html) handle "different prices and discounts based on currencies, time periods, purchase volumes, customers' location, and/or customer type" |
| Stock levels                         | Odoo                       | The storefront displays a number it did not calculate                                                                                                                                                                                                  |
| Tax rates                            | Odoo                       | The invoice is posted in Odoo, so the shop's rates come from there                                                                                                                                                                                     |
| Orders and invoices                  | Odoo                       | Fulfilment and invoicing happen in Odoo                                                                                                                                                                                                                |
| Order confirmation e-mail            | Usually Odoo               | On a client's headless shop running on Odoo, it comes out of an Odoo template                                                                                                                                                                          |
| Pages, campaigns, navigation, images | The storefront and its CMS | Odoo does not need to know about them                                                                                                                                                                                                                  |
| Product descriptions                 | Your choice                | Either side works. Pick one deliberately                                                                                                                                                                                                               |

If product descriptions live in Odoo, your content team files a request every time a sentence changes. If they live in the CMS, operations loses sight of what the shop says. Decide before launch, because moving them later means a content migration.

## Which Odoo API should the integration use?

Build on the [External JSON-2 API](https://www.odoo.com/documentation/19.0/developer/reference/external_api.html), which is "new in version 19.0". Odoo's documentation says the older XML-RPC and JSON-RPC endpoints are ["scheduled for removal in Odoo 22 (fall 2028) and Online 21.1 (winter 2027)"](https://www.odoo.com/documentation/19.0/developer/reference/external_rpc_api.html). An integration written against them today has to be rewritten, and on Odoo Online sooner.

Three details from the JSON-2 documentation shape the build:

1. **One API key per integration.** Odoo recommends "dedicated bot users" for automated integrations, so the key has only the permissions it needs and the access log shows which system made each change.
2. **No transaction spans two calls.** "Using the JSON-2 API, it is not possible to chain multiple calls inside a single transaction." Odoo calls this "especially dangerous when performing operations related to reservations, payments, and such", which describes a checkout. Its fix is one method doing all related work, written "in a dedicated module" if needed. On Odoo Online that module is not an option.
3. **Each database is different.** "The actual models, fields and methods available are specific to every database", and each one lists its own on a `/doc` page.

## Which stock number, and when does an order count?

Two decisions that look small and cause most of the support tickets later:

- **Stock.** Odoo documents two numbers: [on-hand](https://www.odoo.com/documentation/19.0/applications/inventory_and_mrp/inventory/product_management/configure/type.html), "the number of units currently available in inventory", and forecasted, which is on hand plus incoming minus outgoing shipments. They differ exactly when an item is popular. Pick one for Meilisearch, and check availability against Odoo again when the order is placed.
- **Orders.** Odoo's own shop moves an order from "Quotation Sent" to "Sales Order" once ["the payment has been successfully received"](https://www.odoo.com/documentation/19.0/applications/websites/ecommerce/order_handling.html). An external shop has to decide where in that flow it writes.

## What can your marketing team change without a developer?

This is the reason to build the storefront separately, so write it down before launch.

| Without a developer                           | Stays with whoever runs Odoo                  |
| --------------------------------------------- | --------------------------------------------- |
| Page layout, campaign and landing pages       | Pricelists and discounts                      |
| Navigation, images, editorial copy            | Tax settings                                  |
| SEO titles and descriptions                   | Stock rules and which quantity the shop shows |
| Product descriptions, if they live in the CMS | Order flow and confirmation e-mail templates  |

If the left column ends up in a ticket queue anyway, the project has not done its job.

## Questions to ask before you start

Ask these of whoever builds it and whoever administers Odoo:

1. Are we on a Custom plan, and where is Odoo hosted?
2. Which system holds product descriptions, and who can edit them without a request?
3. Which stock number goes to the shop, and is it checked again at checkout?
4. How quickly does a change in Odoo reach Meilisearch, and how often does the full sync run?
5. What happens to an order placed while Odoo is unreachable?
6. Is the integration on JSON-2, and if not, when does it move?
7. Which steps of creating an order run as separate calls, and what happens if one fails halfway?
8. Who is notified when a sync fails, and who is notified when it succeeds but skips records?

Question 8 is the one most often missing, because a sync that skips records still reports success and nobody gets told.

If your marketing plan needs a better shop and the engineers who could build it are busy with the product, this is the work we do. Our [Odoo e-commerce integration](/services/odoo-ecommerce-integration/) page explains how we connect a headless storefront to Odoo, and [what a website audit reveals](/blog/what-a-website-audit-reveals/) covers how we look at an existing shop before anyone scopes a rebuild.