One day, out of curiosity, you run your Odoo website through PageSpeed Insights. The score comes up red. 45. 38. On Odoo's official forum, some report 19 out of 100. The reflex is immediate: you've been had, or the integrator cut corners.
Neither. We measured, with figures, what an Odoo page actually sends to your visitor. The cause is structural, it is perfectly logical — and there is only one way to truly escape it: code the page yourself.
1. No, your integrator didn’t cut corners
The topic comes up again and again on Odoo's forum, and almost always without a clear answer: “is there an Odoo site above 60 on mobile?”, “my site has a bad PageSpeed score”. The replies go in circles — enable a CDN, compress your images — without ever naming the real cause.
This cause has nothing to do with your theme, your host or the quality of your implementation. It is built into the way Odoo's Website module works. Until you understand that, you wear yourself out optimising details that will never move the needle by more than a few points.
💡 The key takeaway up front
A low PageSpeed score on Odoo is not a manufacturing defect or negligence. It is the price of a feature you most likely demanded: being able to edit your website yourself, by drag and drop, without a developer.
2. What an Odoo page actually sends
Enough theory. We measured our own server: Odoo 19, a single instance, a single domain name, the same cache and the same CDN for everyone. On one side a standard Website page (a simple contact form), on the other a services page that we serve differently. The protocol is trivial to reproduce: fetch the HTML, list the <script src> tags and the stylesheets, weigh each file.
Here is what the browser has to download before it can display anything:
📊 Standard Odoo page — the details
web.assets_frontend_lazy.min.js — 2,318 KB
web.assets_frontend.min.css — 809 KB
web.assets_frontend_minimal.min.js — 30 KB
Total imposed by Odoo: 3,157 KB, spread over 7 blocking requests.
By comparison, the services page you are reading on this same server loads 25 KB of CSS and zero kilobytes of application JavaScript.
3. Why 3.1 MB to display a contact form?
Because Odoo doesn't know in advance what you will do with this page. The assets_frontend bundle doesn't contain “what's needed to display a form”. It contains everything an Odoo website might need: the live content editor, the complete snippet library, the e-commerce cart and checkout, the customer portal, blog widgets, animations, image galleries.
This package is assembled once for the whole site, then served on every public page, identically. Your “Legal notice” page, which contains only text, downloads the e-commerce engine. Your contact form downloads the website editor. The visitor pays for features they will never see.
This isn't absurd: it's the deal. This bundle is exactly what lets you click “Edit”, move a block with the mouse and publish without calling anyone. The weight is not a bug, it's the bill for autonomy.
💡 The direct consequence
No setting, no Odoo configuration option will let you go significantly below these 3 MB as long as the page goes through the standard template of the Website module. The ceiling is structural.
4. What Google really measures (and what it ignores)
Before you panic, a clarification that is worth money: the PageSpeed score is not a grade Google gives your SEO. It is the result of a lab test, run on a deliberately throttled mobile device and a deliberately slow connection. It is meant to diagnose, not to penalise.
What Google actually uses in its ranking is the Core Web Vitals measured on your real visitors — their real phones, their real connection, often with your files already cached. These figures are consistently better than the lab score. And even they only act as a tiebreaker between two results of equivalent quality: mediocre but fast content will never outrank excellent but slow content.
In other words: a red score does not make you vanish from Google. It does, however, cost you where it can be measured — bounce rate and conversion. On a landing page that receives paid advertising traffic, every second of waiting is paid for in lost visitors. That, not ranking, is where the real stake lies.
⚔️ The Match: standard Odoo page vs custom-coded page
| Criterion | Standard Website page | Custom-coded page |
|---|---|---|
| JS + CSS weight | 3,157 KB | 25 KB |
| Blocking requests | 7 | 3 |
| Unused JavaScript | Most of the bundle | None |
| Edited by the client | Drag and drop, autonomous | Goes through a developer |
| Ideal use case | Internal pages, living content | Landing pages, strategic pages |
Measurements taken on the same Odoo 19 instance, same domain, same CDN. The real total of the standard page reaches 3,654 KB once audience-measurement tools are added.
5. Half-measures, and where they stop
The usual advice isn't wrong, it is simply capped. You should apply it — it's cheap — but knowing what it delivers:
A CDN and proper caching: the most profitable gain. Your 3 MB travel a shorter distance and are reused from one page to the next. The first display stays heavy, the following ones become comfortable.
Uninstall unused Website modules: each active module adds its share to the bundle. A showcase site dragging along e-commerce without using it can really slim down. Typical gain: a few hundred kilobytes.
Compress images and enable lazy loading: essential, and often the first real culprit behind the Largest Contentful Paint. But it doesn't touch the 3,157 KB of code in the slightest.
Add it all up: you gain ten to twenty points. You go from red to orange. You won't reach green, because the foundation doesn't move.
💡 Beware of “Odoo optimisation” promises
Many offers promise 90/100 on a standard Odoo site without ever explaining how. Always ask what the strategy is for the assets_frontend bundle. If the answer mentions neither its content nor how to do without it, there is no strategy.
6. The only real solution: code the page
If the weight comes from the standard template, then the only way out is to not go through that template. In practice: an Odoo module that declares its own routes and returns the page's HTML directly, never invoking the layout of the Website module. No bundle is injected, because no bundle is requested.
This is exactly what we built for our own services pages, after finding that no setting would get us below 3 MB. The result is the right-hand column of the table above: 25 KB of hand-written CSS, served on its own route with its own cache, and strictly nothing else.
The important point, and what distinguishes a real solution from a hack: you don't leave Odoo for it. The page is still served by Odoo, on the same domain, with native routing. It appears in the sitemap.xml. It keeps the built-in visitor tracking, so the statistics continue to feed the CRM. The content lives in an Odoo model, managed from the back office like any other data. You keep the ERP, you simply choose what goes to the visitor.
💡 The technical principle in one sentence
A route that returns an HTML response built by the module, rather than a render going through the Website module's template: this single architectural choice is what takes a page from 3,157 KB to 25 KB.
7. What you lose — because it needs saying
A page served outside the standard template can no longer be edited by drag and drop. No more “Edit” button, no more snippets to move with the mouse. Every change goes through a developer. That is a real cost, and anyone selling you this approach without mentioning it is selling it badly.
Hence the only rule that matters: don't code everything, code what counts. Your internal pages, your news, everything that changes often and is managed as you go: keep the Odoo editor, that is precisely its purpose. Your strategic pages — the ones that receive advertising, the ones that carry conversion, the ones that get shared — deserve to be coded.
It is a page-by-page trade-off, not a religion. On our own site, both approaches coexist on the same instance.
The Verdict: a low score is not inevitable, it is a trade-off
A slow Odoo site is not a failed site: it is a site that has paid for the comfort of autonomous editing with performance. On most of your pages, that is an excellent deal. On those that drive your revenue, it is a bad one — and the only way to turn the tables is to take back control of what the page sends.
Want to know what your pages really weigh, and which ones are worth taking over? That is the starting point of our audit, and the daily ground of our custom development.
One day, out of curiosity, you run your Odoo website through PageSpeed Insights. The score comes up red. 45. 38. On Odoo's official forum, some report 19 out of 100. The reflex is immediate: you've been had, or the integrator cut corners.
Neither. We measured, with figures, what an Odoo page actually sends to your visitor. The cause is structural, it is perfectly logical — and there is only one way to truly escape it: code the page yourself.
1. No, your integrator didn’t cut corners
The topic comes up again and again on Odoo's forum, and almost always without a clear answer: “is there an Odoo site above 60 on mobile?”, “my site has a bad PageSpeed score”. The replies go in circles — enable a CDN, compress your images — without ever naming the real cause.
This cause has nothing to do with your theme, your host or the quality of your implementation. It is built into the way Odoo's Website module works. Until you understand that, you wear yourself out optimising details that will never move the needle by more than a few points.
💡 The key takeaway up front
A low PageSpeed score on Odoo is not a manufacturing defect or negligence. It is the price of a feature you most likely demanded: being able to edit your website yourself, by drag and drop, without a developer.
2. What an Odoo page actually sends
Enough theory. We measured our own server: Odoo 19, a single instance, a single domain name, the same cache and the same CDN for everyone. On one side a standard Website page (a simple contact form), on the other a services page that we serve differently. The protocol is trivial to reproduce: fetch the HTML, list the <script src> tags and the stylesheets, weigh each file.
Here is what the browser has to download before it can display anything:
📊 Standard Odoo page — the details
web.assets_frontend_lazy.min.js — 2,318 KB
web.assets_frontend.min.css — 809 KB
web.assets_frontend_minimal.min.js — 30 KB
Total imposed by Odoo: 3,157 KB, spread over 7 blocking requests.
By comparison, the services page you are reading on this same server loads 25 KB of CSS and zero kilobytes of application JavaScript.
3. Why 3.1 MB to display a contact form?
Because Odoo doesn't know in advance what you will do with this page. The assets_frontend bundle doesn't contain “what's needed to display a form”. It contains everything an Odoo website might need: the live content editor, the complete snippet library, the e-commerce cart and checkout, the customer portal, blog widgets, animations, image galleries.
This package is assembled once for the whole site, then served on every public page, identically. Your “Legal notice” page, which contains only text, downloads the e-commerce engine. Your contact form downloads the website editor. The visitor pays for features they will never see.
This isn't absurd: it's the deal. This bundle is exactly what lets you click “Edit”, move a block with the mouse and publish without calling anyone. The weight is not a bug, it's the bill for autonomy.
💡 The direct consequence
No setting, no Odoo configuration option will let you go significantly below these 3 MB as long as the page goes through the standard template of the Website module. The ceiling is structural.
4. What Google really measures (and what it ignores)
Before you panic, a clarification that is worth money: the PageSpeed score is not a grade Google gives your SEO. It is the result of a lab test, run on a deliberately throttled mobile device and a deliberately slow connection. It is meant to diagnose, not to penalise.
What Google actually uses in its ranking is the Core Web Vitals measured on your real visitors — their real phones, their real connection, often with your files already cached. These figures are consistently better than the lab score. And even they only act as a tiebreaker between two results of equivalent quality: mediocre but fast content will never outrank excellent but slow content.
In other words: a red score does not make you vanish from Google. It does, however, cost you where it can be measured — bounce rate and conversion. On a landing page that receives paid advertising traffic, every second of waiting is paid for in lost visitors. That, not ranking, is where the real stake lies.
⚔️ The Match: standard Odoo page vs custom-coded page
| Criterion | Standard Website page | Custom-coded page |
|---|---|---|
| JS + CSS weight | 3,157 KB | 25 KB |
| Blocking requests | 7 | 3 |
| Unused JavaScript | Most of the bundle | None |
| Edited by the client | Drag and drop, autonomous | Goes through a developer |
| Ideal use case | Internal pages, living content | Landing pages, strategic pages |
Measurements taken on the same Odoo 19 instance, same domain, same CDN. The real total of the standard page reaches 3,654 KB once audience-measurement tools are added.
5. Half-measures, and where they stop
The usual advice isn't wrong, it is simply capped. You should apply it — it's cheap — but knowing what it delivers:
A CDN and proper caching: the most profitable gain. Your 3 MB travel a shorter distance and are reused from one page to the next. The first display stays heavy, the following ones become comfortable.
Uninstall unused Website modules: each active module adds its share to the bundle. A showcase site dragging along e-commerce without using it can really slim down. Typical gain: a few hundred kilobytes.
Compress images and enable lazy loading: essential, and often the first real culprit behind the Largest Contentful Paint. But it doesn't touch the 3,157 KB of code in the slightest.
Add it all up: you gain ten to twenty points. You go from red to orange. You won't reach green, because the foundation doesn't move.
💡 Beware of “Odoo optimisation” promises
Many offers promise 90/100 on a standard Odoo site without ever explaining how. Always ask what the strategy is for the assets_frontend bundle. If the answer mentions neither its content nor how to do without it, there is no strategy.
6. The only real solution: code the page
If the weight comes from the standard template, then the only way out is to not go through that template. In practice: an Odoo module that declares its own routes and returns the page's HTML directly, never invoking the layout of the Website module. No bundle is injected, because no bundle is requested.
This is exactly what we built for our own services pages, after finding that no setting would get us below 3 MB. The result is the right-hand column of the table above: 25 KB of hand-written CSS, served on its own route with its own cache, and strictly nothing else.
The important point, and what distinguishes a real solution from a hack: you don't leave Odoo for it. The page is still served by Odoo, on the same domain, with native routing. It appears in the sitemap.xml. It keeps the built-in visitor tracking, so the statistics continue to feed the CRM. The content lives in an Odoo model, managed from the back office like any other data. You keep the ERP, you simply choose what goes to the visitor.
💡 The technical principle in one sentence
A route that returns an HTML response built by the module, rather than a render going through the Website module's template: this single architectural choice is what takes a page from 3,157 KB to 25 KB.
7. What you lose — because it needs saying
A page served outside the standard template can no longer be edited by drag and drop. No more “Edit” button, no more snippets to move with the mouse. Every change goes through a developer. That is a real cost, and anyone selling you this approach without mentioning it is selling it badly.
Hence the only rule that matters: don't code everything, code what counts. Your internal pages, your news, everything that changes often and is managed as you go: keep the Odoo editor, that is precisely its purpose. Your strategic pages — the ones that receive advertising, the ones that carry conversion, the ones that get shared — deserve to be coded.
It is a page-by-page trade-off, not a religion. On our own site, both approaches coexist on the same instance.
The Verdict: a low score is not inevitable, it is a trade-off
A slow Odoo site is not a failed site: it is a site that has paid for the comfort of autonomous editing with performance. On most of your pages, that is an excellent deal. On those that drive your revenue, it is a bad one — and the only way to turn the tables is to take back control of what the page sends.
Want to know what your pages really weigh, and which ones are worth taking over? That is the starting point of our audit, and the daily ground of our custom development.