GuideReporting & BIAugust 7, 2026By Olivia, Senior Odoo Architect

Connecting Odoo to Power BI, Tableau or Apache Superset
The three routes, the security trap, and the schema quirks that produce wrong numbers

Odoo's built-in reporting is good at answering questions about one module. It is much weaker the moment a question spans finance, inventory and sales at once, or needs five years of history, or has to sit on a screen in the boardroom next to data from three other systems. That is when teams reach for a BI tool. The connection itself takes an afternoon. What takes longer, and what almost nobody gets right first time, is that querying Odoo's database directly bypasses every access rule Odoo enforces, and that several of Odoo's own storage conventions will silently give you numbers that look plausible and are wrong.

A business intelligence dashboard on screen, showing KPI tiles for click-through rate, cost per conversion and quality score, each with its own trend line

The three ways to get data out of Odoo

There are only three, and the choice is mostly about how much data you need and how fresh it has to be.

Direct PostgreSQL. Odoo stores everything in Postgres, and every BI tool worth using speaks Postgres natively. This is the fastest route, handles millions of rows without complaint, and is what we use for most deployments. It is also the route with the security problem described in the next section, so it should never point at your production database.

The Odoo API. XML-RPC and JSON-RPC respect Odoo's access rules, which sounds like the safer choice. In practice the API is slow for analytical volumes, because it returns records through the ORM rather than aggregating in the database. Pulling three years of journal items this way can take hours. There is also a deadline: Odoo's documentation schedules the removal of both endpoints in Odoo 20, so anything built on them now has a rebuild coming. If your reporting already runs this way, the RPC migration audit exists to inventory exactly that exposure.

ETL into a warehouse. Extract on a schedule into BigQuery, Snowflake or a plain Postgres warehouse, then point BI at the warehouse. This is the right answer when Odoo is one of several systems feeding the same dashboards, or when you want history that outlives your Odoo upgrades. It costs more to build and adds latency measured in hours rather than seconds.

The security trap nobody mentions

Odoo's access control lives in the ORM, not in the database. Record rules, the mechanism that stops a salesperson seeing another region's pipeline and stops one company in a multi-company database seeing another's ledger, are applied as SQL conditions that Odoo appends at query time. They are not Postgres row-level security policies. They do not exist at the database layer at all.

The consequence is blunt: a direct database connection sees everything. Every company, every salesperson's opportunities, every employee's salary if you run HR in Odoo. A BI tool connected straight to Odoo's database has, in effect, superuser visibility, and whoever can build a chart can read the whole company.

This is not a reason to avoid the direct route. It is a reason to put the access control somewhere else. That means a read-only database user restricted to the tables reporting actually needs, curated views that pre-filter by company, and row-level security enforced in the BI tool rather than assumed from Odoo. Superset and Power BI both support this properly. What does not work is connecting a tool to Odoo's database and trusting that people will only look at their own data.

It is also why we never point BI at production. A read replica costs little, removes the risk of an analytical query locking tables during month end, and gives you somewhere to put those curated views without touching the live schema.

Five Odoo conventions that produce wrong numbers

These are the ones that catch people, in rough order of how often we see them. Each produces output that looks entirely reasonable, which is what makes them dangerous.

Soft deletes. Odoo does not delete much. Archiving sets active = false and the row stays. A count of products or customers that ignores active includes everything ever archived, which on a mature database can be a large fraction of the table.

Draft records. In accounting, account_move_line is the fact table you want, but it contains lines belonging to unposted drafts. Reporting revenue without filtering on the move's posted state inflates it with invoices nobody has confirmed. The same applies to draft sales orders and unvalidated stock moves.

Translatable fields are JSON. Since Odoo 16, translatable fields such as product names are stored as JSONB, not text. A naive SELECT name FROM product_template returns {"en_US": "Desk", "fr_CA": "Bureau"} rather than a label. You need to extract the key for the locale you are reporting in.

Multi-company. Almost every operational table carries company_id. If you run more than one company in one database and forget it, you silently consolidate entities that your accountant reports separately.

Many-to-many lives in join tables. Tags, categories and similar relations are not columns. They sit in separate relation tables, and joining them without care multiplies your rows, which quietly doubles or triples any metric summed across the join.

Power BI, Tableau or Superset

All three connect to Odoo's Postgres perfectly well. The differences that matter are licensing, where your data ends up, and who is going to maintain the thing in two years.

Power BI is the pragmatic choice if you are already a Microsoft organisation. Licensing is per user and modest, the modelling layer is genuinely strong, and your finance team probably already knows it. The friction is that connecting to a self-hosted Odoo database from the Power BI service requires an on-premises data gateway, which is one more component to run and keep patched. Import mode is usually the right setting rather than DirectQuery, because DirectQuery pushes interactive query load straight at your replica.

Tableau has the best visualisation craft of the three and the most expensive seats. It earns that money when you have analysts who spend their day in it. For a dashboard that a dozen managers glance at once a week, the per-seat cost is very hard to justify against the alternatives.

Apache Superset is what we usually recommend, and the reasoning is the same reasoning that leads people to Odoo. It is open source with no per-seat licence, so adding the twentieth viewer costs nothing and you are not re-running a procurement conversation every time reporting spreads. It is self-hosted, so operational data never leaves infrastructure you control, which matters when the dashboard contains margin and payroll. SQL Lab suits the kind of person who is comfortable writing the query that answers the actual question. Its row-level security is the mechanism that replaces the Odoo record rules a direct connection bypasses.

The honest counterweight: Superset needs someone to run it. It is a Python application with a metadata database, a cache and a worker queue, and nobody sends you a patch notification. If you have no infrastructure capability and no partner maintaining it, Power BI's managed service is the more sensible answer, and we will say so rather than sell you something you cannot operate.

The setup we actually deploy

For most clients the shape is the same, and it takes two to four weeks rather than a quarter.

A streaming read replica of the Odoo database, so analytical load never touches production. A dedicated read-only role on that replica with access only to the tables reporting needs. A schema of curated views that resolve the traps in section three once, centrally: active filtered, drafts excluded or explicitly flagged, JSONB names extracted to the reporting locale, company_id exposed so it can be filtered rather than forgotten. Superset on top, with row-level security mapping users to the companies and regions they are allowed to see.

The curated views are the part that matters most and the part people skip. Without them every analyst re-derives the same joins slightly differently, and within a year you have three dashboards that disagree about revenue. With them, the definition of revenue lives in one place, and when it changes it changes once.

See how we build Odoo reporting →

Thinking about reporting on top of Odoo?

Tell us which questions your current reporting cannot answer, how many people need to see the result, and whether you run more than one company in the database. We will tell you which of the three routes fits, and whether Superset or Power BI is the better call for who has to maintain it.